Fix: UI Should show other tags if the glossary search index fails. (#5081)

This commit is contained in:
darth-coder00 2022-05-21 11:20:07 +05:30 committed by GitHub
parent e23bb5d0f4
commit 3ee279fa70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 666 additions and 42 deletions

View File

@ -20,6 +20,7 @@ import { useAuthContext } from '../../authentication/auth-provider/AuthProvider'
import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants';
import { getTeamAndUserDetailsPath } from '../../constants/constants';
import { observerOptions } from '../../constants/Mydata.constants';
import { SettledStatus } from '../../enums/axios.enum';
import { EntityType } from '../../enums/entity.enum';
import { OwnerType } from '../../enums/user.enum';
import { Dashboard } from '../../generated/entity/data/dashboard';
@ -358,24 +359,38 @@ const DashboardDetails = ({
const fetchTagsAndGlossaryTerms = () => {
setIsTagLoading(true);
Promise.all([getTagCategories(), fetchGlossaryTerms()])
Promise.allSettled([getTagCategories(), fetchGlossaryTerms()])
.then((values) => {
let tagsAndTerms: TagOption[] = [];
if (values[0].data) {
tagsAndTerms = getTaglist(values[0].data).map((tag) => {
if (
values[0].status === SettledStatus.FULFILLED &&
values[0].value.data
) {
tagsAndTerms = getTaglist(values[0].value.data).map((tag) => {
return { fqn: tag, source: 'Tag' };
});
}
if (values[1] && values[1].length > 0) {
const glossaryTerms: TagOption[] = getGlossaryTermlist(values[1]).map(
(tag) => {
return { fqn: tag, source: 'Glossary' };
}
);
if (
values[1].status === SettledStatus.FULFILLED &&
values[1].value &&
values[1].value.length > 0
) {
const glossaryTerms: TagOption[] = getGlossaryTermlist(
values[1].value
).map((tag) => {
return { fqn: tag, source: 'Glossary' };
});
tagsAndTerms = [...tagsAndTerms, ...glossaryTerms];
}
setTagList(tagsAndTerms);
setTagFetchFailed(false);
if (
values[0].status === SettledStatus.FULFILLED &&
values[1].status === SettledStatus.FULFILLED
) {
setTagFetchFailed(false);
} else {
setTagFetchFailed(true);
}
})
.catch(() => {
setTagList([]);
@ -577,6 +592,7 @@ const DashboardDetails = ({
</td>
<td
className="tw-group tw-relative tableBody-cell"
data-testid="tags-wrapper"
onClick={() => {
if (!editChartTags) {
// Fetch tags and terms only once

View File

@ -11,16 +11,31 @@
* limitations under the License.
*/
import { findByTestId, findByText, render } from '@testing-library/react';
import { LeafNodes, LoadingNodeState } from 'Models';
import {
findByTestId,
findByText,
fireEvent,
render,
} from '@testing-library/react';
import { flatten } from 'lodash';
import {
FormattedGlossaryTermData,
LeafNodes,
LoadingNodeState,
TagOption,
} from 'Models';
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { Dashboard } from '../../generated/entity/data/dashboard';
import { TagCategory, TagClass } from '../../generated/entity/tags/tagCategory';
import { EntityLineage } from '../../generated/type/entityLineage';
import { EntityReference } from '../../generated/type/entityReference';
import { Paging } from '../../generated/type/paging';
import { TagLabel } from '../../generated/type/tagLabel';
import { fetchGlossaryTerms } from '../../utils/GlossaryUtils';
import { getTagCategories } from '../../utils/TagsUtils';
import DashboardDetails from './DashboardDetails.component';
import { ChartType } from './DashboardDetails.interface';
jest.mock('../../authentication/auth-provider/AuthProvider', () => {
return {
@ -54,7 +69,13 @@ const mockUserTeam = [
];
const DashboardDetailsProps = {
charts: [],
charts: [
{
chartUrl: 'http://localhost',
chartType: 'Area',
displayName: 'Test chart',
},
] as ChartType[],
serviceType: '',
dashboardUrl: '',
tagList: [],
@ -100,6 +121,58 @@ const DashboardDetailsProps = {
const mockObserve = jest.fn();
const mockunObserve = jest.fn();
const mockTagList = [
{
id: 'tagCatId1',
name: 'TagCat1',
description: '',
categoryType: 'Classification',
children: [
{
id: 'tagId1',
name: 'Tag1',
fullyQualifiedName: 'TagCat1.Tag1',
description: '',
deprecated: false,
deleted: false,
},
],
},
{
id: 'tagCatId2',
name: 'TagCat2',
description: '',
categoryType: 'Classification',
children: [
{
id: 'tagId2',
name: 'Tag2',
fullyQualifiedName: 'TagCat2.Tag2',
description: '',
deprecated: false,
deleted: false,
},
],
},
];
const mockGlossaryList = [
{
name: 'Tag1',
displayName: 'Tag1',
fqdn: 'Glossary.Tag1',
type: 'glossaryTerm',
id: 'glossaryTagId1',
},
{
name: 'Tag2',
displayName: 'Tag2',
fqdn: 'Glossary.Tag2',
type: 'glossaryTerm',
id: 'glossaryTagId2',
},
];
window.IntersectionObserver = jest.fn().mockImplementation(() => ({
observe: mockObserve,
unobserve: mockunObserve,
@ -117,7 +190,15 @@ jest.mock('../common/rich-text-editor/RichTextEditorPreviewer', () => {
});
jest.mock('../tags-container/tags-container', () => {
return jest.fn().mockReturnValue(<p>Tag Container</p>);
return jest.fn().mockImplementation(({ tagList }) => {
return (
<>
{tagList.map((tag: TagOption, idx: number) => (
<p key={idx}>{tag.fqn}</p>
))}
</>
);
});
});
jest.mock('../tags/tags', () => {
@ -144,6 +225,14 @@ jest.mock('../EntityLineage/EntityLineage.component', () => {
return jest.fn().mockReturnValue(<p data-testid="lineage">Lineage</p>);
});
jest.mock('../common/non-admin-action/NonAdminAction', () => {
return jest
.fn()
.mockImplementation(({ children }) => (
<p data-testid="tag-action">{children}</p>
));
});
jest.mock('../../utils/CommonUtils', () => ({
addToRecentViewed: jest.fn(),
getCountBadge: jest.fn(),
@ -154,6 +243,30 @@ jest.mock('../../utils/CommonUtils', () => ({
getEntityPlaceHolder: jest.fn().mockReturnValue('value'),
getEntityName: jest.fn().mockReturnValue('entityName'),
pluralize: jest.fn().mockReturnValue('2 charts'),
isEven: jest.fn().mockReturnValue(true),
getEntityDeleteMessage: jest.fn(),
}));
jest.mock('../../utils/GlossaryUtils', () => ({
fetchGlossaryTerms: jest.fn(() => Promise.resolve(mockGlossaryList)),
getGlossaryTermlist: jest.fn((terms) => {
return terms.map((term: FormattedGlossaryTermData) => term?.fqdn);
}),
}));
jest.mock('../../utils/TagsUtils', () => ({
getTagCategories: jest.fn(() => Promise.resolve({ data: mockTagList })),
getTaglist: jest.fn((categories) => {
const children = categories.map((category: TagCategory) => {
return category.children || [];
});
const allChildren = flatten(children);
const tagList = (allChildren as unknown as TagClass[]).map((tag) => {
return tag?.fullyQualifiedName || '';
});
return tagList;
}),
}));
describe('Test DashboardDetails component', () => {
@ -243,4 +356,100 @@ describe('Test DashboardDetails component', () => {
expect(mockObserve).toHaveBeenCalled();
});
it('Check if tags and glossary-terms are present', async () => {
const { getByTestId, findByText } = render(
<DashboardDetails {...DashboardDetailsProps} />,
{
wrapper: MemoryRouter,
}
);
const tagWrapper = getByTestId('tags-wrapper');
fireEvent.click(
tagWrapper,
new MouseEvent('click', { bubbles: true, cancelable: true })
);
const tag1 = await findByText('TagCat1.Tag1');
const glossaryTerm1 = await findByText('Glossary.Tag1');
expect(tag1).toBeInTheDocument();
expect(glossaryTerm1).toBeInTheDocument();
});
it('Check if only tags are present', async () => {
(fetchGlossaryTerms as jest.Mock).mockImplementationOnce(() =>
Promise.reject()
);
const { getByTestId, findByText, queryByText } = render(
<DashboardDetails {...DashboardDetailsProps} />,
{
wrapper: MemoryRouter,
}
);
const tagWrapper = getByTestId('tags-wrapper');
fireEvent.click(
tagWrapper,
new MouseEvent('click', { bubbles: true, cancelable: true })
);
const tag1 = await findByText('TagCat1.Tag1');
const glossaryTerm1 = queryByText('Glossary.Tag1');
expect(tag1).toBeInTheDocument();
expect(glossaryTerm1).not.toBeInTheDocument();
});
it('Check if only glossary terms are present', async () => {
(getTagCategories as jest.Mock).mockImplementationOnce(() =>
Promise.reject()
);
const { getByTestId, findByText, queryByText } = render(
<DashboardDetails {...DashboardDetailsProps} />,
{
wrapper: MemoryRouter,
}
);
const tagWrapper = getByTestId('tags-wrapper');
fireEvent.click(
tagWrapper,
new MouseEvent('click', { bubbles: true, cancelable: true })
);
const tag1 = queryByText('TagCat1.Tag1');
const glossaryTerm1 = await findByText('Glossary.Tag1');
expect(tag1).not.toBeInTheDocument();
expect(glossaryTerm1).toBeInTheDocument();
});
it('Check that tags and glossary terms are not present', async () => {
(getTagCategories as jest.Mock).mockImplementationOnce(() =>
Promise.reject()
);
(fetchGlossaryTerms as jest.Mock).mockImplementationOnce(() =>
Promise.reject()
);
const { getByTestId, queryByText } = render(
<DashboardDetails {...DashboardDetailsProps} />,
{
wrapper: MemoryRouter,
}
);
const tagWrapper = getByTestId('tags-wrapper');
fireEvent.click(
tagWrapper,
new MouseEvent('click', { bubbles: true, cancelable: true })
);
const tag1 = queryByText('TagCat1.Tag1');
const glossaryTerm1 = queryByText('Glossary.Tag1');
expect(tag1).not.toBeInTheDocument();
expect(glossaryTerm1).not.toBeInTheDocument();
});
});

View File

@ -21,6 +21,7 @@ import { Link } from 'react-router-dom';
import { useExpanded, useTable } from 'react-table';
import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants';
import { getTableDetailsPath } from '../../constants/constants';
import { SettledStatus } from '../../enums/axios.enum';
import { EntityType, FqnPart } from '../../enums/entity.enum';
import {
Column,
@ -154,24 +155,38 @@ const EntityTable = ({
const fetchTagsAndGlossaryTerms = () => {
setIsTagLoading(true);
Promise.all([getTagCategories(), fetchGlossaryTerms()])
Promise.allSettled([getTagCategories(), fetchGlossaryTerms()])
.then((values) => {
let tagsAndTerms: TagOption[] = [];
if (values[0].data) {
tagsAndTerms = getTaglist(values[0].data).map((tag) => {
if (
values[0].status === SettledStatus.FULFILLED &&
values[0].value.data
) {
tagsAndTerms = getTaglist(values[0].value.data).map((tag) => {
return { fqn: tag, source: 'Tag' };
});
}
if (values[1] && values[1].length > 0) {
const glossaryTerms: TagOption[] = getGlossaryTermlist(values[1]).map(
(tag) => {
return { fqn: tag, source: 'Glossary' };
}
);
if (
values[1].status === SettledStatus.FULFILLED &&
values[1].value &&
values[1].value.length > 0
) {
const glossaryTerms: TagOption[] = getGlossaryTermlist(
values[1].value
).map((tag) => {
return { fqn: tag, source: 'Glossary' };
});
tagsAndTerms = [...tagsAndTerms, ...glossaryTerms];
}
setAllTags(tagsAndTerms);
setTagFetchFailed(false);
if (
values[0].status === SettledStatus.FULFILLED &&
values[1].status === SettledStatus.FULFILLED
) {
setTagFetchFailed(false);
} else {
setTagFetchFailed(true);
}
})
.catch(() => {
setAllTags([]);
@ -525,6 +540,7 @@ const EntityTable = ({
</div>
) : (
<div
data-testid="tags-wrapper"
onClick={() => {
if (!editColumnTag) {
handleEditColumnTag(row.original, row.id);

View File

@ -18,10 +18,15 @@ import {
queryByTestId,
render,
} from '@testing-library/react';
import { flatten } from 'lodash';
import { FormattedGlossaryTermData, TagOption } from 'Models';
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { Table } from '../../generated/entity/data/table';
import { TagCategory, TagClass } from '../../generated/entity/tags/tagCategory';
import { ModifiedTableColumn } from '../../interface/dataQuality.interface';
import { fetchGlossaryTerms } from '../../utils/GlossaryUtils';
import { getTagCategories } from '../../utils/TagsUtils';
import EntityTable from './EntityTable.component';
const mockTableheader = [
@ -144,12 +149,68 @@ const mockEntityTableProp = {
onThreadLinkSelect,
};
const mockTagList = [
{
id: 'tagCatId1',
name: 'TagCat1',
description: '',
categoryType: 'Classification',
children: [
{
id: 'tagId1',
name: 'Tag1',
fullyQualifiedName: 'TagCat1.Tag1',
description: '',
deprecated: false,
deleted: false,
},
],
},
{
id: 'tagCatId2',
name: 'TagCat2',
description: '',
categoryType: 'Classification',
children: [
{
id: 'tagId2',
name: 'Tag2',
fullyQualifiedName: 'TagCat2.Tag2',
description: '',
deprecated: false,
deleted: false,
},
],
},
];
const mockGlossaryList = [
{
name: 'Tag1',
displayName: 'Tag1',
fqdn: 'Glossary.Tag1',
type: 'glossaryTerm',
id: 'glossaryTagId1',
},
{
name: 'Tag2',
displayName: 'Tag2',
fqdn: 'Glossary.Tag2',
type: 'glossaryTerm',
id: 'glossaryTagId2',
},
];
jest.mock('@fortawesome/react-fontawesome', () => ({
FontAwesomeIcon: jest.fn().mockReturnValue(<i>Icon</i>),
}));
jest.mock('../common/non-admin-action/NonAdminAction', () => {
return jest.fn().mockReturnValue(<p>NonAdminAction</p>);
return jest
.fn()
.mockImplementation(({ children }) => (
<p data-testid="tag-action">{children}</p>
));
});
jest.mock('../common/rich-text-editor/RichTextEditorPreviewer', () => {
@ -159,7 +220,15 @@ jest.mock('../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor', () => ({
ModalWithMarkdownEditor: jest.fn().mockReturnValue(<p>EditorModal</p>),
}));
jest.mock('../tags-container/tags-container', () => {
return jest.fn().mockReturnValue(<p>TagContainer</p>);
return jest.fn().mockImplementation(({ tagList }) => {
return (
<>
{tagList.map((tag: TagOption, idx: number) => (
<p key={idx}>{tag.fqn}</p>
))}
</>
);
});
});
jest.mock('../tags-viewer/tags-viewer', () => {
return jest.fn().mockReturnValue(<p>TagViewer</p>);
@ -168,6 +237,28 @@ jest.mock('../tags/tags', () => {
return jest.fn().mockReturnValue(<p>Tag</p>);
});
jest.mock('../../utils/GlossaryUtils', () => ({
fetchGlossaryTerms: jest.fn(() => Promise.resolve(mockGlossaryList)),
getGlossaryTermlist: jest.fn((terms) => {
return terms.map((term: FormattedGlossaryTermData) => term?.fqdn);
}),
}));
jest.mock('../../utils/TagsUtils', () => ({
getTagCategories: jest.fn(() => Promise.resolve({ data: mockTagList })),
getTaglist: jest.fn((categories) => {
const children = categories.map((category: TagCategory) => {
return category.children || [];
});
const allChildren = flatten(children);
const tagList = (allChildren as unknown as TagClass[]).map((tag) => {
return tag?.fullyQualifiedName || '';
});
return tagList;
}),
}));
describe('Test EntityTable Component', () => {
it('Check if it has all child elements', async () => {
const { container } = render(<EntityTable {...mockEntityTableProp} />, {
@ -309,4 +400,97 @@ describe('Test EntityTable Component', () => {
String(mockEntityFieldThreads[0].count)
);
});
it('Check if tags and glossary-terms are present', async () => {
const { getAllByTestId, findAllByText } = render(
<EntityTable {...mockEntityTableProp} />,
{
wrapper: MemoryRouter,
}
);
const tagWrapper = getAllByTestId('tags-wrapper')[0];
fireEvent.click(tagWrapper);
const tag1 = await findAllByText('TagCat1.Tag1');
const glossaryTerm1 = await findAllByText('Glossary.Tag1');
expect(tag1).toHaveLength(mockEntityTableProp.tableColumns.length);
expect(glossaryTerm1).toHaveLength(mockEntityTableProp.tableColumns.length);
});
it('Check if only tags are present', async () => {
(fetchGlossaryTerms as jest.Mock).mockImplementationOnce(() =>
Promise.reject()
);
const { getAllByTestId, findAllByText, queryAllByText } = render(
<EntityTable {...mockEntityTableProp} />,
{
wrapper: MemoryRouter,
}
);
const tagWrapper = getAllByTestId('tags-wrapper')[0];
fireEvent.click(
tagWrapper,
new MouseEvent('click', { bubbles: true, cancelable: true })
);
const tag1 = await findAllByText('TagCat1.Tag1');
const glossaryTerm1 = queryAllByText('Glossary.Tag1');
expect(tag1).toHaveLength(mockEntityTableProp.tableColumns.length);
expect(glossaryTerm1).toHaveLength(0);
});
it('Check if only glossary terms are present', async () => {
(getTagCategories as jest.Mock).mockImplementationOnce(() =>
Promise.reject()
);
const { getAllByTestId, findAllByText, queryAllByText } = render(
<EntityTable {...mockEntityTableProp} />,
{
wrapper: MemoryRouter,
}
);
const tagWrapper = getAllByTestId('tags-wrapper')[0];
fireEvent.click(
tagWrapper,
new MouseEvent('click', { bubbles: true, cancelable: true })
);
const tag1 = queryAllByText('TagCat1.Tag1');
const glossaryTerm1 = await findAllByText('Glossary.Tag1');
expect(tag1).toHaveLength(0);
expect(glossaryTerm1).toHaveLength(mockEntityTableProp.tableColumns.length);
});
it('Check that tags and glossary terms are not present', async () => {
(getTagCategories as jest.Mock).mockImplementationOnce(() =>
Promise.reject()
);
(fetchGlossaryTerms as jest.Mock).mockImplementationOnce(() =>
Promise.reject()
);
const { getAllByTestId, queryAllByText } = render(
<EntityTable {...mockEntityTableProp} />,
{
wrapper: MemoryRouter,
}
);
const tagWrapper = getAllByTestId('tags-wrapper')[0];
fireEvent.click(
tagWrapper,
new MouseEvent('click', { bubbles: true, cancelable: true })
);
const tag1 = queryAllByText('TagCat1.Tag1');
const glossaryTerm1 = queryAllByText('Glossary.Tag1');
expect(tag1).toHaveLength(0);
expect(glossaryTerm1).toHaveLength(0);
});
});

View File

@ -18,9 +18,17 @@ import {
queryByTestId,
render,
} from '@testing-library/react';
import { flatten } from 'lodash';
import { FormattedGlossaryTermData, TagOption } from 'Models';
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import {
TagCategory,
TagClass,
} from '../../../generated/entity/tags/tagCategory';
import { TagLabel } from '../../../generated/type/tagLabel';
import { fetchGlossaryTerms } from '../../../utils/GlossaryUtils';
import { getTagCategories } from '../../../utils/TagsUtils';
import EntityPageInfo from './EntityPageInfo';
const mockEntityFieldThreads = [
@ -112,6 +120,58 @@ const mockEntityInfoProp = {
onThreadLinkSelect,
};
const mockTagList = [
{
id: 'tagCatId1',
name: 'TagCat1',
description: '',
categoryType: 'Classification',
children: [
{
id: 'tagId1',
name: 'Tag1',
fullyQualifiedName: 'TagCat1.Tag1',
description: '',
deprecated: false,
deleted: false,
},
],
},
{
id: 'tagCatId2',
name: 'TagCat2',
description: '',
categoryType: 'Classification',
children: [
{
id: 'tagId2',
name: 'Tag2',
fullyQualifiedName: 'TagCat2.Tag2',
description: '',
deprecated: false,
deleted: false,
},
],
},
];
const mockGlossaryList = [
{
name: 'Tag1',
displayName: 'Tag1',
fqdn: 'Glossary.Tag1',
type: 'glossaryTerm',
id: 'glossaryTagId1',
},
{
name: 'Tag2',
displayName: 'Tag2',
fqdn: 'Glossary.Tag2',
type: 'glossaryTerm',
id: 'glossaryTagId2',
},
];
jest.mock('../../../utils/CommonUtils', () => ({
getHtmlForNonAdminAction: jest.fn(),
}));
@ -122,8 +182,10 @@ jest.mock('../../../utils/EntityUtils', () => ({
}));
jest.mock('../../../utils/GlossaryUtils', () => ({
fetchGlossaryTerms: jest.fn(),
getGlossaryTermlist: jest.fn(),
fetchGlossaryTerms: jest.fn(() => Promise.resolve(mockGlossaryList)),
getGlossaryTermlist: jest.fn((terms) => {
return terms.map((term: FormattedGlossaryTermData) => term?.fqdn);
}),
}));
jest.mock('../../../utils/TableUtils', () => ({
@ -131,18 +193,38 @@ jest.mock('../../../utils/TableUtils', () => ({
}));
jest.mock('../../../utils/TagsUtils', () => ({
getTagCategories: jest.fn(),
getTaglist: jest.fn(),
getTagCategories: jest.fn(() => Promise.resolve({ data: mockTagList })),
getTaglist: jest.fn((categories) => {
const children = categories.map((category: TagCategory) => {
return category.children || [];
});
const allChildren = flatten(children);
const tagList = (allChildren as unknown as TagClass[]).map((tag) => {
return tag?.fullyQualifiedName || '';
});
return tagList;
}),
}));
jest.mock('../non-admin-action/NonAdminAction', () => {
return jest
.fn()
.mockReturnValue(<p data-testid="tag-action">NonAdminAction</p>);
.mockImplementation(({ children }) => (
<p data-testid="tag-action">{children}</p>
));
});
jest.mock('../../tags-container/tags-container', () => {
return jest.fn().mockReturnValue(<p>TagContainer</p>);
return jest.fn().mockImplementation(({ tagList }) => {
return (
<>
{tagList.map((tag: TagOption, idx: number) => (
<p key={idx}>{tag.fqn}</p>
))}
</>
);
});
});
jest.mock('../../tags-viewer/tags-viewer', () => {
@ -431,4 +513,100 @@ describe('Test EntityPageInfo component', () => {
expect(onThreadLinkSelect).toBeCalled();
});
it('Check if tags and glossary-terms are present', async () => {
const { getByTestId, findByText } = render(
<EntityPageInfo {...mockEntityInfoProp} isTagEditable />,
{
wrapper: MemoryRouter,
}
);
const tagWrapper = getByTestId('tags-wrapper');
fireEvent.click(
tagWrapper,
new MouseEvent('click', { bubbles: true, cancelable: true })
);
const tag1 = await findByText('TagCat1.Tag1');
const glossaryTerm1 = await findByText('Glossary.Tag1');
expect(tag1).toBeInTheDocument();
expect(glossaryTerm1).toBeInTheDocument();
});
it('Check if only tags are present', async () => {
(fetchGlossaryTerms as jest.Mock).mockImplementationOnce(() =>
Promise.reject()
);
const { getByTestId, findByText, queryByText } = render(
<EntityPageInfo {...mockEntityInfoProp} isTagEditable />,
{
wrapper: MemoryRouter,
}
);
const tagWrapper = getByTestId('tags-wrapper');
fireEvent.click(
tagWrapper,
new MouseEvent('click', { bubbles: true, cancelable: true })
);
const tag1 = await findByText('TagCat1.Tag1');
const glossaryTerm1 = queryByText('Glossary.Tag1');
expect(tag1).toBeInTheDocument();
expect(glossaryTerm1).not.toBeInTheDocument();
});
it('Check if only glossary terms are present', async () => {
(getTagCategories as jest.Mock).mockImplementationOnce(() =>
Promise.reject()
);
const { getByTestId, findByText, queryByText } = render(
<EntityPageInfo {...mockEntityInfoProp} isTagEditable />,
{
wrapper: MemoryRouter,
}
);
const tagWrapper = getByTestId('tags-wrapper');
fireEvent.click(
tagWrapper,
new MouseEvent('click', { bubbles: true, cancelable: true })
);
const tag1 = queryByText('TagCat1.Tag1');
const glossaryTerm1 = await findByText('Glossary.Tag1');
expect(tag1).not.toBeInTheDocument();
expect(glossaryTerm1).toBeInTheDocument();
});
it('Check that tags and glossary terms are not present', async () => {
(getTagCategories as jest.Mock).mockImplementationOnce(() =>
Promise.reject()
);
(fetchGlossaryTerms as jest.Mock).mockImplementationOnce(() =>
Promise.reject()
);
const { getByTestId, queryByText } = render(
<EntityPageInfo {...mockEntityInfoProp} isTagEditable />,
{
wrapper: MemoryRouter,
}
);
const tagWrapper = getByTestId('tags-wrapper');
fireEvent.click(
tagWrapper,
new MouseEvent('click', { bubbles: true, cancelable: true })
);
const tag1 = queryByText('TagCat1.Tag1');
const glossaryTerm1 = queryByText('Glossary.Tag1');
expect(tag1).not.toBeInTheDocument();
expect(glossaryTerm1).not.toBeInTheDocument();
});
});

View File

@ -19,6 +19,7 @@ import { EntityFieldThreads, EntityTags, ExtraInfo, TagOption } from 'Models';
import React, { Fragment, useEffect, useState } from 'react';
import { FQN_SEPARATOR_CHAR } from '../../../constants/char.constants';
import { FOLLOWERS_VIEW_CAP } from '../../../constants/constants';
import { SettledStatus } from '../../../enums/axios.enum';
import { Operation } from '../../../generated/entity/policies/accessControl/rule';
import { EntityReference } from '../../../generated/type/entityReference';
import { LabelType, State, TagLabel } from '../../../generated/type/tagLabel';
@ -223,24 +224,38 @@ const EntityPageInfo = ({
const fetchTagsAndGlossaryTerms = () => {
setIsTagLoading(true);
Promise.all([getTagCategories(), fetchGlossaryTerms()])
Promise.allSettled([getTagCategories(), fetchGlossaryTerms()])
.then((values) => {
let tagsAndTerms: TagOption[] = [];
if (values[0].data) {
tagsAndTerms = getTaglist(values[0].data).map((tag) => {
if (
values[0].status === SettledStatus.FULFILLED &&
values[0].value.data
) {
tagsAndTerms = getTaglist(values[0].value.data).map((tag) => {
return { fqn: tag, source: 'Tag' };
});
}
if (values[1] && values[1].length > 0) {
const glossaryTerms: TagOption[] = getGlossaryTermlist(values[1]).map(
(tag) => {
return { fqn: tag, source: 'Glossary' };
}
);
if (
values[1].status === SettledStatus.FULFILLED &&
values[1].value &&
values[1].value.length > 0
) {
const glossaryTerms: TagOption[] = getGlossaryTermlist(
values[1].value
).map((tag) => {
return { fqn: tag, source: 'Glossary' };
});
tagsAndTerms = [...tagsAndTerms, ...glossaryTerms];
}
setTagList(tagsAndTerms);
setTagFetchFailed(false);
if (
values[0].status === SettledStatus.FULFILLED &&
values[1].status === SettledStatus.FULFILLED
) {
setTagFetchFailed(false);
} else {
setTagFetchFailed(true);
}
})
.catch(() => {
setTagList([]);
@ -395,6 +410,7 @@ const EntityPageInfo = ({
trigger="click">
<div
className="tw-inline-block"
data-testid="tags-wrapper"
onClick={() => {
// Fetch tags and terms only once
if (tagList.length === 0 || tagFetchFailed) {

View File

@ -18,3 +18,8 @@ export enum ClientErrors {
FORBIDDEN = 403,
NOT_FOUND = 404,
}
export enum SettledStatus {
FULFILLED = 'fulfilled',
REJECTED = 'rejected',
}