mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-12-25 22:49:12 +00:00
fixed: tag api being called on every click in create glossary and create glossary term page (#10126)
* fixed: tag api being called on every click in create glossary and create glossary term page * added unit test and optimise the code
This commit is contained in:
parent
8d6a8938ad
commit
b8e15bd969
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2023 Collate.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { act, render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { mockTagsApiResponse } from 'mocks/Tags.mock';
|
||||
import React from 'react';
|
||||
import { getAllTagsForOptions } from 'utils/TagsUtils';
|
||||
import { AddTags } from './add-tags.component';
|
||||
|
||||
const mockSetTags = jest.fn();
|
||||
|
||||
jest.mock('../../utils/TagsUtils', () => ({
|
||||
...jest.requireActual('../../utils/TagsUtils'),
|
||||
getAllTagsForOptions: jest
|
||||
.fn()
|
||||
.mockImplementation(() => Promise.resolve(mockTagsApiResponse.data)),
|
||||
}));
|
||||
|
||||
describe('AddTags Component', () => {
|
||||
it('component should render', async () => {
|
||||
const mockGetAllTagsForOptions = getAllTagsForOptions as jest.Mock;
|
||||
await act(async () => {
|
||||
render(<AddTags setTags={mockSetTags} />);
|
||||
});
|
||||
|
||||
expect(await screen.findByRole('combobox')).toBeInTheDocument();
|
||||
expect(mockGetAllTagsForOptions).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Tags api should call once', async () => {
|
||||
const mockGetAllTagsForOptions = getAllTagsForOptions as jest.Mock;
|
||||
const flushPromises = () => new Promise(setImmediate);
|
||||
await act(async () => {
|
||||
render(<AddTags setTags={mockSetTags} />);
|
||||
});
|
||||
const selectBox = await screen.findByRole('combobox');
|
||||
|
||||
// There should not be any call at 1st render
|
||||
expect(mockGetAllTagsForOptions.mock.calls).toHaveLength(0);
|
||||
expect(selectBox).toBeInTheDocument();
|
||||
|
||||
await act(async () => {
|
||||
// Click on select element
|
||||
userEvent.click(selectBox);
|
||||
await flushPromises();
|
||||
|
||||
expect(
|
||||
await mockGetAllTagsForOptions.mock.results[0].value
|
||||
).toStrictEqual(mockTagsApiResponse.data);
|
||||
});
|
||||
|
||||
const options = await screen.findAllByRole('option');
|
||||
|
||||
expect(options).toHaveLength(2);
|
||||
|
||||
await act(async () => {
|
||||
userEvent.click(options[0]);
|
||||
});
|
||||
|
||||
expect(mockGetAllTagsForOptions.mock.calls).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
@ -12,16 +12,17 @@
|
||||
*/
|
||||
|
||||
import { Select } from 'antd';
|
||||
import { AxiosError } from 'axios';
|
||||
import { EntityTags, TagOption } from 'Models';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { showErrorToast } from 'utils/ToastUtils';
|
||||
import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants';
|
||||
import { getAllTagsForOptions, getTagOptions } from '../../utils/TagsUtils';
|
||||
|
||||
export const AddTags = ({
|
||||
setTags,
|
||||
}: {
|
||||
selectedTags?: Array<EntityTags>;
|
||||
setTags?: (tags: EntityTags[]) => void;
|
||||
}) => {
|
||||
const [isTagLoading, setIsTagLoading] = useState<boolean>(false);
|
||||
@ -33,10 +34,14 @@ export const AddTags = ({
|
||||
|
||||
const fetchTags = async () => {
|
||||
setIsTagLoading(true);
|
||||
const tags = await getAllTagsForOptions();
|
||||
setTagList(tags.map((t) => t.fullyQualifiedName || t.name));
|
||||
|
||||
setIsTagLoading(false);
|
||||
try {
|
||||
const tags = await getAllTagsForOptions();
|
||||
setTagList(tags.map((t) => t.fullyQualifiedName || t.name));
|
||||
} catch (error) {
|
||||
showErrorToast(error as AxiosError);
|
||||
} finally {
|
||||
setIsTagLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const tagsList = useMemo(() => {
|
||||
@ -53,12 +58,17 @@ export const AddTags = ({
|
||||
}, [tagList]);
|
||||
|
||||
const onClickSelect = useCallback(() => {
|
||||
fetchTags();
|
||||
}, []);
|
||||
if (tagList.length === 0) {
|
||||
fetchTags();
|
||||
}
|
||||
}, [tagList]);
|
||||
|
||||
const handleChange = useCallback((value: string[]) => {
|
||||
setSelectedTags && setSelectedTags(value);
|
||||
}, []);
|
||||
const handleChange = useCallback(
|
||||
(value: string[]) => {
|
||||
setSelectedTags(value);
|
||||
},
|
||||
[setSelectedTags]
|
||||
);
|
||||
|
||||
tagsList.forEach((tag) =>
|
||||
options.push(<Select.Option key={tag.label}>{tag.value}</Select.Option>)
|
||||
@ -72,6 +82,8 @@ export const AddTags = ({
|
||||
|
||||
return (
|
||||
<Select
|
||||
allowClear
|
||||
id="select-tags"
|
||||
loading={isTagLoading}
|
||||
mode="multiple"
|
||||
placeholder={t('label.add-entity', {
|
||||
|
||||
@ -26,3 +26,59 @@ export const mockTagList = [
|
||||
mutuallyExclusive: true,
|
||||
},
|
||||
];
|
||||
|
||||
export const mockTagsApiResponse = {
|
||||
data: [
|
||||
{
|
||||
id: '0897311f-1321-4e1c-a857-aab7dedc632d',
|
||||
name: 'Personal',
|
||||
fullyQualifiedName: 'PersonalData.Personal',
|
||||
description:
|
||||
'Data that can be used to directly or indirectly identify a person.',
|
||||
classification: {
|
||||
id: '5ce3825b-3227-4326-8beb-37ed2784149e',
|
||||
type: 'classification',
|
||||
name: 'PersonalData',
|
||||
fullyQualifiedName: 'PersonalData',
|
||||
description:
|
||||
'Tags related classifying **Personal data** as defined by **GDPR.**<br/><br/>',
|
||||
deleted: false,
|
||||
href: 'http://localhost:8585/api/v1/classifications/5ce3825b-3227-4326-8beb-37ed2784149e',
|
||||
},
|
||||
version: 0.1,
|
||||
updatedAt: 1675078969456,
|
||||
updatedBy: 'admin',
|
||||
href: 'http://localhost:8585/api/v1/tags/0897311f-1321-4e1c-a857-aab7dedc632d',
|
||||
deprecated: false,
|
||||
deleted: false,
|
||||
provider: 'system',
|
||||
mutuallyExclusive: false,
|
||||
},
|
||||
{
|
||||
id: '68a9fa7f-9342-404a-b31a-112dea0e0f81',
|
||||
name: 'SpecialCategory',
|
||||
fullyQualifiedName: 'PersonalData.SpecialCategory',
|
||||
description:
|
||||
'GDPR special category data is personal information of data subjects that is especially sensitive',
|
||||
classification: {
|
||||
id: '5ce3825b-3227-4326-8beb-37ed2784149e',
|
||||
type: 'classification',
|
||||
name: 'PersonalData',
|
||||
fullyQualifiedName: 'PersonalData',
|
||||
description:
|
||||
'Tags related classifying **Personal data** as defined by **GDPR.**<br/><br/>',
|
||||
deleted: false,
|
||||
href: 'http://localhost:8585/api/v1/classifications/5ce3825b-3227-4326-8beb-37ed2784149e',
|
||||
},
|
||||
version: 0.1,
|
||||
updatedAt: 1675078969475,
|
||||
updatedBy: 'admin',
|
||||
href: 'http://localhost:8585/api/v1/tags/68a9fa7f-9342-404a-b31a-112dea0e0f81',
|
||||
deprecated: false,
|
||||
deleted: false,
|
||||
provider: 'system',
|
||||
mutuallyExclusive: false,
|
||||
},
|
||||
],
|
||||
paging: { total: 2 },
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user