Minor: improve the unit test coverage for ui component part 2 (#15097)

* Minor: improve the unit test coverage for ui component part 2

* miner fix

* added unt test for frequently joined tables

* added unit test for swagger component

* style fix

* added unit test for request description and tags page
This commit is contained in:
Shailesh Parmar 2024-02-09 22:10:16 +05:30 committed by GitHub
parent 6b770f4b75
commit 1005097208
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 540 additions and 6 deletions

View File

@ -0,0 +1,40 @@
/*
* Copyright 2024 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 React from 'react';
import SwaggerPage from './index';
jest.mock('./RapiDocReact', () => {
return jest.fn().mockImplementation((props) => (
<div>
<p>RapiDocReact.component</p>
<p>{props['api-key-value']}</p>
</div>
));
});
describe('SwaggerPage component', () => {
it('renders SwaggerPage component correctly', async () => {
// Mocking localStorage.getItem method
const mockGetItem = jest.spyOn(window.localStorage.__proto__, 'getItem');
mockGetItem.mockReturnValue('fakeToken'); // Mocking the return value of getItem
render(<SwaggerPage />);
expect(await screen.findByTestId('fluid-container')).toBeInTheDocument();
expect(
await screen.findByText('RapiDocReact.component')
).toBeInTheDocument();
expect(await screen.findByText('Bearer fakeToken')).toBeInTheDocument();
});
});

View File

@ -33,13 +33,19 @@ export const FrequentlyJoinedTables = ({
const { t } = useTranslation();
return (
<Row className="m-b-lg" gutter={[0, 8]}>
<Row
className="m-b-lg"
data-testid="frequently-joint-table-container"
gutter={[0, 8]}>
<Col className="m-b" span={24}>
<Typography.Text className="right-panel-label">
{t('label.frequently-joined-table-plural')}
</Typography.Text>
</Col>
<Col className="frequently-joint-data-container" span={24}>
<Col
className="frequently-joint-data-container"
data-testid="frequently-joint-data-container"
span={24}>
{joinedTables.map((table) => (
<Space
className="w-full frequently-joint-data"

View File

@ -0,0 +1,53 @@
/*
* Copyright 2024 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 React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { FrequentlyJoinedTables } from './FrequentlyJoinedTables.component';
const mockFrequentlyJoinedTablesProps = {
joinedTables: [
{
name: 'test',
fullyQualifiedName: 'test',
joinCount: 1,
},
],
};
describe('FrequentlyJoinedTables component', () => {
it('should render the component', async () => {
render(<FrequentlyJoinedTables {...mockFrequentlyJoinedTablesProps} />, {
wrapper: MemoryRouter,
});
expect(
await screen.findByTestId('frequently-joint-table-container')
).toBeInTheDocument();
expect(
await screen.findByTestId('frequently-joint-data-container')
).toBeInTheDocument();
expect(
await screen.findByText('label.frequently-joined-table-plural')
).toBeInTheDocument();
});
it("should show the table's name and join count", async () => {
render(<FrequentlyJoinedTables {...mockFrequentlyJoinedTablesProps} />, {
wrapper: MemoryRouter,
});
expect(await screen.findByText('test')).toBeInTheDocument();
expect(await screen.findByText('1')).toBeInTheDocument();
});
});

View File

@ -0,0 +1,141 @@
/*
* Copyright 2024 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, { forwardRef } from 'react';
import { postThread } from '../../../rest/feedsAPI';
import RequestDescription from './RequestDescriptionPage';
const mockUseHistory = {
push: jest.fn(),
goBack: jest.fn(),
};
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useParams: jest.fn().mockReturnValue({ entityType: 'table' }),
useLocation: jest
.fn()
.mockReturnValue({ search: 'field=columns&value="address.street_name"' }),
useHistory: jest.fn().mockImplementation(() => mockUseHistory),
}));
jest.mock('../../../components/common/ResizablePanels/ResizablePanels', () =>
jest.fn().mockImplementation(({ firstPanel, secondPanel }) => (
<>
<div>{firstPanel.children}</div>
<div>{secondPanel.children}</div>
</>
))
);
jest.mock('../../../utils/TasksUtils', () => ({
fetchEntityDetail: jest
.fn()
.mockImplementation((_entityType, _decodedEntityFQN, setEntityData) => {
setEntityData({
id: 'id1',
name: 'dim_location',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify.dim_location',
tableType: 'Regular',
owner: {
id: 'id1',
name: 'sample_data',
type: 'User',
},
});
}),
fetchOptions: jest.fn(),
getBreadCrumbList: jest.fn().mockReturnValue([]),
getTaskMessage: jest.fn().mockReturnValue('Task message'),
}));
jest.mock('../shared/Assignees', () =>
jest.fn().mockImplementation(() => <div>Assignees.component</div>)
);
jest.mock(
'../../../components/ExploreV1/ExploreSearchCard/ExploreSearchCard',
() =>
jest.fn().mockImplementation(() => <div>ExploreSearchCard.component</div>)
);
jest.mock(
'../../../components/common/TitleBreadcrumb/TitleBreadcrumb.component',
() => jest.fn().mockImplementation(() => <div>TitleBreadcrumb.component</div>)
);
jest.mock('../../../components/common/RichTextEditor/RichTextEditor', () =>
forwardRef(
jest.fn().mockImplementation(() => <div>RichTextEditor.component</div>)
)
);
jest.mock('../../../rest/feedsAPI', () => ({
postThread: jest.fn().mockResolvedValue({}),
}));
jest.mock('../../../hooks/useFqn', () => ({
useFqn: jest
.fn()
.mockReturnValue({ fqn: 'sample_data.ecommerce_db.shopify.dim_location' }),
}));
describe('RequestDescriptionPage', () => {
it('should render component', async () => {
render(<RequestDescription />);
expect(
await screen.findByText('TitleBreadcrumb.component')
).toBeInTheDocument();
expect(await screen.findByText('Assignees.component')).toBeInTheDocument();
expect(
await screen.findByText('RichTextEditor.component')
).toBeInTheDocument();
expect(await screen.findByTestId('form-title')).toBeInTheDocument();
expect(await screen.findByTestId('form-container')).toBeInTheDocument();
expect(await screen.findByTestId('title')).toBeInTheDocument();
expect(await screen.findByTestId('cancel-btn')).toBeInTheDocument();
expect(await screen.findByTestId('submit-btn')).toBeInTheDocument();
});
it("should go back to previous page when 'Cancel' button is clicked", async () => {
render(<RequestDescription />);
const cancelBtn = await screen.findByTestId('cancel-btn');
act(() => {
fireEvent.click(cancelBtn);
});
expect(mockUseHistory.goBack).toHaveBeenCalled();
});
it('should submit form when submit button is clicked', async () => {
const mockPostThread = postThread as jest.Mock;
render(<RequestDescription />);
const submitBtn = await screen.findByTestId('submit-btn');
await act(async () => {
fireEvent.click(submitBtn);
});
expect(mockPostThread).toHaveBeenCalledWith({
about:
'<#E::table::sample_data.ecommerce_db.shopify.dim_location::columns::"address.street_name"::description>',
from: undefined,
message: 'Task message',
taskDetails: {
assignees: [
{
id: 'id1',
type: 'User',
},
],
oldValue: '',
suggestion: undefined,
type: 'RequestDescription',
},
type: 'Task',
});
});
});

View File

@ -209,7 +209,11 @@ const RequestDescription = () => {
entity: t('label.task'),
})}
</Typography.Paragraph>
<Form form={form} layout="vertical" onFinish={onCreateTask}>
<Form
data-testid="form-container"
form={form}
layout="vertical"
onFinish={onCreateTask}>
<Form.Item
data-testid="title"
label={`${t('label.task-entity', {
@ -265,11 +269,11 @@ const RequestDescription = () => {
className="w-full justify-end"
data-testid="cta-buttons"
size={16}>
<Button type="link" onClick={back}>
<Button data-testid="cancel-btn" type="link" onClick={back}>
{t('label.back')}
</Button>
<Button
data-testid="submit-test"
data-testid="submit-btn"
htmlType="submit"
loading={isLoading}
type="primary">

View File

@ -0,0 +1,141 @@
/*
* Copyright 2024 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 { MemoryRouter } from 'react-router-dom';
import { postThread } from '../../../rest/feedsAPI';
import RequestTag from './RequestTagPage';
const mockUseHistory = {
push: jest.fn(),
goBack: jest.fn(),
};
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useParams: jest.fn().mockReturnValue({ entityType: 'table' }),
useLocation: jest
.fn()
.mockReturnValue({ search: 'field=columns&value="address.street_name"' }),
useHistory: jest.fn().mockImplementation(() => mockUseHistory),
}));
jest.mock('../../../components/common/ResizablePanels/ResizablePanels', () =>
jest.fn().mockImplementation(({ firstPanel, secondPanel }) => (
<>
<div>{firstPanel.children}</div>
<div>{secondPanel.children}</div>
</>
))
);
jest.mock('../../../utils/TasksUtils', () => ({
fetchEntityDetail: jest
.fn()
.mockImplementation((_entityType, _decodedEntityFQN, setEntityData) => {
setEntityData({
id: 'id1',
name: 'dim_location',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify.dim_location',
tableType: 'Regular',
owner: {
id: 'id1',
name: 'sample_data',
type: 'User',
},
});
}),
fetchOptions: jest.fn(),
getBreadCrumbList: jest.fn().mockReturnValue([]),
getTaskMessage: jest.fn().mockReturnValue('Task message'),
}));
jest.mock('../shared/Assignees', () =>
jest.fn().mockImplementation(() => <div>Assignees.component</div>)
);
jest.mock(
'../../../components/common/TitleBreadcrumb/TitleBreadcrumb.component',
() => jest.fn().mockImplementation(() => <div>TitleBreadcrumb.component</div>)
);
jest.mock('../../../rest/feedsAPI', () => ({
postThread: jest.fn().mockResolvedValue({}),
}));
jest.mock(
'../../../components/ExploreV1/ExploreSearchCard/ExploreSearchCard',
() =>
jest.fn().mockImplementation(() => <div>ExploreSearchCard.component</div>)
);
jest.mock('../shared/TagSuggestion', () =>
jest.fn().mockImplementation(() => <div>TagSuggestion.component</div>)
);
jest.mock('../../../hooks/useFqn', () => ({
useFqn: jest
.fn()
.mockReturnValue({ fqn: 'sample_data.ecommerce_db.shopify.dim_location' }),
}));
describe('RequestTagPage', () => {
it('should render component', async () => {
render(<RequestTag />, { wrapper: MemoryRouter });
expect(
await screen.findByText('TitleBreadcrumb.component')
).toBeInTheDocument();
expect(await screen.findByText('Assignees.component')).toBeInTheDocument();
expect(
await screen.findByText('TagSuggestion.component')
).toBeInTheDocument();
expect(await screen.findByTestId('form-title')).toBeInTheDocument();
expect(await screen.findByTestId('form-container')).toBeInTheDocument();
expect(await screen.findByTestId('title')).toBeInTheDocument();
expect(await screen.findByTestId('cancel-btn')).toBeInTheDocument();
expect(await screen.findByTestId('submit-tag-request')).toBeInTheDocument();
});
it("should go back to previous page when 'Cancel' button is clicked", async () => {
render(<RequestTag />, { wrapper: MemoryRouter });
const cancelBtn = await screen.findByTestId('cancel-btn');
act(() => {
fireEvent.click(cancelBtn);
});
expect(mockUseHistory.goBack).toHaveBeenCalled();
});
it('should submit form when submit button is clicked', async () => {
const mockPostThread = postThread as jest.Mock;
render(<RequestTag />, { wrapper: MemoryRouter });
const submitBtn = await screen.findByTestId('submit-tag-request');
await act(async () => {
fireEvent.click(submitBtn);
});
expect(mockPostThread).toHaveBeenCalledWith({
about:
'<#E::table::sample_data.ecommerce_db.shopify.dim_location::columns::"address.street_name"::tags>',
from: undefined,
message: 'Task message',
taskDetails: {
assignees: [
{
id: 'id1',
type: 'User',
},
],
oldValue: '[]',
suggestion: '[]',
type: 'RequestTag',
},
type: 'Task',
});
});
});

View File

@ -196,6 +196,7 @@ const RequestTag = () => {
})}
</Typography.Paragraph>
<Form
data-testid="form-container"
form={form}
initialValues={{
suggestTags: [],
@ -249,7 +250,7 @@ const RequestTag = () => {
className="w-full justify-end"
data-testid="cta-buttons"
size={16}>
<Button type="link" onClick={back}>
<Button data-testid="cancel-btn" type="link" onClick={back}>
{t('label.back')}
</Button>
<Button

View File

@ -0,0 +1,148 @@
/*
* Copyright 2024 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 React from 'react';
import { useFqn } from '../../hooks/useFqn';
import { getIngestionPipelineByFqn } from '../../rest/ingestionPipelineAPI';
import { getTestSuiteByName } from '../../rest/testAPI';
import TestSuiteIngestionPage from './TestSuiteIngestionPage';
const mockTestSuite = {
id: '58e37b60-aa4f-4228-8cb7-89fe659fa14b',
name: 'sample_data.ecommerce_db.shopify.dim_address.testSuite',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify.dim_address.testSuite',
description: 'This is an executable test suite linked to an entity',
serviceType: 'TestSuite',
deleted: false,
executable: true,
executableEntityReference: {
id: '8f7c814f-d6ca-4ce2-911e-d7f3586c955b',
type: 'table',
name: 'dim_address',
fullyQualifiedName: 'sample_data.ecommerce_db.shopify.dim_address',
},
testCaseResultSummary: [],
};
jest.mock('../../hooks/useFqn', () => {
return {
useFqn: jest.fn().mockReturnValue({
fqn: 'testSuiteFQN',
}),
};
});
const mockUseHistory = {
goBack: jest.fn(),
};
jest.mock('react-router-dom', () => {
return {
useHistory: jest.fn().mockImplementation(() => mockUseHistory),
};
});
jest.mock('../../rest/testAPI', () => {
return {
getTestSuiteByName: jest
.fn()
.mockImplementation(() => Promise.resolve(mockTestSuite)),
};
});
jest.mock('../../rest/ingestionPipelineAPI', () => {
return {
getIngestionPipelineByFqn: jest
.fn()
.mockImplementation(() => Promise.resolve({})),
};
});
jest.mock('../../components/common/ResizablePanels/ResizablePanels', () =>
jest.fn().mockImplementation(({ firstPanel, secondPanel }) => (
<>
<div>{firstPanel.children}</div>
<div>{secondPanel.children}</div>
</>
))
);
jest.mock('../../components/common/ErrorWithPlaceholder/ErrorPlaceHolder', () =>
jest.fn().mockReturnValue(<div>ErrorPlaceHolder.component</div>)
);
jest.mock(
'../../components/common/TitleBreadcrumb/TitleBreadcrumb.component',
() => jest.fn().mockReturnValue(<div>TitleBreadcrumb.component</div>)
);
jest.mock('../../components/AddDataQualityTest/TestSuiteIngestion', () =>
jest.fn().mockImplementation(({ onCancel }) => (
<div>
<p>TestSuiteIngestion.component</p>
<button data-testid="back-btn" onClick={onCancel}>
Back
</button>
</div>
))
);
jest.mock('../../components/AddDataQualityTest/components/RightPanel', () =>
jest.fn().mockReturnValue(<div>RightPanel.component</div>)
);
describe('TestSuiteIngestionPage', () => {
it('should render component', async () => {
await act(async () => {
render(<TestSuiteIngestionPage />);
});
expect(
await screen.findByText('TitleBreadcrumb.component')
).toBeInTheDocument();
expect(
await screen.findByText('TestSuiteIngestion.component')
).toBeInTheDocument();
expect(await screen.findByText('RightPanel.component')).toBeInTheDocument();
});
it('should render error placeholder', async () => {
(getTestSuiteByName as jest.Mock).mockImplementationOnce(() =>
Promise.reject(new Error('Error'))
);
await act(async () => {
render(<TestSuiteIngestionPage />);
});
expect(
await screen.findByText('ErrorPlaceHolder.component')
).toBeInTheDocument();
});
it("should fetch ingestion details if ingestionFQN is present in URL's query params", async () => {
(useFqn as jest.Mock).mockImplementationOnce(() => ({
fqn: 'testSuiteFQN',
ingestionFQN: 'ingestionFQN',
}));
getIngestionPipelineByFqn as jest.Mock;
await act(async () => {
render(<TestSuiteIngestionPage />);
});
expect(getIngestionPipelineByFqn).toHaveBeenCalledWith('ingestionFQN');
});
it('should go back on back button click', async () => {
await act(async () => {
render(<TestSuiteIngestionPage />);
});
const backButton = screen.getByTestId('back-btn');
backButton.click();
expect(mockUseHistory.goBack).toHaveBeenCalled();
});
});