ui: added unit test for data quality page part 1 (#12267)

This commit is contained in:
Shailesh Parmar 2023-07-04 14:45:31 +05:30 committed by GitHub
parent 16280ffd1e
commit 75d7f1df68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 424 additions and 5 deletions

View File

@ -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

View File

@ -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',
});
});
});

View File

@ -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>

View File

@ -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();
});
});

View File

@ -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();
});
});

View File

@ -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>