mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-12-26 23:18:25 +00:00
Add unit test for table entity page (#3730)
* Add unit test for table entity page * Add unit test for description component * Add unit for EntityPageInfo component * Add unit test for EntityTable component
This commit is contained in:
parent
9fb78ed2c1
commit
227d81951c
@ -11,7 +11,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { findByText, getByTestId, render } from '@testing-library/react';
|
||||
import {
|
||||
findByTestId,
|
||||
findByText,
|
||||
getByTestId,
|
||||
queryByTestId,
|
||||
render,
|
||||
} from '@testing-library/react';
|
||||
import { LeafNodes, LoadingNodeState } from 'Models';
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
@ -58,6 +64,40 @@ const mockUserTeam = [
|
||||
type: 'type',
|
||||
},
|
||||
];
|
||||
|
||||
const mockThreads = [
|
||||
{
|
||||
id: '465b2dfb-300e-45f5-a1a6-e19c6225e9e7',
|
||||
href: 'http://localhost:8585/api/v1/feed/465b2dfb-300e-45f5-a1a6-e19c6225e9e7',
|
||||
threadTs: 1647434125848,
|
||||
about: '<#E/table/bigquery_gcp.shopify.raw_product_catalog/description>',
|
||||
entityId: 'f1ebcfdf-d4b8-43bd-add2-1789e25ddde3',
|
||||
createdBy: 'aaron_johnson0',
|
||||
updatedAt: 1647434125848,
|
||||
updatedBy: 'anonymous',
|
||||
resolved: false,
|
||||
message: 'New thread.',
|
||||
postsCount: 0,
|
||||
posts: [],
|
||||
relativeDay: 'Today',
|
||||
},
|
||||
{
|
||||
id: '40c2faec-0159-4d86-9b15-c17f3e1c081b',
|
||||
href: 'http://localhost:8585/api/v1/feed/40c2faec-0159-4d86-9b15-c17f3e1c081b',
|
||||
threadTs: 1647411418056,
|
||||
about: '<#E/table/bigquery_gcp.shopify.raw_product_catalog/description>',
|
||||
entityId: 'f1ebcfdf-d4b8-43bd-add2-1789e25ddde3',
|
||||
createdBy: 'sachin.c',
|
||||
updatedAt: 1647434031435,
|
||||
updatedBy: 'anonymous',
|
||||
resolved: false,
|
||||
message: 'New thread.',
|
||||
postsCount: 0,
|
||||
posts: [],
|
||||
relativeDay: 'Today',
|
||||
},
|
||||
];
|
||||
|
||||
const DatasetDetailsProps = {
|
||||
activeTab: 1,
|
||||
columns: [],
|
||||
@ -93,7 +133,7 @@ const DatasetDetailsProps = {
|
||||
removeLineageHandler: jest.fn(),
|
||||
entityLineageHandler: jest.fn(),
|
||||
tableQueries: [],
|
||||
entityThread: [],
|
||||
entityThread: mockThreads,
|
||||
isentityThreadLoading: false,
|
||||
postFeedHandler: jest.fn(),
|
||||
feedCount: 0,
|
||||
@ -115,15 +155,17 @@ const DatasetDetailsProps = {
|
||||
tagUpdateHandler: jest.fn(),
|
||||
};
|
||||
jest.mock('../ManageTab/ManageTab.component', () => {
|
||||
return jest.fn().mockReturnValue(<p>ManageTab</p>);
|
||||
return jest.fn().mockReturnValue(<p data-testid="manage">ManageTab</p>);
|
||||
});
|
||||
|
||||
jest.mock('../EntityLineage/EntityLineage.component', () => {
|
||||
return jest.fn().mockReturnValue(<p>Lineage</p>);
|
||||
return jest.fn().mockReturnValue(<p data-testid="lineage">Lineage</p>);
|
||||
});
|
||||
|
||||
jest.mock('../TableProfiler/TableProfiler.component', () => {
|
||||
return jest.fn().mockReturnValue(<p>ProfilerTable</p>);
|
||||
return jest
|
||||
.fn()
|
||||
.mockReturnValue(<p data-testid="TableProfiler">TableProfiler</p>);
|
||||
});
|
||||
|
||||
jest.mock('../common/description/Description', () => {
|
||||
@ -138,12 +180,8 @@ jest.mock('../common/entityPageInfo/EntityPageInfo', () => {
|
||||
return jest.fn().mockReturnValue(<p>EntityPageInfo</p>);
|
||||
});
|
||||
|
||||
jest.mock('../common/TabsPane/TabsPane', () => {
|
||||
return jest.fn().mockReturnValue(<p>TabsPane</p>);
|
||||
});
|
||||
|
||||
jest.mock('../ActivityFeed/ActivityFeedList/ActivityFeedList.tsx', () => {
|
||||
return jest.fn().mockReturnValue(<p>FeedCards</p>);
|
||||
return jest.fn().mockReturnValue(<p>ActivityFeedList</p>);
|
||||
});
|
||||
|
||||
jest.mock('../ActivityFeed/ActivityThreadPanel/ActivityThreadPanel.tsx', () => {
|
||||
@ -155,9 +193,9 @@ jest.mock('../ActivityFeed/ActivityFeedEditor/ActivityFeedEditor.tsx', () => {
|
||||
|
||||
jest.mock('../../utils/CommonUtils', () => ({
|
||||
addToRecentViewed: jest.fn(),
|
||||
getCountBadge: jest.fn(),
|
||||
getCurrentUserId: jest.fn().mockReturnValue('CurrentUserId'),
|
||||
getPartialNameFromFQN: jest.fn().mockReturnValue('PartialNameFromFQN'),
|
||||
// getTableFQNFromColumnFQN: jest.fn().mockReturnValue('TableFQNFromColumnFQN'),
|
||||
getUserTeams: () => mockUserTeam,
|
||||
}));
|
||||
|
||||
@ -169,10 +207,123 @@ describe('Test MyDataDetailsPage page', () => {
|
||||
|
||||
const relatedTables = getByTestId(container, 'related-tables-container');
|
||||
const EntityPageInfo = await findByText(container, /EntityPageInfo/i);
|
||||
const TabsPane = await findByText(container, /TabsPane/i);
|
||||
const description = await findByText(container, /Description/i);
|
||||
const tabs = await findByTestId(container, 'tabs');
|
||||
const schemaTab = await findByTestId(tabs, 'Schema');
|
||||
const activityFeedTab = await findByTestId(tabs, 'Activity Feed');
|
||||
const sampleDataTab = await findByTestId(tabs, 'Sample Data');
|
||||
const queriesTab = await findByTestId(tabs, 'Queries');
|
||||
const profilerTab = await findByTestId(tabs, 'Profiler');
|
||||
const dataQualityTab = await findByTestId(tabs, 'Data Quality');
|
||||
const lineageTab = await findByTestId(tabs, 'Lineage');
|
||||
const manageTab = await findByTestId(tabs, 'Manage');
|
||||
const dbtTab = queryByTestId(tabs, 'DBT');
|
||||
|
||||
expect(relatedTables).toBeInTheDocument();
|
||||
expect(EntityPageInfo).toBeInTheDocument();
|
||||
expect(TabsPane).toBeInTheDocument();
|
||||
expect(description).toBeInTheDocument();
|
||||
expect(tabs).toBeInTheDocument();
|
||||
expect(schemaTab).toBeInTheDocument();
|
||||
expect(activityFeedTab).toBeInTheDocument();
|
||||
expect(sampleDataTab).toBeInTheDocument();
|
||||
expect(queriesTab).toBeInTheDocument();
|
||||
expect(profilerTab).toBeInTheDocument();
|
||||
expect(dataQualityTab).toBeInTheDocument();
|
||||
expect(lineageTab).toBeInTheDocument();
|
||||
expect(manageTab).toBeInTheDocument();
|
||||
expect(dbtTab).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if active tab is schema', async () => {
|
||||
const { container } = render(<DatasetDetails {...DatasetDetailsProps} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
const schema = await findByText(container, /SchemaTab/i);
|
||||
|
||||
expect(schema).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if active tab is activity feed', async () => {
|
||||
const { container } = render(
|
||||
<DatasetDetails {...DatasetDetailsProps} activeTab={2} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
const activityFeedList = await findByText(container, /ActivityFeedList/i);
|
||||
|
||||
expect(activityFeedList).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if active tab is sample data', async () => {
|
||||
const { container } = render(
|
||||
<DatasetDetails {...DatasetDetailsProps} activeTab={3} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
const sampleData = await findByTestId(container, 'sample-data');
|
||||
|
||||
expect(sampleData).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if active tab is queries', async () => {
|
||||
const { container } = render(
|
||||
<DatasetDetails {...DatasetDetailsProps} activeTab={4} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
const tableQueries = await findByTestId(container, 'table-queries');
|
||||
|
||||
expect(tableQueries).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if active tab is profiler', async () => {
|
||||
const { container } = render(
|
||||
<DatasetDetails {...DatasetDetailsProps} activeTab={5} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
const tableProfiler = await findByTestId(container, 'TableProfiler');
|
||||
|
||||
expect(tableProfiler).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if active tab is data quality', async () => {
|
||||
const { container } = render(
|
||||
<DatasetDetails {...DatasetDetailsProps} activeTab={6} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
const dataQuality = await findByTestId(container, 'data-quality-tab');
|
||||
|
||||
expect(dataQuality).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if active tab is lineage', async () => {
|
||||
const { container } = render(
|
||||
<DatasetDetails {...DatasetDetailsProps} activeTab={7} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
const lineage = await findByTestId(container, 'lineage');
|
||||
|
||||
expect(lineage).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if active tab is manage', async () => {
|
||||
const { container } = render(
|
||||
<DatasetDetails {...DatasetDetailsProps} activeTab={9} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
const manage = await findByTestId(container, 'manage');
|
||||
|
||||
expect(manage).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@ -61,7 +61,7 @@ import TagsContainer from '../tags-container/tags-container';
|
||||
import TagsViewer from '../tags-viewer/tags-viewer';
|
||||
import Tags from '../tags/tags';
|
||||
|
||||
type Props = {
|
||||
interface Props {
|
||||
owner: Table['owner'];
|
||||
tableColumns: ModifiedTableColumn[];
|
||||
joins: Array<ColumnJoins>;
|
||||
@ -74,7 +74,7 @@ type Props = {
|
||||
onUpdate?: (columns: ModifiedTableColumn[]) => void;
|
||||
onThreadLinkSelect?: (value: string) => void;
|
||||
onEntityFieldSelect?: (value: string) => void;
|
||||
};
|
||||
}
|
||||
|
||||
const EntityTable = ({
|
||||
tableColumns,
|
||||
@ -341,8 +341,11 @@ const EntityTable = ({
|
||||
|
||||
return (
|
||||
<div className="tw-table-responsive" id="schemaTable">
|
||||
<table className="tw-w-full" {...getTableProps()}>
|
||||
<thead>
|
||||
<table
|
||||
className="tw-w-full"
|
||||
{...getTableProps()}
|
||||
data-testid="entity-table">
|
||||
<thead data-testid="table-header">
|
||||
{/* eslint-disable-next-line */}
|
||||
{headerGroups.map((headerGroup: any, index: number) => (
|
||||
<tr
|
||||
@ -356,6 +359,7 @@ const EntityTable = ({
|
||||
'tw-w-60':
|
||||
column.id === 'tags' || column.id === 'columnTests',
|
||||
})}
|
||||
data-testid={column.id}
|
||||
key={index}
|
||||
{...column.getHeaderProps()}>
|
||||
{column.render('Header')}
|
||||
@ -365,7 +369,7 @@ const EntityTable = ({
|
||||
))}
|
||||
</thead>
|
||||
|
||||
<tbody {...getTableBodyProps()}>
|
||||
<tbody {...getTableBodyProps()} data-testid="table-body">
|
||||
{/* eslint-disable-next-line */}
|
||||
{rows.map((row: any, index: number) => {
|
||||
prepareRow(row);
|
||||
@ -373,6 +377,7 @@ const EntityTable = ({
|
||||
return (
|
||||
<tr
|
||||
className={classNames('tableBody-row')}
|
||||
data-testid="row"
|
||||
key={index}
|
||||
{...row.getRowProps()}>
|
||||
{/* eslint-disable-next-line */}
|
||||
|
||||
@ -0,0 +1,309 @@
|
||||
/*
|
||||
* Copyright 2021 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 {
|
||||
findAllByTestId,
|
||||
findByTestId,
|
||||
fireEvent,
|
||||
queryByTestId,
|
||||
render,
|
||||
} from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { Table } from '../../generated/entity/data/table';
|
||||
import { ModifiedTableColumn } from '../../interface/dataQuality.interface';
|
||||
import EntityTable from './EntityTable.component';
|
||||
|
||||
const mockTableheader = [
|
||||
{
|
||||
Header: 'Name',
|
||||
accessor: 'name',
|
||||
},
|
||||
{
|
||||
Header: 'Type',
|
||||
accessor: 'dataTypeDisplay',
|
||||
},
|
||||
{
|
||||
Header: 'Data Quality',
|
||||
accessor: 'columnTests',
|
||||
},
|
||||
{
|
||||
Header: 'Description',
|
||||
accessor: 'description',
|
||||
},
|
||||
{
|
||||
Header: 'Tags',
|
||||
accessor: 'tags',
|
||||
},
|
||||
];
|
||||
|
||||
const mockEntityFieldThreads = [
|
||||
{
|
||||
entityLink:
|
||||
'<#E/table/bigquery_gcp.shopify.raw_product_catalog/columns/products/description>',
|
||||
count: 1,
|
||||
entityField: 'columns/products/description',
|
||||
},
|
||||
];
|
||||
|
||||
const onEntityFieldSelect = jest.fn();
|
||||
const onThreadLinkSelect = jest.fn();
|
||||
|
||||
const mockEntityTableProp = {
|
||||
tableColumns: [
|
||||
{
|
||||
name: 'comments',
|
||||
dataType: 'STRING',
|
||||
dataLength: 1,
|
||||
dataTypeDisplay: 'string',
|
||||
fullyQualifiedName: 'bigquery_gcp.shopify.raw_product_catalog.comments',
|
||||
tags: [],
|
||||
constraint: 'NULL',
|
||||
ordinalPosition: 1,
|
||||
},
|
||||
{
|
||||
name: 'products',
|
||||
dataType: 'ARRAY',
|
||||
arrayDataType: 'STRUCT',
|
||||
dataLength: 1,
|
||||
dataTypeDisplay:
|
||||
'array<struct<product_id:character varying(24),price:int,onsale:boolean,tax:int,weight:int,others:int,vendor:character varying(64), stock:int>>',
|
||||
fullyQualifiedName: 'bigquery_gcp.shopify.raw_product_catalog.products',
|
||||
tags: [],
|
||||
constraint: 'NULL',
|
||||
ordinalPosition: 2,
|
||||
},
|
||||
{
|
||||
name: 'platform',
|
||||
dataType: 'STRING',
|
||||
dataLength: 1,
|
||||
dataTypeDisplay: 'string',
|
||||
fullyQualifiedName: 'bigquery_gcp.shopify.raw_product_catalog.platform',
|
||||
tags: [],
|
||||
constraint: 'NULL',
|
||||
ordinalPosition: 3,
|
||||
},
|
||||
{
|
||||
name: 'store_address',
|
||||
dataType: 'ARRAY',
|
||||
arrayDataType: 'STRUCT',
|
||||
dataLength: 1,
|
||||
dataTypeDisplay:
|
||||
'array<struct<name:character varying(32),street_address:character varying(128),city:character varying(32),postcode:character varying(8)>>',
|
||||
fullyQualifiedName:
|
||||
'bigquery_gcp.shopify.raw_product_catalog.store_address',
|
||||
tags: [],
|
||||
constraint: 'NULL',
|
||||
ordinalPosition: 4,
|
||||
},
|
||||
{
|
||||
name: 'first_order_date',
|
||||
dataType: 'TIMESTAMP',
|
||||
dataTypeDisplay: 'timestamp',
|
||||
description:
|
||||
'The date (ISO 8601) and time (UTC) when the customer placed their first order. The format is YYYY-MM-DD HH:mm:ss (for example, 2016-02-05 17:04:01).',
|
||||
fullyQualifiedName:
|
||||
'bigquery_gcp.shopify.raw_product_catalog.first_order_date',
|
||||
tags: [],
|
||||
ordinalPosition: 5,
|
||||
},
|
||||
{
|
||||
name: 'last_order_date',
|
||||
dataType: 'TIMESTAMP',
|
||||
dataTypeDisplay: 'timestamp',
|
||||
description:
|
||||
'The date (ISO 8601) and time (UTC) when the customer placed their most recent order. The format is YYYY-MM-DD HH:mm:ss (for example, 2016-02-05 17:04:01).',
|
||||
fullyQualifiedName:
|
||||
'bigquery_gcp.shopify.raw_product_catalog.last_order_date',
|
||||
tags: [],
|
||||
ordinalPosition: 6,
|
||||
},
|
||||
] as ModifiedTableColumn[],
|
||||
searchText: '',
|
||||
hasEditAccess: false,
|
||||
joins: [],
|
||||
entityFieldThreads: [],
|
||||
isReadOnly: false,
|
||||
entityFqn: 'bigquery_gcp.shopify.raw_product_catalog',
|
||||
owner: {} as Table['owner'],
|
||||
columnName: '',
|
||||
onEntityFieldSelect,
|
||||
onThreadLinkSelect,
|
||||
};
|
||||
|
||||
jest.mock('@fortawesome/react-fontawesome', () => ({
|
||||
FontAwesomeIcon: jest.fn().mockReturnValue(<i>Icon</i>),
|
||||
}));
|
||||
|
||||
jest.mock('../common/non-admin-action/NonAdminAction', () => {
|
||||
return jest.fn().mockReturnValue(<p>NonAdminAction</p>);
|
||||
});
|
||||
|
||||
jest.mock('../common/rich-text-editor/RichTextEditorPreviewer', () => {
|
||||
return jest.fn().mockReturnValue(<p>RichTextEditorPreviewer</p>);
|
||||
});
|
||||
jest.mock('../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor', () => ({
|
||||
ModalWithMarkdownEditor: jest.fn().mockReturnValue(<p>EditorModal</p>),
|
||||
}));
|
||||
jest.mock('../tags-container/tags-container', () => {
|
||||
return jest.fn().mockReturnValue(<p>TagContainer</p>);
|
||||
});
|
||||
jest.mock('../tags-viewer/tags-viewer', () => {
|
||||
return jest.fn().mockReturnValue(<p>TagViewer</p>);
|
||||
});
|
||||
jest.mock('../tags/tags', () => {
|
||||
return jest.fn().mockReturnValue(<p>Tag</p>);
|
||||
});
|
||||
|
||||
describe('Test EntityTable Component', () => {
|
||||
it('Check if it has all child elements', async () => {
|
||||
const { container } = render(<EntityTable {...mockEntityTableProp} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
|
||||
const entityTable = await findByTestId(container, 'entity-table');
|
||||
|
||||
expect(entityTable).toBeInTheDocument();
|
||||
|
||||
const tableHeader = await findByTestId(container, 'table-header');
|
||||
|
||||
expect(tableHeader).toBeInTheDocument();
|
||||
|
||||
for (let index = 0; index < mockTableheader.length; index++) {
|
||||
const headerValue = mockTableheader[index];
|
||||
|
||||
const header = await findByTestId(tableHeader, `${headerValue.accessor}`);
|
||||
|
||||
expect(header).toBeInTheDocument();
|
||||
}
|
||||
|
||||
const tableBody = await findByTestId(container, 'table-body');
|
||||
|
||||
expect(tableBody).toBeInTheDocument();
|
||||
|
||||
const tableRows = await findAllByTestId(tableBody, 'row');
|
||||
|
||||
expect(tableRows).toHaveLength(mockEntityTableProp.tableColumns.length);
|
||||
});
|
||||
|
||||
it('should render request description button', async () => {
|
||||
const { container } = render(<EntityTable {...mockEntityTableProp} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
|
||||
const entityTable = await findByTestId(container, 'entity-table');
|
||||
|
||||
expect(entityTable).toBeInTheDocument();
|
||||
|
||||
const tableBody = await findByTestId(container, 'table-body');
|
||||
|
||||
expect(tableBody).toBeInTheDocument();
|
||||
|
||||
const tableRows = await findAllByTestId(tableBody, 'row');
|
||||
|
||||
const requestDescriptionButton = await findByTestId(
|
||||
tableRows[0],
|
||||
'request-description'
|
||||
);
|
||||
|
||||
expect(requestDescriptionButton).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(
|
||||
requestDescriptionButton,
|
||||
new MouseEvent('click', { bubbles: true, cancelable: true })
|
||||
);
|
||||
|
||||
expect(onEntityFieldSelect).toBeCalled();
|
||||
|
||||
const descriptionThread = queryByTestId(tableRows[0], 'field-thread');
|
||||
const startDescriptionThread = queryByTestId(
|
||||
tableRows[0],
|
||||
'start-field-thread'
|
||||
);
|
||||
|
||||
// should not be in the document, as request description button is present
|
||||
expect(descriptionThread).not.toBeInTheDocument();
|
||||
expect(startDescriptionThread).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should render start thread button', async () => {
|
||||
const { container } = render(<EntityTable {...mockEntityTableProp} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
|
||||
const entityTable = await findByTestId(container, 'entity-table');
|
||||
|
||||
expect(entityTable).toBeInTheDocument();
|
||||
|
||||
const tableBody = await findByTestId(container, 'table-body');
|
||||
|
||||
expect(tableBody).toBeInTheDocument();
|
||||
|
||||
const tableRows = await findAllByTestId(tableBody, 'row');
|
||||
|
||||
const startThreadButton = await findByTestId(
|
||||
tableRows[4],
|
||||
'start-field-thread'
|
||||
);
|
||||
|
||||
expect(startThreadButton).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(
|
||||
startThreadButton,
|
||||
new MouseEvent('click', { bubbles: true, cancelable: true })
|
||||
);
|
||||
|
||||
expect(onThreadLinkSelect).toBeCalled();
|
||||
});
|
||||
|
||||
it('Should render thread button with count', async () => {
|
||||
const { container } = render(
|
||||
<EntityTable
|
||||
{...mockEntityTableProp}
|
||||
entityFieldThreads={mockEntityFieldThreads}
|
||||
/>,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
|
||||
const entityTable = await findByTestId(container, 'entity-table');
|
||||
|
||||
expect(entityTable).toBeInTheDocument();
|
||||
|
||||
const tableBody = await findByTestId(container, 'table-body');
|
||||
|
||||
expect(tableBody).toBeInTheDocument();
|
||||
|
||||
const tableRows = await findAllByTestId(tableBody, 'row');
|
||||
|
||||
const threadButton = await findByTestId(tableRows[1], 'field-thread');
|
||||
|
||||
expect(threadButton).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(
|
||||
threadButton,
|
||||
new MouseEvent('click', { bubbles: true, cancelable: true })
|
||||
);
|
||||
|
||||
expect(onThreadLinkSelect).toBeCalled();
|
||||
|
||||
const threadCount = await findByTestId(threadButton, 'field-thread-count');
|
||||
|
||||
expect(threadCount).toBeInTheDocument();
|
||||
|
||||
expect(threadCount).toHaveTextContent(
|
||||
String(mockEntityFieldThreads[0].count)
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -11,6 +11,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
faChevronLeft,
|
||||
faChevronRight,
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import classNames from 'classnames';
|
||||
import { lowerCase } from 'lodash';
|
||||
import React, {
|
||||
@ -23,11 +28,6 @@ import React, {
|
||||
import { TableData } from '../../generated/entity/data/table';
|
||||
import { withLoader } from '../../hoc/withLoader';
|
||||
import { isEven } from '../../utils/CommonUtils';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import {
|
||||
faChevronLeft,
|
||||
faChevronRight,
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
export type SampleColumns = { name: string; dataType: string };
|
||||
|
||||
@ -70,6 +70,7 @@ const SampleDataTable: FunctionComponent<Props> = ({ sampleData }: Props) => {
|
||||
return (
|
||||
<div
|
||||
className="tw-relative tw-flex tw-justify-between"
|
||||
data-testid="sample-data"
|
||||
onScrollCapture={() => {
|
||||
setScrollOffSet(tableRef.current?.scrollLeft ?? 0);
|
||||
}}>
|
||||
|
||||
@ -23,7 +23,7 @@ interface TableQueriesProp extends HTMLAttributes<HTMLDivElement> {
|
||||
|
||||
const TableQueries: FC<TableQueriesProp> = ({ queries, className }) => {
|
||||
return (
|
||||
<div className={className}>
|
||||
<div className={className} data-testid="table-queries">
|
||||
<div className="tw-my-6" data-testid="queries-container">
|
||||
{!isUndefined(queries) && queries.length > 0 ? (
|
||||
queries.map((query, index) => <QueryCard key={index} query={query} />)
|
||||
|
||||
@ -53,6 +53,7 @@ const TabsPane = ({
|
||||
<div className={classNames('tw-bg-transparent tw--mx-6', className)}>
|
||||
<nav
|
||||
className="tw-flex tw-items-center tw-justify-between tw-gh-tabs-container tw-px-7"
|
||||
data-testid="tabs"
|
||||
id="tabs">
|
||||
<div className="tw-flex tw-flex-grow">
|
||||
{tabs.map((tab) =>
|
||||
@ -64,7 +65,7 @@ const TabsPane = ({
|
||||
title={TITLE_FOR_NON_OWNER_ACTION}>
|
||||
<button
|
||||
className={getTabClasses(tab.position, activeTab)}
|
||||
data-testid="tab"
|
||||
data-testid={tab.name}
|
||||
id={camelCase(tab.name)}
|
||||
onClick={() => setActiveTab?.(tab.position)}>
|
||||
{tab.name}
|
||||
@ -73,7 +74,7 @@ const TabsPane = ({
|
||||
) : (
|
||||
<button
|
||||
className={getTabClasses(tab.position, activeTab)}
|
||||
data-testid="tab"
|
||||
data-testid={tab.name}
|
||||
id={camelCase(tab.name)}
|
||||
key={tab.position}
|
||||
onClick={() => setActiveTab?.(tab.position)}>
|
||||
|
||||
@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright 2021 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 { findByTestId, queryByTestId, render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import Description from './Description';
|
||||
|
||||
const mockEntityFieldThreads = [
|
||||
{
|
||||
entityLink:
|
||||
'<#E/table/bigquery_gcp.shopify.raw_product_catalog/description>',
|
||||
count: 1,
|
||||
entityField: 'description',
|
||||
},
|
||||
];
|
||||
|
||||
const mockDescriptionProp = {
|
||||
description: 'description',
|
||||
isEdit: false,
|
||||
isReadOnly: false,
|
||||
blurWithBodyBG: false,
|
||||
removeBlur: false,
|
||||
entityName: 'entity1',
|
||||
entityFieldThreads: [],
|
||||
entityType: 'xyz',
|
||||
entityFqn: 'x.y.z',
|
||||
onCancel: jest.fn(),
|
||||
onDescriptionUpdate: jest.fn(),
|
||||
onThreadLinkSelect: jest.fn(),
|
||||
onEntityFieldSelect: jest.fn(),
|
||||
};
|
||||
|
||||
jest.mock('../../../utils/CommonUtils', () => ({
|
||||
getHtmlForNonAdminAction: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../../utils/EntityUtils', () => ({
|
||||
getEntityFeedLink: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock(
|
||||
'../../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor',
|
||||
() => ({
|
||||
ModalWithMarkdownEditor: jest
|
||||
.fn()
|
||||
.mockReturnValue(
|
||||
<p data-testid="editor-modal">ModalWithMarkdownEditor</p>
|
||||
),
|
||||
})
|
||||
);
|
||||
jest.mock('../rich-text-editor/RichTextEditorPreviewer', () => {
|
||||
return jest
|
||||
.fn()
|
||||
.mockReturnValue(
|
||||
<p data-testid="rich-text-previewer">RichTextPreviewer</p>
|
||||
);
|
||||
});
|
||||
|
||||
jest.mock('../non-admin-action/NonAdminAction', () => {
|
||||
return jest
|
||||
.fn()
|
||||
.mockReturnValue(<p data-testid="edit-description">NonAdminAction</p>);
|
||||
});
|
||||
|
||||
describe('Test Description Component', () => {
|
||||
it('Check if it has all child elements', async () => {
|
||||
const { container } = render(<Description {...mockDescriptionProp} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
|
||||
const descriptionContainer = await findByTestId(container, 'description');
|
||||
const editDescriptionButton = await findByTestId(
|
||||
container,
|
||||
'edit-description'
|
||||
);
|
||||
|
||||
expect(descriptionContainer).toBeInTheDocument();
|
||||
expect(editDescriptionButton).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if it has isReadOnly as true', async () => {
|
||||
const { container } = render(
|
||||
<Description {...mockDescriptionProp} isReadOnly />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
|
||||
const descriptionContainer = await findByTestId(container, 'description');
|
||||
const editDescriptionButton = queryByTestId(container, 'edit-description');
|
||||
|
||||
expect(descriptionContainer).toBeInTheDocument();
|
||||
expect(editDescriptionButton).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if it has isEdit as true', async () => {
|
||||
const { container } = render(
|
||||
<Description {...mockDescriptionProp} isEdit />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
|
||||
const descriptionContainer = await findByTestId(container, 'description');
|
||||
const editorModal = await findByTestId(container, 'editor-modal');
|
||||
|
||||
expect(descriptionContainer).toBeInTheDocument();
|
||||
expect(editorModal).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if it has isEdit as false', async () => {
|
||||
const { container } = render(
|
||||
<Description {...mockDescriptionProp} isEdit={false} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
|
||||
const descriptionContainer = await findByTestId(container, 'description');
|
||||
const editorModal = queryByTestId(container, 'editor-modal');
|
||||
|
||||
expect(descriptionContainer).toBeInTheDocument();
|
||||
expect(editorModal).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if it has entityFieldThreads', async () => {
|
||||
const { container } = render(
|
||||
<Description
|
||||
{...mockDescriptionProp}
|
||||
entityFieldThreads={mockEntityFieldThreads}
|
||||
/>,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
|
||||
const descriptionContainer = await findByTestId(container, 'description');
|
||||
const descriptionThread = await findByTestId(
|
||||
container,
|
||||
'description-thread'
|
||||
);
|
||||
const descriptionThreadCount = await findByTestId(
|
||||
descriptionThread,
|
||||
'description-thread-count'
|
||||
);
|
||||
|
||||
expect(descriptionContainer).toBeInTheDocument();
|
||||
|
||||
expect(descriptionThread).toBeInTheDocument();
|
||||
expect(descriptionThreadCount).toBeInTheDocument();
|
||||
// check for thread count
|
||||
expect(descriptionThreadCount).toHaveTextContent(
|
||||
String(mockEntityFieldThreads[0].count)
|
||||
);
|
||||
});
|
||||
|
||||
it('Check if it has entityFieldThreads as empty list', async () => {
|
||||
const { container } = render(
|
||||
<Description {...mockDescriptionProp} entityFieldThreads={[]} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
|
||||
const descriptionContainer = await findByTestId(container, 'description');
|
||||
const descriptionThread = queryByTestId(container, 'description-thread');
|
||||
const startDescriptionThread = await findByTestId(
|
||||
container,
|
||||
'start-description-thread'
|
||||
);
|
||||
|
||||
expect(descriptionContainer).toBeInTheDocument();
|
||||
expect(descriptionThread).not.toBeInTheDocument();
|
||||
// should render startDescription thread button, as description thread is empty value
|
||||
expect(startDescriptionThread).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if it has entityFieldThreads as empty list, description as empty string', async () => {
|
||||
const { container } = render(
|
||||
<Description
|
||||
{...mockDescriptionProp}
|
||||
description=""
|
||||
entityFieldThreads={[]}
|
||||
/>,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
|
||||
const descriptionContainer = await findByTestId(container, 'description');
|
||||
const descriptionThread = queryByTestId(container, 'description-thread');
|
||||
const startDescriptionThread = queryByTestId(
|
||||
container,
|
||||
'start-description-thread'
|
||||
);
|
||||
|
||||
const requestDescription = await findByTestId(
|
||||
container,
|
||||
'request-description'
|
||||
);
|
||||
|
||||
expect(descriptionContainer).toBeInTheDocument();
|
||||
expect(descriptionThread).not.toBeInTheDocument();
|
||||
expect(startDescriptionThread).not.toBeInTheDocument();
|
||||
|
||||
// should render requestDescription, as description thread and description are empty value
|
||||
expect(requestDescription).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@ -25,7 +25,7 @@ import NonAdminAction from '../non-admin-action/NonAdminAction';
|
||||
import PopOver from '../popover/PopOver';
|
||||
import RichTextEditorPreviewer from '../rich-text-editor/RichTextEditorPreviewer';
|
||||
|
||||
type Props = {
|
||||
interface Props {
|
||||
entityName?: string;
|
||||
owner?: Table['owner'];
|
||||
hasEditAccess?: boolean;
|
||||
@ -43,7 +43,7 @@ type Props = {
|
||||
onDescriptionUpdate?: (value: string) => void;
|
||||
onSuggest?: (value: string) => void;
|
||||
onEntityFieldSelect?: (value: string) => void;
|
||||
};
|
||||
}
|
||||
|
||||
const Description = ({
|
||||
owner,
|
||||
@ -143,12 +143,18 @@ const Description = ({
|
||||
{!isUndefined(descriptionThread) ? (
|
||||
<p
|
||||
className="link-text tw-ml-2 tw-w-8 tw-h-8 tw-flex-none"
|
||||
data-testid="description-thread"
|
||||
onClick={() =>
|
||||
onThreadLinkSelect?.(descriptionThread.entityLink)
|
||||
}>
|
||||
<span className="tw-flex">
|
||||
<SVGIcons alt="comments" icon={Icons.COMMENT} width="20px" />{' '}
|
||||
<span className="tw-ml-1"> {descriptionThread.count}</span>
|
||||
<span
|
||||
className="tw-ml-1"
|
||||
data-testid="description-thread-count">
|
||||
{' '}
|
||||
{descriptionThread.count}
|
||||
</span>
|
||||
</span>
|
||||
</p>
|
||||
) : (
|
||||
@ -156,6 +162,7 @@ const Description = ({
|
||||
{description?.trim() && onThreadLinkSelect ? (
|
||||
<p
|
||||
className="link-text tw-flex-none tw-ml-2"
|
||||
data-testid="start-description-thread"
|
||||
onClick={() =>
|
||||
onThreadLinkSelect?.(
|
||||
getEntityFeedLink(entityType, entityFqn, 'description')
|
||||
|
||||
@ -0,0 +1,434 @@
|
||||
/*
|
||||
* Copyright 2021 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 {
|
||||
findByTestId,
|
||||
findByText,
|
||||
fireEvent,
|
||||
queryByTestId,
|
||||
render,
|
||||
} from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { TagLabel } from '../../../generated/type/tagLabel';
|
||||
import EntityPageInfo from './EntityPageInfo';
|
||||
|
||||
const mockEntityFieldThreads = [
|
||||
{
|
||||
entityLink: '<#E/table/bigquery_gcp.shopify.raw_product_catalog/tags>',
|
||||
count: 1,
|
||||
entityField: 'tags',
|
||||
},
|
||||
];
|
||||
|
||||
const followHandler = jest.fn();
|
||||
const versionHandler = jest.fn();
|
||||
const onThreadLinkSelect = jest.fn();
|
||||
const mockTier = {
|
||||
tagFQN: 'Tier.Tier1',
|
||||
description: '',
|
||||
source: 'Tag',
|
||||
labelType: 'Manual',
|
||||
state: 'Confirmed',
|
||||
};
|
||||
|
||||
const mockInfoTags = [
|
||||
{
|
||||
tagFQN: 'User.Biometric',
|
||||
source: 'Tag',
|
||||
labelType: 'Manual',
|
||||
state: 'Confirmed',
|
||||
},
|
||||
];
|
||||
|
||||
const mockEntityInfoProp = {
|
||||
titleLinks: [
|
||||
{
|
||||
name: 'bigquery_gcp',
|
||||
url: '/service/databaseServices/bigquery_gcp',
|
||||
imgSrc: '/service-icon-query.png',
|
||||
},
|
||||
{
|
||||
name: 'shopify',
|
||||
url: '/database/bigquery_gcp.shopify',
|
||||
},
|
||||
{
|
||||
name: 'raw_product_catalog',
|
||||
url: '',
|
||||
activeTitle: true,
|
||||
},
|
||||
],
|
||||
hasEditAccess: false,
|
||||
isFollowing: false,
|
||||
isTagEditable: false,
|
||||
isVersionSelected: undefined,
|
||||
deleted: false,
|
||||
followHandler,
|
||||
followers: 0,
|
||||
extraInfo: [
|
||||
{
|
||||
key: 'Owner',
|
||||
value: '',
|
||||
placeholderText: '',
|
||||
isLink: false,
|
||||
openInNewTab: false,
|
||||
},
|
||||
{
|
||||
key: 'Tier',
|
||||
value: '',
|
||||
},
|
||||
{
|
||||
value: 'Usage - 0th pctile',
|
||||
},
|
||||
{
|
||||
value: '0 queries',
|
||||
},
|
||||
{
|
||||
key: 'Columns',
|
||||
value: '6 columns',
|
||||
},
|
||||
],
|
||||
tier: {} as TagLabel,
|
||||
tags: mockInfoTags,
|
||||
owner: undefined,
|
||||
tagsHandler: jest.fn(),
|
||||
followersList: [],
|
||||
entityFqn: 'bigquery_gcp.shopify.raw_product_catalog',
|
||||
entityName: 'raw_product_catalog',
|
||||
entityType: 'table',
|
||||
version: '0.3',
|
||||
versionHandler,
|
||||
entityFieldThreads: [],
|
||||
onThreadLinkSelect,
|
||||
};
|
||||
|
||||
jest.mock('../../../utils/CommonUtils', () => ({
|
||||
getHtmlForNonAdminAction: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../../utils/EntityUtils', () => ({
|
||||
getEntityFeedLink: jest.fn(),
|
||||
getInfoElements: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../../utils/GlossaryUtils', () => ({
|
||||
fetchGlossaryTerms: jest.fn(),
|
||||
getGlossaryTermlist: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../../utils/TableUtils', () => ({
|
||||
getFollowerDetail: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../../utils/TagsUtils', () => ({
|
||||
getTagCategories: jest.fn(),
|
||||
getTaglist: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../non-admin-action/NonAdminAction', () => {
|
||||
return jest
|
||||
.fn()
|
||||
.mockReturnValue(<p data-testid="tag-action">NonAdminAction</p>);
|
||||
});
|
||||
|
||||
jest.mock('../../tags-container/tags-container', () => {
|
||||
return jest.fn().mockReturnValue(<p>TagContainer</p>);
|
||||
});
|
||||
|
||||
jest.mock('../../tags-viewer/tags-viewer', () => {
|
||||
return jest.fn().mockReturnValue(<p data-testid="info-tags">TagViewer</p>);
|
||||
});
|
||||
|
||||
jest.mock('../../tags/tags', () => {
|
||||
return jest.fn().mockReturnValue(<p data-testid="tier-tag">Tag</p>);
|
||||
});
|
||||
|
||||
jest.mock('../avatar/Avatar', () => {
|
||||
return jest.fn().mockReturnValue(<p>Avatar</p>);
|
||||
});
|
||||
|
||||
jest.mock('./FollowersModal', () => {
|
||||
return jest.fn().mockReturnValue(<p>FollowModal</p>);
|
||||
});
|
||||
|
||||
jest.mock('../title-breadcrumb/title-breadcrumb.component', () => {
|
||||
return jest.fn().mockReturnValue(<p>TitleBreadCrumb</p>);
|
||||
});
|
||||
|
||||
describe('Test EntityPageInfo component', () => {
|
||||
it('Check if it has all child elements', async () => {
|
||||
const { container } = render(<EntityPageInfo {...mockEntityInfoProp} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
|
||||
const entityPageInfoContainer = await findByTestId(
|
||||
container,
|
||||
'entity-page-info'
|
||||
);
|
||||
|
||||
expect(entityPageInfoContainer).toBeInTheDocument();
|
||||
|
||||
const titleBreadCrumb = await findByText(
|
||||
entityPageInfoContainer,
|
||||
/TitleBreadCrumb/i
|
||||
);
|
||||
|
||||
expect(titleBreadCrumb).toBeInTheDocument();
|
||||
|
||||
const versionButton = await findByTestId(
|
||||
entityPageInfoContainer,
|
||||
'version-button'
|
||||
);
|
||||
|
||||
expect(versionButton).toBeInTheDocument();
|
||||
|
||||
const versionValue = await findByTestId(
|
||||
entityPageInfoContainer,
|
||||
'version-value'
|
||||
);
|
||||
|
||||
expect(versionValue).toBeInTheDocument();
|
||||
expect(versionValue).toHaveTextContent(mockEntityInfoProp.version);
|
||||
|
||||
const deleteBadge = queryByTestId(entityPageInfoContainer, 'deleted-badge');
|
||||
|
||||
expect(deleteBadge).not.toBeInTheDocument();
|
||||
|
||||
const followButton = await findByTestId(
|
||||
entityPageInfoContainer,
|
||||
'follow-button'
|
||||
);
|
||||
|
||||
expect(followButton).toBeInTheDocument();
|
||||
|
||||
const followerValue = await findByTestId(
|
||||
entityPageInfoContainer,
|
||||
'follower-value'
|
||||
);
|
||||
|
||||
expect(followerValue).toBeInTheDocument();
|
||||
expect(followerValue).toHaveTextContent(
|
||||
String(mockEntityInfoProp.followers)
|
||||
);
|
||||
|
||||
const extraInfo = await findByTestId(entityPageInfoContainer, 'extrainfo');
|
||||
|
||||
expect(extraInfo).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should call version handler on version button click', async () => {
|
||||
const { container } = render(<EntityPageInfo {...mockEntityInfoProp} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
const entityPageInfoContainer = await findByTestId(
|
||||
container,
|
||||
'entity-page-info'
|
||||
);
|
||||
|
||||
expect(entityPageInfoContainer).toBeInTheDocument();
|
||||
|
||||
const versionButton = await findByTestId(
|
||||
entityPageInfoContainer,
|
||||
'version-button'
|
||||
);
|
||||
|
||||
expect(versionButton).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(
|
||||
versionButton,
|
||||
new MouseEvent('click', { bubbles: true, cancelable: true })
|
||||
);
|
||||
|
||||
expect(versionHandler).toBeCalled();
|
||||
});
|
||||
|
||||
it('Should call follow handler on follow button click', async () => {
|
||||
const { container } = render(<EntityPageInfo {...mockEntityInfoProp} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
|
||||
const entityPageInfoContainer = await findByTestId(
|
||||
container,
|
||||
'entity-page-info'
|
||||
);
|
||||
|
||||
expect(entityPageInfoContainer).toBeInTheDocument();
|
||||
|
||||
const followButton = await findByTestId(
|
||||
entityPageInfoContainer,
|
||||
'follow-button'
|
||||
);
|
||||
|
||||
expect(followButton).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(
|
||||
followButton,
|
||||
new MouseEvent('click', { bubbles: true, cancelable: true })
|
||||
);
|
||||
|
||||
expect(followHandler).toBeCalled();
|
||||
});
|
||||
|
||||
it('Should render all the extra info', async () => {
|
||||
const { container } = render(<EntityPageInfo {...mockEntityInfoProp} />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
|
||||
const entityPageInfoContainer = await findByTestId(
|
||||
container,
|
||||
'entity-page-info'
|
||||
);
|
||||
|
||||
expect(entityPageInfoContainer).toBeInTheDocument();
|
||||
|
||||
const extraInfo = await findByTestId(entityPageInfoContainer, 'extrainfo');
|
||||
|
||||
expect(extraInfo).toBeInTheDocument();
|
||||
|
||||
for (let index = 0; index < mockEntityInfoProp.extraInfo.length; index++) {
|
||||
const info = mockEntityInfoProp.extraInfo[index];
|
||||
const key = await findByTestId(
|
||||
extraInfo,
|
||||
`${info.key ? info.key : `info${index}`}`
|
||||
);
|
||||
|
||||
expect(key).toBeInTheDocument();
|
||||
}
|
||||
});
|
||||
|
||||
it('Should render all the tags including tier tag', async () => {
|
||||
const { container } = render(
|
||||
<EntityPageInfo {...mockEntityInfoProp} tier={mockTier as TagLabel} />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
|
||||
const entityPageInfoContainer = await findByTestId(
|
||||
container,
|
||||
'entity-page-info'
|
||||
);
|
||||
|
||||
expect(entityPageInfoContainer).toBeInTheDocument();
|
||||
|
||||
const entityTags = await findByTestId(
|
||||
entityPageInfoContainer,
|
||||
'entity-tags'
|
||||
);
|
||||
|
||||
expect(entityTags).toBeInTheDocument();
|
||||
|
||||
const tierTag = await findByTestId(entityTags, 'tier-tag');
|
||||
|
||||
expect(tierTag).toBeInTheDocument();
|
||||
|
||||
const infoTags = await findByTestId(entityTags, 'info-tags');
|
||||
|
||||
expect(infoTags).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Check if it has isTagEditable as true and deleted as false value', async () => {
|
||||
const { container } = render(
|
||||
<EntityPageInfo {...mockEntityInfoProp} isTagEditable />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
|
||||
const entityPageInfoContainer = await findByTestId(
|
||||
container,
|
||||
'entity-page-info'
|
||||
);
|
||||
|
||||
expect(entityPageInfoContainer).toBeInTheDocument();
|
||||
|
||||
const tagAction = await findByTestId(entityPageInfoContainer, 'tag-action');
|
||||
|
||||
// should render tag action either add tag or edit tag
|
||||
expect(tagAction).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should render start thread button', async () => {
|
||||
const { container } = render(
|
||||
<EntityPageInfo {...mockEntityInfoProp} isTagEditable />,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
|
||||
const entityPageInfoContainer = await findByTestId(
|
||||
container,
|
||||
'entity-page-info'
|
||||
);
|
||||
|
||||
expect(entityPageInfoContainer).toBeInTheDocument();
|
||||
|
||||
const startThreadButton = await findByTestId(
|
||||
entityPageInfoContainer,
|
||||
'start-tag-thread'
|
||||
);
|
||||
|
||||
expect(startThreadButton).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(
|
||||
startThreadButton,
|
||||
new MouseEvent('click', { bubbles: true, cancelable: true })
|
||||
);
|
||||
|
||||
expect(onThreadLinkSelect).toBeCalled();
|
||||
});
|
||||
|
||||
it('Should render tag thread button with count', async () => {
|
||||
const { container } = render(
|
||||
<EntityPageInfo
|
||||
{...mockEntityInfoProp}
|
||||
isTagEditable
|
||||
entityFieldThreads={mockEntityFieldThreads}
|
||||
/>,
|
||||
{
|
||||
wrapper: MemoryRouter,
|
||||
}
|
||||
);
|
||||
|
||||
const entityPageInfoContainer = await findByTestId(
|
||||
container,
|
||||
'entity-page-info'
|
||||
);
|
||||
|
||||
expect(entityPageInfoContainer).toBeInTheDocument();
|
||||
|
||||
const tagThreadButton = await findByTestId(
|
||||
entityPageInfoContainer,
|
||||
'tag-thread'
|
||||
);
|
||||
|
||||
expect(tagThreadButton).toBeInTheDocument();
|
||||
|
||||
const tagThreadCount = await findByTestId(
|
||||
tagThreadButton,
|
||||
'tag-thread-count'
|
||||
);
|
||||
|
||||
expect(tagThreadCount).toBeInTheDocument();
|
||||
expect(tagThreadCount).toHaveTextContent(
|
||||
String(mockEntityFieldThreads[0].count)
|
||||
);
|
||||
|
||||
fireEvent.click(
|
||||
tagThreadButton,
|
||||
new MouseEvent('click', { bubbles: true, cancelable: true })
|
||||
);
|
||||
|
||||
expect(onThreadLinkSelect).toBeCalled();
|
||||
});
|
||||
});
|
||||
@ -47,7 +47,7 @@ import TitleBreadcrumb from '../title-breadcrumb/title-breadcrumb.component';
|
||||
import { TitleBreadcrumbProps } from '../title-breadcrumb/title-breadcrumb.interface';
|
||||
import FollowersModal from './FollowersModal';
|
||||
|
||||
type Props = {
|
||||
interface Props {
|
||||
titleLinks: TitleBreadcrumbProps['titleLinks'];
|
||||
isFollowing?: boolean;
|
||||
deleted?: boolean;
|
||||
@ -69,7 +69,7 @@ type Props = {
|
||||
followHandler?: () => void;
|
||||
tagsHandler?: (selectedTags?: Array<EntityTags>) => void;
|
||||
versionHandler?: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
const EntityPageInfo = ({
|
||||
titleLinks,
|
||||
@ -189,7 +189,10 @@ const EntityPageInfo = ({
|
||||
|
||||
const getVersionButton = (version: string) => {
|
||||
return (
|
||||
<div className="tw-flex tw-h-6 tw-ml-2 tw-mt-2" onClick={versionHandler}>
|
||||
<div
|
||||
className="tw-flex tw-h-6 tw-ml-2 tw-mt-2"
|
||||
data-testid="version"
|
||||
onClick={versionHandler}>
|
||||
<span
|
||||
className={classNames(
|
||||
'tw-flex tw-border tw-border-primary tw-rounded',
|
||||
@ -214,7 +217,7 @@ const EntityPageInfo = ({
|
||||
|
||||
<span
|
||||
className="tw-text-xs tw-border-l-0 tw-font-medium tw-py-1 tw-px-2 tw-rounded-r tw-cursor-pointer hover:tw-underline"
|
||||
data-testid="getversions">
|
||||
data-testid="version-value">
|
||||
{parseFloat(version).toFixed(1)}
|
||||
</span>
|
||||
</span>
|
||||
@ -257,14 +260,16 @@ const EntityPageInfo = ({
|
||||
}, [followersList]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div data-testid="entity-page-info">
|
||||
<div className="tw-flex tw-flex-col">
|
||||
<div className="tw-flex tw-flex-initial tw-justify-between tw-items-start">
|
||||
<div className="tw-flex tw-items-center">
|
||||
<TitleBreadcrumb titleLinks={titleLinks} />
|
||||
{deleted && (
|
||||
<>
|
||||
<div className="tw-rounded tw-bg-error-lite tw-text-error tw-font-medium tw-h-6 tw-px-2 tw-py-0.5 tw-ml-2">
|
||||
<div
|
||||
className="tw-rounded tw-bg-error-lite tw-text-error tw-font-medium tw-h-6 tw-px-2 tw-py-0.5 tw-ml-2"
|
||||
data-testid="deleted-badge">
|
||||
<FontAwesomeIcon
|
||||
className="tw-mr-1"
|
||||
icon={faExclamationCircle}
|
||||
@ -331,7 +336,7 @@ const EntityPageInfo = ({
|
||||
trigger="click">
|
||||
<span
|
||||
className="tw-text-xs tw-border-l-0 tw-font-medium tw-py-1 tw-px-2 tw-rounded-r tw-cursor-pointer hover:tw-underline"
|
||||
data-testid="getFollowerDetail">
|
||||
data-testid="follower-value">
|
||||
{followers}
|
||||
</span>
|
||||
</PopOver>
|
||||
@ -341,9 +346,14 @@ const EntityPageInfo = ({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="tw-flex tw-gap-1 tw-mb-2 tw-mt-1 tw-ml-7 tw-flex-wrap tw-items-center">
|
||||
<div
|
||||
className="tw-flex tw-gap-1 tw-mb-2 tw-mt-1 tw-ml-7 tw-flex-wrap tw-items-center"
|
||||
data-testid="extrainfo">
|
||||
{extraInfo.map((info, index) => (
|
||||
<span className="tw-flex tw-items-center" key={index}>
|
||||
<span
|
||||
className="tw-flex tw-items-center"
|
||||
data-testid={info.key || `info${index}`}
|
||||
key={index}>
|
||||
{getInfoElements(info)}
|
||||
{extraInfo.length !== 1 && index < extraInfo.length - 1 ? (
|
||||
<span className="tw-mx-1.5 tw-inline-block tw-text-gray-400">
|
||||
@ -355,7 +365,7 @@ const EntityPageInfo = ({
|
||||
</div>
|
||||
<div
|
||||
className="tw-flex tw-flex-wrap tw-pt-1 tw-ml-7 tw-group"
|
||||
data-testid="breadcrumb-tags">
|
||||
data-testid="entity-tags">
|
||||
{(!isEditable || !isTagEditable || deleted) && (
|
||||
<>
|
||||
{(tags.length > 0 || !isEmpty(tier)) && (
|
||||
@ -435,15 +445,19 @@ const EntityPageInfo = ({
|
||||
{!isUndefined(tagThread) ? (
|
||||
<p
|
||||
className="link-text tw-ml-1 tw-w-8 tw-flex-none"
|
||||
data-testid="tag-thread"
|
||||
onClick={() => onThreadLinkSelect?.(tagThread.entityLink)}>
|
||||
<span className="tw-flex">
|
||||
<SVGIcons alt="comments" icon={Icons.COMMENT} width="20px" />
|
||||
<span className="tw-ml-1">{tagThread.count}</span>
|
||||
<span className="tw-ml-1" data-testid="tag-thread-count">
|
||||
{tagThread.count}
|
||||
</span>
|
||||
</span>
|
||||
</p>
|
||||
) : (
|
||||
<p
|
||||
className="link-text tw-self-start tw-w-8 tw-opacity-0 tw-ml-1 group-hover:tw-opacity-100 tw-flex-none"
|
||||
data-testid="start-tag-thread"
|
||||
onClick={() =>
|
||||
onThreadLinkSelect?.(
|
||||
getEntityFeedLink(entityType, entityFqn, 'tags')
|
||||
|
||||
@ -41,6 +41,7 @@ export const getFieldThreadElement = (
|
||||
return !isEmpty(threadValue) ? (
|
||||
<p
|
||||
className="link-text tw-w-8 tw-h-8 tw-flex-none"
|
||||
data-testid="field-thread"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@ -48,7 +49,9 @@ export const getFieldThreadElement = (
|
||||
}}>
|
||||
<span className="tw-flex">
|
||||
<SVGIcons alt="comments" icon={Icons.COMMENT} width="20px" />
|
||||
<span className="tw-ml-1">{threadValue.count}</span>
|
||||
<span className="tw-ml-1" data-testid="field-thread-count">
|
||||
{threadValue.count}
|
||||
</span>
|
||||
</span>
|
||||
</p>
|
||||
) : (
|
||||
@ -56,6 +59,7 @@ export const getFieldThreadElement = (
|
||||
{entityType && entityFqn && entityField && flag ? (
|
||||
<p
|
||||
className="link-text tw-self-start tw-w-8 tw-h-8 tw-opacity-0 tw-ml-1 group-hover:tw-opacity-100 tw-flex-none"
|
||||
data-testid="start-field-thread"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user