mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-31 20:51:26 +00:00
ui: added unit test for data quality page part 1 (#12267)
This commit is contained in:
parent
16280ffd1e
commit
75d7f1df68
@ -12,10 +12,12 @@
|
||||
*/
|
||||
import { Col, Row } from 'antd';
|
||||
import { AxiosError } from 'axios';
|
||||
import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder';
|
||||
import Searchbar from 'components/common/searchbar/Searchbar';
|
||||
import { usePermissionProvider } from 'components/PermissionProvider/PermissionProvider';
|
||||
import DataQualityTab from 'components/ProfilerDashboard/component/DataQualityTab';
|
||||
import { INITIAL_PAGING_VALUE, PAGE_SIZE } from 'constants/constants';
|
||||
import { ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum';
|
||||
import { SearchIndex } from 'enums/search.enum';
|
||||
import { TestCase } from 'generated/tests/testCase';
|
||||
import { Paging } from 'generated/type/paging';
|
||||
@ -181,11 +183,20 @@ export const TestCases = () => {
|
||||
fetchTestCases();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [tab, searchValue, testCasePermission]);
|
||||
|
||||
if (!testCasePermission?.ViewAll && !testCasePermission?.ViewBasic) {
|
||||
return <ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Row className="p-x-lg p-t-md" gutter={[16, 16]}>
|
||||
<Row
|
||||
className="p-x-lg p-t-md"
|
||||
data-testid="test-case-container"
|
||||
gutter={[16, 16]}>
|
||||
<Col span={8}>
|
||||
<Searchbar
|
||||
removeMargin
|
||||
|
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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 { render, screen } from '@testing-library/react';
|
||||
import { DataQualityPageTabs } from 'pages/DataQuality/DataQualityPage.interface';
|
||||
import React from 'react';
|
||||
import { searchQuery } from 'rest/searchAPI';
|
||||
import { getListTestCase } from 'rest/testAPI';
|
||||
import { TestCases } from './TestCases.component';
|
||||
|
||||
const testCasePermission = {
|
||||
Create: true,
|
||||
Delete: true,
|
||||
ViewAll: true,
|
||||
EditAll: true,
|
||||
EditDescription: true,
|
||||
EditDisplayName: true,
|
||||
EditCustomFields: true,
|
||||
};
|
||||
const mockUseParam = { tab: DataQualityPageTabs.TEST_CASES } as {
|
||||
tab?: DataQualityPageTabs;
|
||||
};
|
||||
const mockUseHistory = { push: jest.fn() };
|
||||
const mockLocation = { search: '' };
|
||||
|
||||
jest.mock('components/PermissionProvider/PermissionProvider', () => ({
|
||||
usePermissionProvider: jest.fn().mockImplementation(() => ({
|
||||
permissions: {
|
||||
testCase: testCasePermission,
|
||||
},
|
||||
})),
|
||||
}));
|
||||
jest.mock('rest/testAPI', () => {
|
||||
return {
|
||||
...jest.requireActual('rest/testAPI'),
|
||||
getListTestCase: jest
|
||||
.fn()
|
||||
.mockImplementation(() =>
|
||||
Promise.resolve({ data: [], paging: { total: 0 } })
|
||||
),
|
||||
getTestCaseById: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||
};
|
||||
});
|
||||
jest.mock('rest/searchAPI', () => {
|
||||
return {
|
||||
...jest.requireActual('rest/searchAPI'),
|
||||
searchQuery: jest
|
||||
.fn()
|
||||
.mockImplementation(() =>
|
||||
Promise.resolve({ hits: { hits: [], total: { value: 0 } } })
|
||||
),
|
||||
};
|
||||
});
|
||||
jest.mock('react-router-dom', () => {
|
||||
return {
|
||||
...jest.requireActual('react-router-dom'),
|
||||
useParams: jest.fn().mockImplementation(() => mockUseParam),
|
||||
useHistory: jest.fn().mockImplementation(() => mockUseHistory),
|
||||
useLocation: jest.fn().mockImplementation(() => mockLocation),
|
||||
};
|
||||
});
|
||||
jest.mock('../SummaryPannel/SummaryPanel.component', () => {
|
||||
return {
|
||||
SummaryPanel: jest
|
||||
.fn()
|
||||
.mockImplementation(() => <div>SummaryPanel.component</div>),
|
||||
};
|
||||
});
|
||||
jest.mock('components/common/next-previous/NextPrevious', () => {
|
||||
return jest.fn().mockImplementation(() => <div>NextPrevious.component</div>);
|
||||
});
|
||||
jest.mock('components/common/searchbar/Searchbar', () => {
|
||||
return jest.fn().mockImplementation(() => <div>Searchbar.component</div>);
|
||||
});
|
||||
jest.mock('components/ProfilerDashboard/component/DataQualityTab', () => {
|
||||
return jest
|
||||
.fn()
|
||||
.mockImplementation(() => <div>DataQualityTab.component</div>);
|
||||
});
|
||||
jest.mock('components/common/error-with-placeholder/ErrorPlaceHolder', () => {
|
||||
return jest
|
||||
.fn()
|
||||
.mockImplementation(({ type }) => (
|
||||
<div data-testid={`error-placeholder-type-${type}`}>
|
||||
ErrorPlaceHolder.component
|
||||
</div>
|
||||
));
|
||||
});
|
||||
|
||||
describe('TestCases component', () => {
|
||||
it('component should render', async () => {
|
||||
render(<TestCases />);
|
||||
|
||||
expect(
|
||||
await screen.findByTestId('test-case-container')
|
||||
).toBeInTheDocument();
|
||||
expect(await screen.findByText('Searchbar.component')).toBeInTheDocument();
|
||||
expect(
|
||||
await screen.findByText('SummaryPanel.component')
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
await screen.findByText('DataQualityTab.component')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('on page load getListTestCase API should call', async () => {
|
||||
const mockGetListTestCase = getListTestCase as jest.Mock;
|
||||
|
||||
render(<TestCases />);
|
||||
|
||||
expect(mockGetListTestCase).toHaveBeenCalledWith({
|
||||
fields: 'testDefinition,testCaseResult,testSuite',
|
||||
});
|
||||
});
|
||||
|
||||
it('should call searchQuery api, if there is search term in URL', async () => {
|
||||
const mockSearchQuery = searchQuery as jest.Mock;
|
||||
mockLocation.search = '?searchValue=sale';
|
||||
|
||||
render(<TestCases />);
|
||||
|
||||
expect(mockSearchQuery).toHaveBeenCalledWith({
|
||||
fetchSource: false,
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
query: 'sale',
|
||||
searchIndex: 'test_case_search_index',
|
||||
});
|
||||
});
|
||||
});
|
@ -13,6 +13,7 @@
|
||||
import { Button, Col, Row, Table } from 'antd';
|
||||
import { ColumnsType } from 'antd/lib/table';
|
||||
import { AxiosError } from 'axios';
|
||||
import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder';
|
||||
import FilterTablePlaceHolder from 'components/common/error-with-placeholder/FilterTablePlaceHolder';
|
||||
import NextPrevious from 'components/common/next-previous/NextPrevious';
|
||||
import { OwnerLabel } from 'components/common/OwnerLabel/OwnerLabel.component';
|
||||
@ -26,6 +27,7 @@ import {
|
||||
ROUTES,
|
||||
} from 'constants/constants';
|
||||
import { PROGRESS_BAR_COLOR } from 'constants/TestSuite.constant';
|
||||
import { ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum';
|
||||
import { EntityTabs } from 'enums/entity.enum';
|
||||
import { TestSummary } from 'generated/entity/data/table';
|
||||
import { TestSuite } from 'generated/tests/testSuite';
|
||||
@ -159,17 +161,28 @@ export const TestSuites = () => {
|
||||
useEffect(() => {
|
||||
if (testSuitePermission?.ViewAll || testSuitePermission?.ViewBasic) {
|
||||
fetchTestSuites();
|
||||
} else {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [tab, testSuitePermission]);
|
||||
|
||||
if (!testSuitePermission?.ViewAll && !testSuitePermission?.ViewBasic) {
|
||||
return <ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Row className="p-x-lg p-t-md" gutter={[16, 16]}>
|
||||
<Row
|
||||
className="p-x-lg p-t-md"
|
||||
data-testid="test-suite-container"
|
||||
gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<Row justify="end">
|
||||
<Col>
|
||||
{tab === DataQualityPageTabs.TEST_SUITES &&
|
||||
testSuitePermission?.Create && (
|
||||
<Link to={ROUTES.ADD_TEST_SUITES}>
|
||||
<Link
|
||||
data-testid="add-test-suite-btn"
|
||||
to={ROUTES.ADD_TEST_SUITES}>
|
||||
<Button type="primary">
|
||||
{t('label.add-entity', { entity: t('label.test-suite') })}
|
||||
</Button>
|
||||
|
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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 { render, screen } from '@testing-library/react';
|
||||
import { DataQualityPageTabs } from 'pages/DataQuality/DataQualityPage.interface';
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { getListTestSuites } from 'rest/testAPI';
|
||||
import { TestSuites } from './TestSuites.component';
|
||||
|
||||
const testSuitePermission = {
|
||||
Create: true,
|
||||
Delete: true,
|
||||
ViewAll: true,
|
||||
EditAll: true,
|
||||
EditDescription: true,
|
||||
EditDisplayName: true,
|
||||
EditCustomFields: true,
|
||||
};
|
||||
const mockUseParam = { tab: DataQualityPageTabs.TABLES } as {
|
||||
tab?: DataQualityPageTabs;
|
||||
};
|
||||
|
||||
jest.mock('components/PermissionProvider/PermissionProvider', () => ({
|
||||
usePermissionProvider: jest.fn().mockImplementation(() => ({
|
||||
permissions: {
|
||||
testSuite: testSuitePermission,
|
||||
},
|
||||
})),
|
||||
}));
|
||||
jest.mock('rest/testAPI', () => {
|
||||
return {
|
||||
...jest.requireActual('rest/testAPI'),
|
||||
getListTestSuites: jest
|
||||
.fn()
|
||||
.mockImplementation(() =>
|
||||
Promise.resolve({ data: [], paging: { total: 0 } })
|
||||
),
|
||||
};
|
||||
});
|
||||
jest.mock('react-router-dom', () => {
|
||||
return {
|
||||
...jest.requireActual('react-router-dom'),
|
||||
useParams: jest.fn().mockImplementation(() => mockUseParam),
|
||||
};
|
||||
});
|
||||
jest.mock('../SummaryPannel/SummaryPanel.component', () => {
|
||||
return {
|
||||
SummaryPanel: jest
|
||||
.fn()
|
||||
.mockImplementation(() => <div>SummaryPanel.component</div>),
|
||||
};
|
||||
});
|
||||
jest.mock('components/common/next-previous/NextPrevious', () => {
|
||||
return jest.fn().mockImplementation(() => <div>NextPrevious.component</div>);
|
||||
});
|
||||
jest.mock('components/common/error-with-placeholder/ErrorPlaceHolder', () => {
|
||||
return jest
|
||||
.fn()
|
||||
.mockImplementation(({ type }) => (
|
||||
<div data-testid={`error-placeholder-type-${type}`}>
|
||||
ErrorPlaceHolder.component
|
||||
</div>
|
||||
));
|
||||
});
|
||||
|
||||
describe('TestSuites component', () => {
|
||||
it('component should render', async () => {
|
||||
render(<TestSuites />);
|
||||
const tableHeader = await screen.findAllByRole('columnheader');
|
||||
const labels = tableHeader.map((header) => header.textContent);
|
||||
|
||||
expect(tableHeader).toHaveLength(4);
|
||||
expect(labels).toStrictEqual([
|
||||
'label.name',
|
||||
'label.test-plural',
|
||||
'label.success %',
|
||||
'label.owner',
|
||||
]);
|
||||
expect(await screen.findByTestId('test-suite-table')).toBeInTheDocument();
|
||||
expect(
|
||||
await screen.findByText('SummaryPanel.component')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should send testSuiteType executable in api, if active tab is tables', async () => {
|
||||
const mockGetListTestSuites = getListTestSuites as jest.Mock;
|
||||
|
||||
render(<TestSuites />);
|
||||
|
||||
expect(
|
||||
await screen.findByTestId('test-suite-container')
|
||||
).toBeInTheDocument();
|
||||
expect(mockGetListTestSuites).toHaveBeenCalledWith({
|
||||
fields: 'owner,summary',
|
||||
testSuiteType: 'executable',
|
||||
});
|
||||
});
|
||||
|
||||
it('pagination should visible if total is grater than 10', async () => {
|
||||
(getListTestSuites as jest.Mock).mockImplementationOnce(() =>
|
||||
Promise.resolve({ data: [], paging: { total: 15 } })
|
||||
);
|
||||
|
||||
render(<TestSuites />);
|
||||
|
||||
expect(
|
||||
await screen.findByText('NextPrevious.component')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// TestSuite type test
|
||||
it('add test suite button should be visible, if type is testSuite', async () => {
|
||||
mockUseParam.tab = DataQualityPageTabs.TEST_SUITES;
|
||||
render(<TestSuites />, { wrapper: MemoryRouter });
|
||||
|
||||
expect(await screen.findByTestId('add-test-suite-btn')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should send testSuiteType logical in api, if active tab is tables', async () => {
|
||||
mockUseParam.tab = DataQualityPageTabs.TEST_SUITES;
|
||||
const mockGetListTestSuites = getListTestSuites as jest.Mock;
|
||||
|
||||
render(<TestSuites />, { wrapper: MemoryRouter });
|
||||
|
||||
expect(
|
||||
await screen.findByTestId('test-suite-container')
|
||||
).toBeInTheDocument();
|
||||
expect(mockGetListTestSuites).toHaveBeenCalledWith({
|
||||
fields: 'owner,summary',
|
||||
testSuiteType: 'logical',
|
||||
});
|
||||
});
|
||||
|
||||
it('should render no data placeholder, if there is no permission', async () => {
|
||||
mockUseParam.tab = DataQualityPageTabs.TEST_SUITES;
|
||||
testSuitePermission.ViewAll = false;
|
||||
render(<TestSuites />, { wrapper: MemoryRouter });
|
||||
|
||||
expect(
|
||||
await screen.findByTestId('error-placeholder-type-PERMISSION')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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, fireEvent, render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { getDataQualityPagePath } from 'utils/RouterUtils';
|
||||
import DataQualityPage from './DataQualityPage';
|
||||
import { DataQualityPageTabs } from './DataQualityPage.interface';
|
||||
|
||||
const mockUseParam = { tab: DataQualityPageTabs.TABLES } as {
|
||||
tab?: DataQualityPageTabs;
|
||||
};
|
||||
const mockUseHistory = {
|
||||
push: jest.fn(),
|
||||
};
|
||||
|
||||
// mock components
|
||||
jest.mock('components/containers/PageLayoutV1', () => {
|
||||
return jest.fn().mockImplementation(({ children }) => <div>{children}</div>);
|
||||
});
|
||||
jest.mock('components/DataQuality/TestSuites/TestSuites.component', () => {
|
||||
return {
|
||||
TestSuites: jest
|
||||
.fn()
|
||||
.mockImplementation(() => <div>TestSuites.component</div>),
|
||||
};
|
||||
});
|
||||
jest.mock('components/DataQuality/TestCases/TestCases.component', () => {
|
||||
return {
|
||||
TestCases: jest
|
||||
.fn()
|
||||
.mockImplementation(() => <div>TestCases.component</div>),
|
||||
};
|
||||
});
|
||||
jest.mock('react-router-dom', () => {
|
||||
return {
|
||||
useParams: jest.fn().mockImplementation(() => mockUseParam),
|
||||
useHistory: jest.fn().mockImplementation(() => mockUseHistory),
|
||||
};
|
||||
});
|
||||
|
||||
describe('DataQualityPage', () => {
|
||||
it('component should render', async () => {
|
||||
render(<DataQualityPage />);
|
||||
|
||||
expect(await screen.findByTestId('page-title')).toBeInTheDocument();
|
||||
expect(await screen.findByTestId('page-sub-title')).toBeInTheDocument();
|
||||
expect(await screen.findByTestId('tabs')).toBeInTheDocument();
|
||||
expect(await screen.findByText('TestSuites.component')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render 3 tabs', async () => {
|
||||
render(<DataQualityPage />);
|
||||
|
||||
const tabs = await screen.findAllByRole('tab');
|
||||
|
||||
expect(tabs).toHaveLength(3);
|
||||
});
|
||||
|
||||
it('should change the tab, onClick of tab', async () => {
|
||||
render(<DataQualityPage />);
|
||||
|
||||
const tabs = await screen.findAllByRole('tab');
|
||||
|
||||
expect(await screen.findByText('TestSuites.component')).toBeInTheDocument();
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(tabs[1]);
|
||||
});
|
||||
|
||||
expect(mockUseHistory.push).toHaveBeenCalledWith(
|
||||
getDataQualityPagePath(DataQualityPageTabs.TEST_CASES)
|
||||
);
|
||||
});
|
||||
|
||||
it('should render tables tab by default', async () => {
|
||||
mockUseParam.tab = undefined;
|
||||
render(<DataQualityPage />);
|
||||
|
||||
expect(await screen.findByText('TestSuites.component')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render testCase tab, if active tab is testCase', async () => {
|
||||
mockUseParam.tab = DataQualityPageTabs.TEST_CASES;
|
||||
render(<DataQualityPage />);
|
||||
|
||||
expect(await screen.findByText('TestCases.component')).toBeInTheDocument();
|
||||
});
|
||||
});
|
@ -58,10 +58,15 @@ const DataQualityPage = () => {
|
||||
<PageLayoutV1 pageTitle="Quality">
|
||||
<Row className="p-t-md" gutter={[0, 16]}>
|
||||
<Col className="p-x-lg" span={24}>
|
||||
<Typography.Title className="m-b-md" level={5}>
|
||||
<Typography.Title
|
||||
className="m-b-md"
|
||||
data-testid="page-title"
|
||||
level={5}>
|
||||
{t('label.data-quality')}
|
||||
</Typography.Title>
|
||||
<Typography.Paragraph className="text-grey-muted">
|
||||
<Typography.Paragraph
|
||||
className="text-grey-muted"
|
||||
data-testid="page-sub-title">
|
||||
{t('message.page-sub-header-for-data-quality')}
|
||||
</Typography.Paragraph>
|
||||
</Col>
|
||||
|
Loading…
x
Reference in New Issue
Block a user