mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-10-14 18:27:35 +00:00
* Fix (#9238) : Dashboard owner and tags not appearing on dashboard list * test: add unit tests
This commit is contained in:
parent
9a955036cf
commit
afa93cbba2
@ -12,17 +12,31 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
findAllByTestId,
|
||||
act,
|
||||
findByTestId,
|
||||
findByText,
|
||||
queryByText,
|
||||
queryByTestId,
|
||||
render,
|
||||
screen,
|
||||
} from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { act } from 'react-test-renderer';
|
||||
import { getCurrentServiceTab } from '../../utils/ServiceUtils';
|
||||
|
||||
let mockParams = {
|
||||
serviceFQN: 'bigquery_gcp',
|
||||
serviceType: 'BigQuery',
|
||||
serviceCategory: 'databaseServices',
|
||||
tab: 'databases',
|
||||
};
|
||||
|
||||
import ServicePage from './index';
|
||||
import { mockData, mockDatabase, mockTabs } from './mocks/servicePage.mock';
|
||||
import {
|
||||
DASHBOARD_DATA,
|
||||
mockData,
|
||||
mockDatabase,
|
||||
mockTabs,
|
||||
} from './mocks/servicePage.mock';
|
||||
|
||||
jest.mock('../../utils/PermissionsUtils', () => ({
|
||||
checkPermission: jest.fn().mockReturnValue(true),
|
||||
@ -94,7 +108,15 @@ jest.mock('../../axiosAPIs/topicsAPI', () => ({
|
||||
}));
|
||||
|
||||
jest.mock('../../axiosAPIs/dashboardAPI', () => ({
|
||||
getDashboards: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||
getDashboards: jest.fn().mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
data: DASHBOARD_DATA,
|
||||
paging: {
|
||||
after: null,
|
||||
before: null,
|
||||
},
|
||||
})
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('../../axiosAPIs/serviceAPI', () => ({
|
||||
@ -125,12 +147,7 @@ jest.mock('react-router-dom', () => ({
|
||||
<span>{children}</span>
|
||||
)),
|
||||
useHistory: jest.fn(),
|
||||
useParams: jest.fn().mockReturnValue({
|
||||
serviceFQN: 'bigquery_gcp',
|
||||
serviceType: 'BigQuery',
|
||||
serviceCategory: 'databaseServices',
|
||||
tab: 'databases',
|
||||
}),
|
||||
useParams: jest.fn().mockImplementation(() => mockParams),
|
||||
}));
|
||||
|
||||
jest.mock('../../components/containers/PageContainer', () => {
|
||||
@ -142,7 +159,7 @@ jest.mock('../../components/containers/PageContainer', () => {
|
||||
});
|
||||
|
||||
jest.mock('../../utils/ServiceUtils', () => ({
|
||||
getCurrentServiceTab: jest.fn().mockReturnValue(1),
|
||||
getCurrentServiceTab: jest.fn().mockImplementation(() => 1),
|
||||
getIsIngestionEnable: jest.fn().mockReturnValue(true),
|
||||
servicePageTabs: jest.fn().mockReturnValue([
|
||||
{
|
||||
@ -150,6 +167,14 @@ jest.mock('../../utils/ServiceUtils', () => ({
|
||||
path: 'databases',
|
||||
field: 'databases',
|
||||
},
|
||||
{
|
||||
name: 'Ingestions',
|
||||
path: 'ingestions',
|
||||
},
|
||||
{
|
||||
name: 'Connection',
|
||||
path: 'connection',
|
||||
},
|
||||
]),
|
||||
getServiceRouteFromServiceType: jest.fn().mockReturnValue('/database'),
|
||||
getServiceCategoryFromType: jest.fn().mockReturnValue('databaseServices'),
|
||||
@ -203,6 +228,34 @@ jest.mock(
|
||||
return jest.fn().mockReturnValue(<div>ManageButton</div>);
|
||||
}
|
||||
);
|
||||
jest.mock('../../components/Ingestion/Ingestion.component', () => {
|
||||
return jest
|
||||
.fn()
|
||||
.mockReturnValue(<div data-testid="ingestions">Ingestion</div>);
|
||||
});
|
||||
|
||||
jest.mock(
|
||||
'../../components/ServiceConnectionDetails/ServiceConnectionDetails.component',
|
||||
() => {
|
||||
return jest
|
||||
.fn()
|
||||
.mockReturnValue(
|
||||
<div data-testid="service-connections">ServiceConnectionDetails</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
jest.mock('../../components/tags-viewer/tags-viewer', () => {
|
||||
return jest
|
||||
.fn()
|
||||
.mockReturnValue(<div data-testid="tag-viewer">Tag Viewer</div>);
|
||||
});
|
||||
|
||||
jest.mock('../../components/common/ProfilePicture/ProfilePicture', () => {
|
||||
return jest.fn().mockImplementation(({ name }) => {
|
||||
return <div data-testid={`${name}-profile`}>{name}</div>;
|
||||
});
|
||||
});
|
||||
|
||||
jest.mock('../../utils/TableUtils', () => ({
|
||||
getEntityLink: jest.fn(),
|
||||
@ -228,33 +281,158 @@ describe('Test ServicePage Component', () => {
|
||||
);
|
||||
const description = await findByText(container, /Description_component/i);
|
||||
const tabPane = await findByText(container, /TabsPane_component/i);
|
||||
const tableContainer = await findByTestId(container, 'table-container');
|
||||
|
||||
expect(servicePage).toBeInTheDocument();
|
||||
expect(titleBreadcrumb).toBeInTheDocument();
|
||||
expect(descriptionContainer).toBeInTheDocument();
|
||||
expect(description).toBeInTheDocument();
|
||||
expect(tabPane).toBeInTheDocument();
|
||||
expect(tableContainer).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('Table should be visible if data is available', async () => {
|
||||
const { container } = render(<ServicePage />, {
|
||||
it('Should render the service children table rows', async () => {
|
||||
render(<ServicePage />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
const tableContainer = await findByTestId(container, 'table-container');
|
||||
const tableContainer = await screen.findByTestId('service-children-table');
|
||||
|
||||
expect(tableContainer).toBeInTheDocument();
|
||||
expect(
|
||||
queryByText(container, /does not have any databases/i)
|
||||
).not.toBeInTheDocument();
|
||||
|
||||
const rows = await screen.findAllByTestId('row');
|
||||
|
||||
expect(rows).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('Number of column should be same as data received', async () => {
|
||||
const { container } = render(<ServicePage />, {
|
||||
it('Should render the owner name and profile pic if child has owner', async () => {
|
||||
render(<ServicePage />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
const column = await findAllByTestId(container, 'column');
|
||||
const tableContainer = await screen.findByTestId('service-children-table');
|
||||
|
||||
expect(column.length).toBe(1);
|
||||
expect(tableContainer).toBeInTheDocument();
|
||||
|
||||
const rows = await screen.findAllByTestId('row');
|
||||
|
||||
const firstRow = rows[0];
|
||||
|
||||
const ownerData = await findByTestId(firstRow, 'owner-data');
|
||||
|
||||
expect(ownerData).toBeInTheDocument();
|
||||
|
||||
// owner profile pic
|
||||
expect(
|
||||
await findByTestId(ownerData, 'Compute-profile')
|
||||
).toBeInTheDocument();
|
||||
|
||||
// owner name
|
||||
expect(
|
||||
await findByTestId(ownerData, 'Compute-owner-name')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should render the ingestion component', async () => {
|
||||
mockParams = { ...mockParams, tab: 'ingestions' };
|
||||
|
||||
(getCurrentServiceTab as jest.Mock).mockImplementationOnce(() => 2);
|
||||
|
||||
await act(async () => {
|
||||
render(<ServicePage />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
});
|
||||
|
||||
const ingestionContainer = await screen.findByText(
|
||||
'Failed to find OpenMetadata - Managed Airflow APIs'
|
||||
);
|
||||
|
||||
expect(ingestionContainer).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should render the connection component', async () => {
|
||||
mockParams = { ...mockParams, tab: 'connection' };
|
||||
|
||||
(getCurrentServiceTab as jest.Mock).mockImplementationOnce(() => 3);
|
||||
|
||||
await act(async () => {
|
||||
render(<ServicePage />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
});
|
||||
|
||||
const connectionContainer = await screen.findByTestId(
|
||||
'service-connections'
|
||||
);
|
||||
|
||||
const editButton = await screen.findByTestId('edit-connection-button');
|
||||
const testButton = screen.queryByTestId('test-connection-button');
|
||||
|
||||
expect(connectionContainer).toBeInTheDocument();
|
||||
|
||||
expect(editButton).toBeInTheDocument();
|
||||
|
||||
expect(testButton).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should render the dashboards and child components', async () => {
|
||||
mockParams = {
|
||||
serviceFQN: 'sample_superset',
|
||||
serviceType: 'Superset',
|
||||
serviceCategory: 'dashboardServices',
|
||||
tab: 'dashboards',
|
||||
};
|
||||
|
||||
await act(async () => {
|
||||
render(<ServicePage />, {
|
||||
wrapper: MemoryRouter,
|
||||
});
|
||||
});
|
||||
|
||||
const tableContainer = await screen.findByTestId('service-children-table');
|
||||
|
||||
expect(tableContainer).toBeInTheDocument();
|
||||
|
||||
const rows = await screen.findAllByTestId('row');
|
||||
|
||||
expect(rows).toHaveLength(3);
|
||||
|
||||
const firstRow = rows[0];
|
||||
const secondRow = rows[1];
|
||||
|
||||
// first row test
|
||||
const ownerData = await findByTestId(firstRow, 'owner-data');
|
||||
|
||||
expect(ownerData).toBeInTheDocument();
|
||||
|
||||
// owner profile pic
|
||||
expect(
|
||||
await findByTestId(ownerData, 'Compute-profile')
|
||||
).toBeInTheDocument();
|
||||
|
||||
// owner name
|
||||
expect(
|
||||
await findByTestId(ownerData, 'Compute-owner-name')
|
||||
).toBeInTheDocument();
|
||||
|
||||
const tagContainer = await findByTestId(firstRow, 'record-tags');
|
||||
|
||||
expect(tagContainer).toBeInTheDocument();
|
||||
|
||||
// should render tag viewer as it has tags
|
||||
expect(await findByTestId(tagContainer, 'tag-viewer')).toBeInTheDocument();
|
||||
|
||||
// second row test
|
||||
|
||||
const noOwnerData = await findByTestId(secondRow, 'no-owner-text');
|
||||
|
||||
expect(noOwnerData).toBeInTheDocument();
|
||||
|
||||
const secondRowTagContainer = await findByTestId(secondRow, 'record-tags');
|
||||
|
||||
expect(secondRowTagContainer).toBeInTheDocument();
|
||||
|
||||
// should not render tag viewer as it does not have tags
|
||||
expect(queryByTestId(secondRowTagContainer, 'tag-viewer')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
@ -11,7 +11,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Button, Col, Row, Space, Tooltip } from 'antd';
|
||||
import { Button, Col, Row, Space, Tooltip, Typography } from 'antd';
|
||||
import Table, { ColumnsType } from 'antd/lib/table';
|
||||
import { AxiosError } from 'axios';
|
||||
import { t } from 'i18next';
|
||||
@ -45,6 +45,7 @@ import EntitySummaryDetails from '../../components/common/EntitySummaryDetails/E
|
||||
import ErrorPlaceHolder from '../../components/common/error-with-placeholder/ErrorPlaceHolder';
|
||||
import ErrorPlaceHolderIngestion from '../../components/common/error-with-placeholder/ErrorPlaceHolderIngestion';
|
||||
import NextPrevious from '../../components/common/next-previous/NextPrevious';
|
||||
import ProfilePicture from '../../components/common/ProfilePicture/ProfilePicture';
|
||||
import RichTextEditorPreviewer from '../../components/common/rich-text-editor/RichTextEditorPreviewer';
|
||||
import TabsPane from '../../components/common/TabsPane/TabsPane';
|
||||
import TitleBreadcrumb from '../../components/common/title-breadcrumb/title-breadcrumb.component';
|
||||
@ -106,7 +107,7 @@ import { IcDeleteColored } from '../../utils/SvgUtils';
|
||||
import { getEntityLink, getUsagePercentile } from '../../utils/TableUtils';
|
||||
import { showErrorToast, showSuccessToast } from '../../utils/ToastUtils';
|
||||
|
||||
export type ServicePageData = Database | Topic | Dashboard;
|
||||
export type ServicePageData = Database | Topic | Dashboard | Mlmodel | Pipeline;
|
||||
|
||||
const ServicePage: FunctionComponent = () => {
|
||||
const { serviceFQN, serviceType, serviceCategory, tab } =
|
||||
@ -524,7 +525,7 @@ const ServicePage: FunctionComponent = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const getOptionalTableCells = (data: Database | Topic) => {
|
||||
const getOptionalTableCells = (data: ServicePageData) => {
|
||||
switch (serviceName) {
|
||||
case ServiceCategory.DATABASE_SERVICES: {
|
||||
const database = data as Database;
|
||||
@ -927,9 +928,9 @@ const ServicePage: FunctionComponent = () => {
|
||||
title: t('label.description'),
|
||||
dataIndex: 'description',
|
||||
key: 'description',
|
||||
render: (text: string) =>
|
||||
text?.trim() ? (
|
||||
<RichTextEditorPreviewer markdown={text} />
|
||||
render: (description: ServicePageData['description']) =>
|
||||
!isUndefined(description) && description.trim() ? (
|
||||
<RichTextEditorPreviewer markdown={description} />
|
||||
) : (
|
||||
<span className="tw-no-description">
|
||||
{t('label.no-description')}
|
||||
@ -940,16 +941,30 @@ const ServicePage: FunctionComponent = () => {
|
||||
title: t('label.owner'),
|
||||
dataIndex: 'owner',
|
||||
key: 'owner',
|
||||
render: (record: ServicePageData) => (
|
||||
<p>{record?.owner?.name || '--'}</p>
|
||||
),
|
||||
render: (owner: ServicePageData['owner']) =>
|
||||
!isUndefined(owner) ? (
|
||||
<Space data-testid="owner-data">
|
||||
<ProfilePicture
|
||||
id=""
|
||||
name={owner.name ?? ''}
|
||||
type="circle"
|
||||
width="24"
|
||||
/>
|
||||
<Typography.Text data-testid={`${owner.name}-owner-name`}>
|
||||
{getEntityName(owner)}
|
||||
</Typography.Text>
|
||||
</Space>
|
||||
) : (
|
||||
<Typography.Text data-testid="no-owner-text">--</Typography.Text>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: lastColumn,
|
||||
dataIndex: toLower(lastColumn),
|
||||
key: toLower(lastColumn),
|
||||
render: (record: ServicePageData) =>
|
||||
getOptionalTableCells(record as Database),
|
||||
render: (_, record: ServicePageData) => (
|
||||
<div data-testid="record-tags">{getOptionalTableCells(record)}</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
}, []);
|
||||
@ -1080,10 +1095,10 @@ const ServicePage: FunctionComponent = () => {
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) => <tr data-testid="column">{children}</tr>,
|
||||
}) => <tr data-testid="row">{children}</tr>,
|
||||
},
|
||||
}}
|
||||
data-testid="database-table"
|
||||
data-testid="service-children-table"
|
||||
dataSource={data}
|
||||
pagination={false}
|
||||
rowKey="id"
|
||||
|
@ -38,6 +38,14 @@ export const mockDatabase = {
|
||||
monthlyStats: { count: 0, percentileRank: 0 },
|
||||
weeklyStats: { count: 0, percentileRank: 0 },
|
||||
},
|
||||
owner: {
|
||||
id: '0ff251d7-f0ab-4892-96d9-35191f36bf8b',
|
||||
type: 'team',
|
||||
name: 'Compute',
|
||||
fullyQualifiedName: 'Compute',
|
||||
deleted: false,
|
||||
href: 'http://sandbox-beta.open-metadata.org/api/v1/teams/0ff251d7-f0ab-4892-96d9-35191f36bf8b',
|
||||
},
|
||||
},
|
||||
],
|
||||
paging: {
|
||||
@ -67,3 +75,155 @@ export const mockTabs = [
|
||||
position: 3,
|
||||
},
|
||||
];
|
||||
|
||||
export const DASHBOARD_DATA = [
|
||||
{
|
||||
id: '04d014be-e24b-40df-913b-c3d3e8c95548',
|
||||
name: '10',
|
||||
displayName: 'deck.gl Demo',
|
||||
fullyQualifiedName: 'sample_superset.10',
|
||||
description: 'Description.',
|
||||
version: 0.4,
|
||||
updatedAt: 1670841493940,
|
||||
updatedBy: 'sachin.c',
|
||||
dashboardUrl: 'http://localhost:808/superset/dashboard/deck/',
|
||||
href: 'http://sandbox-beta.open-metadata.org/api/v1/dashboards/04d014be-e24b-40df-913b-c3d3e8c95548',
|
||||
owner: {
|
||||
id: '0ff251d7-f0ab-4892-96d9-35191f36bf8b',
|
||||
type: 'team',
|
||||
name: 'Compute',
|
||||
fullyQualifiedName: 'Compute',
|
||||
deleted: false,
|
||||
href: 'http://sandbox-beta.open-metadata.org/api/v1/teams/0ff251d7-f0ab-4892-96d9-35191f36bf8b',
|
||||
},
|
||||
tags: [
|
||||
{
|
||||
tagFQN: 'PersonalData.SpecialCategory',
|
||||
description: 'GDPR',
|
||||
source: 'Tag',
|
||||
labelType: 'Manual',
|
||||
state: 'Confirmed',
|
||||
},
|
||||
{
|
||||
tagFQN: 'PII.None',
|
||||
description: 'Non PII',
|
||||
source: 'Tag',
|
||||
labelType: 'Manual',
|
||||
state: 'Confirmed',
|
||||
},
|
||||
],
|
||||
service: {
|
||||
id: '2b9a4c6a-6dd1-43b1-b73e-434392f7e443',
|
||||
type: 'dashboardService',
|
||||
name: 'sample_superset',
|
||||
fullyQualifiedName: 'sample_superset',
|
||||
deleted: false,
|
||||
href: 'http://sandbox-beta.open-metadata.org/api/v1/services/dashboardServices/2b9a4c6a-6dd1-43b1-b73e-434392f7e443',
|
||||
},
|
||||
serviceType: 'Superset',
|
||||
usageSummary: {
|
||||
dailyStats: {
|
||||
count: 0,
|
||||
percentileRank: 0,
|
||||
},
|
||||
weeklyStats: {
|
||||
count: 0,
|
||||
percentileRank: 0,
|
||||
},
|
||||
monthlyStats: {
|
||||
count: 0,
|
||||
percentileRank: 0,
|
||||
},
|
||||
date: '2022-12-12',
|
||||
},
|
||||
changeDescription: {
|
||||
fieldsAdded: [],
|
||||
fieldsUpdated: [
|
||||
{
|
||||
name: 'description',
|
||||
oldValue: '',
|
||||
newValue: 'Description.',
|
||||
},
|
||||
],
|
||||
fieldsDeleted: [],
|
||||
previousVersion: 0.3,
|
||||
},
|
||||
deleted: false,
|
||||
},
|
||||
{
|
||||
id: '0ab07868-b2da-4879-b29d-0977fac0c360',
|
||||
name: '11',
|
||||
displayName: 'FCC New Coder Survey 2018',
|
||||
fullyQualifiedName: 'sample_superset.11',
|
||||
description: '',
|
||||
version: 0.1,
|
||||
updatedAt: 1668510719495,
|
||||
updatedBy: 'ingestion-bot',
|
||||
dashboardUrl: 'http://localhost:808/superset/dashboard/7/',
|
||||
href: 'http://sandbox-beta.open-metadata.org/api/v1/dashboards/0ab07868-b2da-4879-b29d-0977fac0c360',
|
||||
tags: [],
|
||||
service: {
|
||||
id: '2b9a4c6a-6dd1-43b1-b73e-434392f7e443',
|
||||
type: 'dashboardService',
|
||||
name: 'sample_superset',
|
||||
fullyQualifiedName: 'sample_superset',
|
||||
deleted: false,
|
||||
href: 'http://sandbox-beta.open-metadata.org/api/v1/services/dashboardServices/2b9a4c6a-6dd1-43b1-b73e-434392f7e443',
|
||||
},
|
||||
serviceType: 'Superset',
|
||||
usageSummary: {
|
||||
dailyStats: {
|
||||
count: 0,
|
||||
percentileRank: 0,
|
||||
},
|
||||
weeklyStats: {
|
||||
count: 0,
|
||||
percentileRank: 0,
|
||||
},
|
||||
monthlyStats: {
|
||||
count: 0,
|
||||
percentileRank: 0,
|
||||
},
|
||||
date: '2022-12-12',
|
||||
},
|
||||
deleted: false,
|
||||
},
|
||||
{
|
||||
id: '359e20da-d8d5-4f68-9694-417b8b24c74d',
|
||||
name: '12',
|
||||
displayName: 'Misc Charts',
|
||||
fullyQualifiedName: 'sample_superset.12',
|
||||
description: '',
|
||||
version: 0.1,
|
||||
updatedAt: 1668510719649,
|
||||
updatedBy: 'ingestion-bot',
|
||||
dashboardUrl: 'http://localhost:808/superset/dashboard/misc_charts/',
|
||||
href: 'http://sandbox-beta.open-metadata.org/api/v1/dashboards/359e20da-d8d5-4f68-9694-417b8b24c74d',
|
||||
tags: [],
|
||||
service: {
|
||||
id: '2b9a4c6a-6dd1-43b1-b73e-434392f7e443',
|
||||
type: 'dashboardService',
|
||||
name: 'sample_superset',
|
||||
fullyQualifiedName: 'sample_superset',
|
||||
deleted: false,
|
||||
href: 'http://sandbox-beta.open-metadata.org/api/v1/services/dashboardServices/2b9a4c6a-6dd1-43b1-b73e-434392f7e443',
|
||||
},
|
||||
serviceType: 'Superset',
|
||||
usageSummary: {
|
||||
dailyStats: {
|
||||
count: 0,
|
||||
percentileRank: 0,
|
||||
},
|
||||
weeklyStats: {
|
||||
count: 0,
|
||||
percentileRank: 0,
|
||||
},
|
||||
monthlyStats: {
|
||||
count: 0,
|
||||
percentileRank: 0,
|
||||
},
|
||||
date: '2022-12-12',
|
||||
},
|
||||
deleted: false,
|
||||
},
|
||||
];
|
||||
|
Loading…
x
Reference in New Issue
Block a user