Test suit for explore, service, and database page (#622)

* Adding test-suits for UI

* fixed broken tests

* fixed all test fail files

* removed parsing errors from files

* resolved test-suits error

* fiexed all the failing test

* fixed tabledatacard title padding

* fixed popOver test

* fixed eslint issue in file

* added eslint disable on top of file

* add test for searchData and MyDataHeader

* add addtional test for teams page

* test suits for teams page and its components

* added test cases for tags page

* added test for services page

* add test for service page and its component

* fixed typo

* test for databasedetails, myData and explore page

* test for service page

* fixed some failing test

* fixed failing test due to data type change

Co-authored-by: darth-coder00 <aashit@getcollate.io>
This commit is contained in:
Shailesh Parmar 2021-10-01 17:51:01 +05:30 committed by GitHub
parent 5a6eded1e7
commit b231e68c6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 423 additions and 54 deletions

View File

@ -15,7 +15,13 @@
* limitations under the License.
*/
import { render } from '@testing-library/react';
import {
findAllByTestId,
findByTestId,
findByText,
fireEvent,
render,
} from '@testing-library/react';
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import Appbar from './Appbar';
@ -26,6 +32,7 @@ jest.mock('../../hooks/authHooks', () => ({
isSignedIn: true,
isSignedOut: false,
isAuthenticatedRoute: true,
isAuthDisabled: true,
};
},
}));
@ -34,34 +41,49 @@ jest.mock('../Modals/WhatsNewModal', () => ({
WhatsNewModal: jest.fn().mockReturnValue(<p>WhatsNewModal</p>),
}));
jest.mock('../../axiosAPIs/miscAPI', () => ({
getVersion: jest.fn().mockImplementation(() =>
Promise.resolve({
data: {
version: '0.5.0-SNAPSHOT',
},
})
),
}));
describe('Test Appbar Component', () => {
it('Component should render', () => {
const { getByTestId } = render(<Appbar />, {
it('Component should render', async () => {
const { container } = render(<Appbar />, {
wrapper: MemoryRouter,
});
// Check for statis user for now
// TODO: Fix the tests when we have actual data
const dropdown = getByTestId('dropdown-profile');
const dropdown = await findByTestId(container, 'dropdown-profile');
const whatsnewModal = await findByTestId(container, 'whatsnew-modal');
const greetingText = await findByTestId(container, 'greeting-text');
expect(dropdown).toBeInTheDocument();
expect(whatsnewModal).toBeInTheDocument();
expect(greetingText).toBeInTheDocument();
});
it('Check for render Items by default', () => {
const { getAllByTestId } = render(<Appbar />, {
it('Check for render Items by default', async () => {
const { container } = render(<Appbar />, {
wrapper: MemoryRouter,
});
const items = getAllByTestId('appbar-item');
const items = await findAllByTestId(container, 'appbar-item');
expect(items).toHaveLength(2);
expect(items.map((i) => i.textContent)).toEqual(['', 'Explore']);
});
it('Check for render dropdown item', () => {
const { getAllByTestId } = render(<Appbar />, {
it('onClick of whatsNewModal, it should open', async () => {
const { container } = render(<Appbar />, {
wrapper: MemoryRouter,
});
const items = getAllByTestId('dropdown-item');
expect(items).toHaveLength(3);
const whatsnewModal = await findByTestId(container, 'whatsnew-modal');
fireEvent.click(whatsnewModal);
expect(await findByText(container, /WhatsNewModal/i)).toBeInTheDocument();
});
});

View File

@ -130,7 +130,7 @@ const Appbar: React.FC = (): JSX.Element => {
: appState.userDetails.displayName || appState.userDetails.name;
return (
<span>
<span data-testid="greeting-text">
Welcome, <span className="tw-font-medium">{name.split(' ')[0]}</span>
</span>
);
@ -238,6 +238,7 @@ const Appbar: React.FC = (): JSX.Element => {
</div>
<button
className="tw-nav focus:tw-no-underline hover:tw-underline"
data-testid="whatsnew-modal"
onClick={openModal}>
<SVGIcons
alt="Doc icon"

View File

@ -19,13 +19,13 @@ import { getByTestId, render } from '@testing-library/react';
import { TableDetail } from 'Models';
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { Column, ColumnDataType } from '../../generated/entity/data/table';
import { Column, DataType } from '../../generated/entity/data/table';
import SchemaTab from './SchemaTab';
const mockColumns: Column[] = [
{
name: 'testId',
columnDataType: ColumnDataType.String,
dataType: DataType.String,
description: 'string',
fullyQualifiedName: 'string',
tags: [{ tagFQN: 'string' }, { tagFQN: 'string2' }],

View File

@ -19,21 +19,23 @@ import { getAllByTestId, render } from '@testing-library/react';
import { TableDetail } from 'Models';
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { ColumnDataType } from '../../generated/entity/data/table';
import { Constraint, DataType, Table } from '../../generated/entity/data/table';
import SchemaTable from './SchemaTable';
jest.mock('../common/rich-text-editor/RichTextEditorPreviewer', () => {
return jest.fn().mockReturnValue(<p>RichTextEditorPreviewer</p>);
});
const mockColumns = [
const mockColumns: Table['columns'] = [
{
name: 'testId',
columnDataType: ColumnDataType.String,
description: 'string',
fullyQualifiedName: 'string',
constraint: Constraint.PrimaryKey,
dataType: DataType.Number,
dataTypeDisplay: 'numeric',
description: 'Unique identifier for the address.',
fullyQualifiedName: 'bigquery.shopify.dim_address.address_id',
name: 'address_id',
ordinalPosition: 1,
tags: [{ tagFQN: 'string' }, { tagFQN: 'string2' }],
ordinalPosition: 2,
},
];

View File

@ -127,7 +127,7 @@ describe('Test MyDataHeader Component', () => {
expect(getByText(container, /40 tables/i)).toBeInTheDocument();
expect(getByText(container, /13 topics/i)).toBeInTheDocument();
expect(getByText(container, /10 dashboards/i)).toBeInTheDocument();
expect(getByText(container, /4 of services/i)).toBeInTheDocument();
expect(getByText(container, /4 services/i)).toBeInTheDocument();
expect(getByText(container, /193 assets/i)).toBeInTheDocument();
});

View File

@ -0,0 +1,254 @@
import {
findByTestId,
findByText,
fireEvent,
render,
} from '@testing-library/react';
import React from 'react';
import { MemoryRouter } from 'react-router';
import DatabaseDetails from './';
const mockDatabase = {
id: '44d92cbd-65d3-4755-aaf9-b4bf01e0d822',
name: 'shopify',
fullyQualifiedName: 'bigquery.shopify',
description: 'This **mock** database contains tables related to',
href: 'http://localhost',
service: {
id: '451ccbeb-24d4-490d-891c-d00b5f18a13b',
type: 'databaseService',
name: 'bigquery',
description: 'BigQuery service used for shopify data',
href: 'http://localhost',
},
};
const mockServiceData = {
id: '451ccbeb-24d4-490d-891c-d00b5f18a13b',
name: 'bigquery',
serviceType: 'BigQuery',
description: 'BigQuery service used for shopify data',
href: 'http://localhost',
jdbc: { driverClass: 'jdbc', connectionUrl: 'jdbc://localhost' },
};
const mockTableData = {
data: [
{
id: 'b69fef11-3cbe-42fb-8303-9ac8e55629ba',
name: 'dim_address',
description:
'This dimension table contains the billing and shipping addresses of customers',
href: 'http://localhost:8585/',
tableType: 'Regular',
fullyQualifiedName: 'bigquery.shopify.dim_address',
columns: [
{
name: 'address_id',
columnDataType: 'NUMERIC',
description: 'Unique identifier for the address.',
fullyQualifiedName: 'bigquery.shopify.dim_address.address_id',
tags: [],
columnConstraint: 'PRIMARY_KEY',
ordinalPosition: 1,
},
],
usageSummary: {
dailyStats: { count: 100, percentileRank: 45 },
weeklyStats: { count: 100, percentileRank: 45 },
monthlyStats: { count: 100, percentileRank: 45 },
date: '2021-09-20',
},
tags: [
{
labelType: 'Manual',
state: 'Confirmed',
tagFQN: 'PersonalData.Personal',
},
],
},
],
paging: { after: 'ZMbpLOqQQsREk_7DmEOr', total: 12 },
};
jest.mock(
'../../components/common/rich-text-editor/RichTextEditorPreviewer',
() => {
return jest.fn().mockImplementation(({ markdown }) => <p>{markdown}</p>);
}
);
jest.mock('react-router-dom', () => ({
Link: jest
.fn()
.mockImplementation(({ children }: { children: React.ReactNode }) => (
<p data-testid="link">{children}</p>
)),
useHistory: jest.fn(),
useParams: jest.fn().mockReturnValue({
databaseFQN: 'bigquery.shopify',
}),
}));
jest.mock('../../AppState', () => {
return jest.fn().mockReturnValue({
inPageSearchText: '',
});
});
jest.mock('../../axiosAPIs/databaseAPI', () => ({
getDatabaseDetailsByFQN: jest
.fn()
.mockImplementation(() => Promise.resolve({ data: mockDatabase })),
patchDatabaseDetails: jest.fn(),
}));
jest.mock('../../components/containers/PageContainer', () => {
return jest
.fn()
.mockImplementation(({ children }: { children: React.ReactNode }) => (
<div data-testid="PageContainer">{children}</div>
));
});
jest.mock('../../axiosAPIs/serviceAPI', () => ({
getServiceById: jest
.fn()
.mockImplementation(() => Promise.resolve({ data: mockServiceData })),
}));
jest.mock('../../axiosAPIs/tableAPI', () => ({
getDatabaseTables: jest
.fn()
.mockImplementation(() => Promise.resolve({ data: mockTableData })),
}));
jest.mock('../../utils/TableUtils', () => ({
getOwnerFromId: jest.fn().mockReturnValue({
name: 'owner',
id: 'string',
type: 'user',
}),
getUsagePercentile: jest.fn().mockReturnValue('Medium - 45th pctile'),
}));
jest.mock('../../components/common/popover/PopOver', () => {
return jest
.fn()
.mockImplementation(({ children }: { children: React.ReactNode }) => (
<div data-testid="popover">{children}</div>
));
});
jest.mock('../../utils/CommonUtils', () => ({
getCurrentUserId: jest
.fn()
.mockReturnValue('5d5ca778-8bee-4ea0-bcb6-b17d92f7ef96'),
isEven: jest.fn().mockReturnValue(true),
}));
jest.mock('../../components/tags/tags', () => {
return jest.fn().mockReturnValue(<span>Tag</span>);
});
jest.mock('../../components/common/next-previous/NextPrevious', () => {
return jest.fn().mockReturnValue(<div>NextPrevious</div>);
});
jest.mock(
'../../components/common/title-breadcrumb/title-breadcrumb.component',
() => {
return jest.fn().mockReturnValue(<div>TitleBreadcrumb</div>);
}
);
jest.mock('../../utils/TagsUtils', () => ({
getTableTags: jest.fn().mockReturnValue([
{
labelType: 'Manual',
state: 'Confirmed',
tagFQN: 'PersonalData.Personal',
},
]),
}));
jest.mock(
'../../components/Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor',
() => ({
ModalWithMarkdownEditor: jest
.fn()
.mockReturnValue(<p>ModalWithMarkdownEditor</p>),
})
);
describe('Test DatabaseDetails page', () => {
it('Component should render', async () => {
const { container } = render(<DatabaseDetails />, {
wrapper: MemoryRouter,
});
const pageContainer = await findByTestId(container, 'page-container');
const titleBreadcrumb = await findByText(container, /TitleBreadcrumb/i);
const tableCount = await findByTestId(container, 'table-count');
const descriptionContainer = await findByTestId(
container,
'description-container'
);
const descriptionEditButton = await findByTestId(
container,
'description-edit-button'
);
const descriptionData = await findByTestId(container, 'description-data');
const databaseTable = await findByTestId(container, 'database-tables');
const count = tableCount.textContent ? parseInt(tableCount.textContent) : 0;
expect(pageContainer).toBeInTheDocument();
expect(titleBreadcrumb).toBeInTheDocument();
expect(count).toEqual(mockTableData.paging.total);
expect(descriptionContainer).toBeInTheDocument();
expect(descriptionEditButton).toBeInTheDocument();
expect(descriptionData).toBeInTheDocument();
expect(databaseTable).toBeInTheDocument();
});
it('Table and its header should render', async () => {
const { container } = render(<DatabaseDetails />, {
wrapper: MemoryRouter,
});
const databaseTable = await findByTestId(container, 'database-tables');
const tableHeader = await findByTestId(container, 'table-header');
const headerName = await findByTestId(container, 'header-name');
const headerDescription = await findByTestId(
container,
'header-description'
);
const headerOwner = await findByTestId(container, 'header-owner');
const headerUsage = await findByTestId(container, 'header-usage');
const headerTags = await findByTestId(container, 'header-tags');
const tableColumn = await findByTestId(container, 'tabale-column');
expect(databaseTable).toBeInTheDocument();
expect(tableHeader).toBeInTheDocument();
expect(headerName).toBeInTheDocument();
expect(headerDescription).toBeInTheDocument();
expect(headerOwner).toBeInTheDocument();
expect(headerUsage).toBeInTheDocument();
expect(headerTags).toBeInTheDocument();
expect(tableColumn).toBeInTheDocument();
});
it('on click of edit description icon ModalWithMarkdownEditor should open', async () => {
const { container } = render(<DatabaseDetails />, {
wrapper: MemoryRouter,
});
const editIcon = await findByTestId(container, 'description-edit-button');
fireEvent.click(editIcon);
expect(
await findByText(container, /ModalWithMarkdownEditor/i)
).toBeInTheDocument();
});
});

View File

@ -229,7 +229,7 @@ const DatabaseDetails: FunctionComponent = () => {
<Loader />
) : (
<PageContainer>
<div className="tw-px-4">
<div className="tw-px-4" data-testid="page-container">
<TitleBreadcrumb titleLinks={slashedTableName} />
<div className="tw-flex tw-gap-1 tw-mb-2 tw-mt-1">
@ -237,12 +237,18 @@ const DatabaseDetails: FunctionComponent = () => {
<span className="tw-text-grey-muted tw-font-normal">
Tables :
</span>{' '}
<span className="tw-pl-1 tw-font-normal">{instanceCount}</span>
<span
className="tw-pl-1 tw-font-normal"
data-testid="table-count">
{instanceCount}
</span>
</span>
</div>
<div className="tw-bg-white tw-mb-4">
<div className="tw-col-span-3">
<div className="schema-description tw-flex tw-flex-col tw-h-full tw-relative tw-border tw-border-main tw-rounded-md">
<div
className="schema-description tw-flex tw-flex-col tw-h-full tw-relative tw-border tw-border-main tw-rounded-md"
data-testid="description-container">
<div className="tw-flex tw-items-center tw-px-3 tw-py-1 tw-border-b tw-border-main">
<span className="tw-flex-1 tw-leading-8 tw-m-0 tw-text-sm tw-font-normal">
Description
@ -250,6 +256,7 @@ const DatabaseDetails: FunctionComponent = () => {
<div className="tw-flex-initial">
<button
className="focus:tw-outline-none"
data-testid="description-edit-button"
onClick={onDescriptionEdit}>
<SVGIcons
alt="edit"
@ -261,7 +268,7 @@ const DatabaseDetails: FunctionComponent = () => {
</div>
</div>
<div className="tw-px-3 tw-pl-5 tw-py-2 tw-overflow-y-auto">
<div data-testid="description" id="description" />
<div data-testid="description-data" id="description" />
{description ? (
<RichTextEditorPreviewer markdown={description} />
) : (
@ -286,13 +293,27 @@ const DatabaseDetails: FunctionComponent = () => {
<table
className="tw-bg-white tw-w-full tw-mb-4"
data-testid="database-tables">
<thead>
<thead data-testid="table-header">
<tr className="tableHead-row">
<th className="tableHead-cell">Table Name</th>
<th className="tableHead-cell">Description</th>
<th className="tableHead-cell">Owner</th>
<th className="tableHead-cell">Usage</th>
<th className="tableHead-cell tw-w-60">Tags</th>
<th className="tableHead-cell" data-testid="header-name">
Table Name
</th>
<th
className="tableHead-cell"
data-testid="header-description">
Description
</th>
<th className="tableHead-cell" data-testid="header-owner">
Owner
</th>
<th className="tableHead-cell" data-testid="header-usage">
Usage
</th>
<th
className="tableHead-cell tw-w-60"
data-testid="header-tags">
Tags
</th>
</tr>
</thead>
<tbody className="tableBody">
@ -303,7 +324,7 @@ const DatabaseDetails: FunctionComponent = () => {
'tableBody-row',
!isEven(index + 1) ? 'odd-row' : null
)}
data-testid="column"
data-testid="tabale-column"
key={index}>
<td className="tableBody-cell">
<Link

View File

@ -15,9 +15,9 @@
* limitations under the License.
*/
import { act, render, screen } from '@testing-library/react';
import { findAllByTestId, findByTestId, render } from '@testing-library/react';
import React from 'react';
import { getFilterString } from '../../utils/FilterUtils';
import { MemoryRouter } from 'react-router';
import ExplorePage from './index';
import { mockResponse } from './index.mock';
jest.mock('react-router-dom', () => ({
@ -36,7 +36,13 @@ jest.mock('../../utils/FilterUtils', () => ({
}));
jest.mock('../../components/searched-data/SearchedData', () => {
return jest.fn().mockReturnValue(<p>SearchedData</p>);
return jest
.fn()
.mockImplementation(({ children }: { children: React.ReactNode }) => (
<div data-testid="search-data">
<div data-testid="wrapped-content">{children}</div>
</div>
));
});
jest.mock('../../hooks/useToastContext', () => {
@ -44,19 +50,16 @@ jest.mock('../../hooks/useToastContext', () => {
});
describe('Test Explore page', () => {
it('Should Call Search API', async () => {
await act(async () => {
render(<ExplorePage />);
it('Component should render', async () => {
const { container } = render(<ExplorePage />, {
wrapper: MemoryRouter,
});
const searchData = await findByTestId(container, 'search-data');
const wrappedContent = await findByTestId(container, 'wrapped-content');
const tabs = await findAllByTestId(container, 'tab');
expect(await screen.findByText('SearchedData')).toBeInTheDocument();
});
it('getFilterString should return filter as string', async () => {
await act(async () => {
render(<ExplorePage />);
});
expect(getFilterString).toEqual(getFilterString);
expect(searchData).toBeInTheDocument();
expect(wrappedContent).toBeInTheDocument();
expect(tabs.length).toBe(3);
});
});

View File

@ -504,6 +504,7 @@ const ExplorePage: React.FC = (): React.ReactElement => {
className={`tw-pb-2 tw-px-4 tw-gh-tabs ${getActiveTabClass(
tab.tab
)}`}
data-testid="tab"
key={index}
onClick={() => {
onTabChange(tab.tab);

View File

@ -17,7 +17,12 @@
/* eslint-disable @typescript-eslint/camelcase */
import { findByTestId, render } from '@testing-library/react';
import {
findAllByTestId,
findByTestId,
findByText,
render,
} from '@testing-library/react';
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import MyDataPage from './index';
@ -189,13 +194,21 @@ jest.mock('../../axiosAPIs/miscAPI', () => ({
jest.mock('../../components/searched-data/SearchedData', () => {
return jest
.fn()
.mockReturnValue(<p data-testid="search-data">SearchedData</p>);
.mockImplementation(({ children }: { children: React.ReactNode }) => (
<div data-testid="search-data">
<div data-testid="wrapped-content">{children}</div>
</div>
));
});
jest.mock('../../components/recently-viewed/RecentlyViewed', () => {
return jest.fn().mockReturnValue(<p>RecentlyViewed</p>);
});
jest.mock('../../components/my-data/MyDataHeader', () => {
return jest.fn().mockReturnValue(<p>MyDataHeader</p>);
});
jest.mock('../../utils/ServiceUtils', () => ({
getAllServices: jest
.fn()
@ -211,7 +224,13 @@ describe('Test MyData page', () => {
wrapper: MemoryRouter,
});
const searchData = await findByTestId(container, 'search-data');
const wrappedContent = await findByTestId(container, 'wrapped-content');
const tabs = await findAllByTestId(container, 'tab');
const myDataHeader = await findByText(container, /MyDataHeader/i);
expect(searchData).toBeInTheDocument();
expect(wrappedContent).toBeInTheDocument();
expect(myDataHeader).toBeInTheDocument();
expect(tabs.length).toBe(3);
});
});

View File

@ -1,6 +1,8 @@
import {
findAllByTestId,
findByTestId,
findByText,
fireEvent,
queryByText,
render,
} from '@testing-library/react';
@ -77,14 +79,41 @@ jest.mock('../../utils/ServiceUtils', () => ({
serviceTypeLogo: jest.fn().mockReturnValue('img/path'),
}));
jest.mock(
'../../components/common/title-breadcrumb/title-breadcrumb.component',
() => {
return jest.fn().mockReturnValue(<div>TitleBreadcrumb</div>);
}
);
jest.mock(
'../../components/Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor',
() => ({
ModalWithMarkdownEditor: jest
.fn()
.mockReturnValue(<p>ModalWithMarkdownEditor</p>),
})
);
describe('Test ServicePage Component', () => {
it('Component should render', async () => {
const { container } = render(<ServicePage />, {
wrapper: MemoryRouter,
});
const servicePage = await findByTestId(container, 'service-page');
const titleBreadcrumb = await findByText(container, /TitleBreadcrumb/i);
const descriptionContainer = await findByTestId(
container,
'description-container'
);
const descriptionData = await findByTestId(container, 'description-data');
const descriptionEdit = await findByTestId(container, 'description-edit');
expect(servicePage).toBeInTheDocument();
expect(titleBreadcrumb).toBeInTheDocument();
expect(descriptionContainer).toBeInTheDocument();
expect(descriptionData).toBeInTheDocument();
expect(descriptionEdit).toBeInTheDocument();
});
it('Table should be visible if data is available', async () => {
@ -107,4 +136,18 @@ describe('Test ServicePage Component', () => {
expect(column.length).toBe(1);
});
it('on click of edit description icon ModalWithMarkdownEditor should open', async () => {
const { container } = render(<ServicePage />, {
wrapper: MemoryRouter,
});
const editIcon = await findByTestId(container, 'description-edit');
fireEvent.click(editIcon);
expect(
await findByText(container, /ModalWithMarkdownEditor/i)
).toBeInTheDocument();
});
});

View File

@ -567,7 +567,9 @@ const ServicePage: FunctionComponent = () => {
<div className="tw-bg-white tw-my-4">
<div className="tw-col-span-3">
<div className="schema-description tw-flex tw-flex-col tw-h-full tw-relative tw-border tw-border-main tw-rounded-md">
<div
className="schema-description tw-flex tw-flex-col tw-h-full tw-relative tw-border tw-border-main tw-rounded-md"
data-testid="description-container">
<div className="tw-flex tw-items-center tw-px-3 tw-py-1 tw-border-b tw-border-main">
<span className="tw-flex-1 tw-leading-8 tw-m-0 tw-text-sm tw-font-normal">
Description
@ -575,6 +577,7 @@ const ServicePage: FunctionComponent = () => {
<div className="tw-flex-initial">
<button
className="focus:tw-outline-none"
data-testid="description-edit"
onClick={onDescriptionEdit}>
<SVGIcons
alt="edit"
@ -586,7 +589,7 @@ const ServicePage: FunctionComponent = () => {
</div>
</div>
<div className="tw-px-3 tw-pl-5 tw-py-2 tw-overflow-y-auto">
<div data-testid="description" id="description" />
<div data-testid="description-data" id="description" />
{description ? (
<RichTextEditorPreviewer markdown={description} />
) : (