From c3e37f4f552276f89d1272e5e3eb747f4eea4dbf Mon Sep 17 00:00:00 2001 From: Shailesh Parmar Date: Tue, 11 Jul 2023 10:34:44 +0530 Subject: [PATCH] ui: added unit test for data quality component part 2 (#12279) * ui: added unit test for data quality component part 2 * added unit test for testSuitePage and editTestCaseModal * updated test with findByLabelText function * updated test for editTestCaseModal * fixed redirection spec in cypress --- .../constants/redirections.constants.js | 2 +- .../EditTestCaseModal.test.tsx | 121 ++++++++++++++ .../AddDataQualityTest/EditTestCaseModal.tsx | 14 +- .../SummaryPannel/SummaryPanel.component.tsx | 13 +- .../SummaryPannel/SummaryPanel.test.tsx | 89 +++++++++++ .../TestCaseStatusModal.component.tsx | 2 + .../TestCaseStatusModal.test.tsx | 97 +++++++++++ .../OwnerLabel/OwnerLabel.component.tsx | 4 +- .../common/OwnerLabel/OwnerLabel.test.tsx | 100 ++++++++++++ .../SummaryCard/SummaryCard.component.tsx | 17 +- .../common/SummaryCard/SummaryCard.test.tsx | 70 ++++++++ .../resources/ui/src/mocks/TestSuite.mock.ts | 35 ++++ .../TestSuiteDetailsPage.component.tsx | 1 + .../TestSuiteDetailsPage.test.tsx | 151 ++++++++++++++++++ 14 files changed, 697 insertions(+), 19 deletions(-) create mode 100644 openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/EditTestCaseModal.test.tsx create mode 100644 openmetadata-ui/src/main/resources/ui/src/components/DataQuality/SummaryPannel/SummaryPanel.test.tsx create mode 100644 openmetadata-ui/src/main/resources/ui/src/components/DataQuality/TestCaseStatusModal/TestCaseStatusModal.test.tsx create mode 100644 openmetadata-ui/src/main/resources/ui/src/components/common/OwnerLabel/OwnerLabel.test.tsx create mode 100644 openmetadata-ui/src/main/resources/ui/src/components/common/SummaryCard/SummaryCard.test.tsx create mode 100644 openmetadata-ui/src/main/resources/ui/src/pages/TestSuiteDetailsPage/TestSuiteDetailsPage.test.tsx diff --git a/openmetadata-ui/src/main/resources/ui/cypress/constants/redirections.constants.js b/openmetadata-ui/src/main/resources/ui/cypress/constants/redirections.constants.js index 255fca85f97..b4e2ef1145a 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/constants/redirections.constants.js +++ b/openmetadata-ui/src/main/resources/ui/cypress/constants/redirections.constants.js @@ -63,7 +63,7 @@ export const LEFT_PANEL_DETAILS = { export const NAVBAR_DETAILS = { explore: { testid: '[data-testid="appbar-item-explore"]', - url: `${BASE_URL}/explore/tables?page=1`, + url: `${BASE_URL}/explore/tables`, }, quality: { testid: '[data-testid="appbar-item-data-quality"]', diff --git a/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/EditTestCaseModal.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/EditTestCaseModal.test.tsx new file mode 100644 index 00000000000..c15314c6831 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/EditTestCaseModal.test.tsx @@ -0,0 +1,121 @@ +/* + * Copyright 2023 Collate. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { act, fireEvent, render, screen } from '@testing-library/react'; +import { + MOCK_TEST_CASE, + MOCK_TEST_DEFINITION_COLUMN_VALUES_TO_MATCH_REGEX, +} from 'mocks/TestSuite.mock'; +import React, { forwardRef } from 'react'; +import { EditTestCaseModalProps } from './AddDataQualityTest.interface'; +import EditTestCaseModal from './EditTestCaseModal'; + +const mockProps: EditTestCaseModalProps = { + visible: true, + testCase: MOCK_TEST_CASE[0], + onCancel: jest.fn(), + onUpdate: jest.fn(), +}; + +jest.mock('../common/rich-text-editor/RichTextEditor', () => { + return forwardRef( + jest.fn().mockImplementation(() =>
RichTextEditor.component
) + ); +}); +jest.mock('./components/ParameterForm', () => { + return jest.fn().mockImplementation(() =>
ParameterForm.component
); +}); +jest.mock('rest/testAPI', () => { + return { + getTestDefinitionById: jest + .fn() + .mockImplementation(() => + Promise.resolve(MOCK_TEST_DEFINITION_COLUMN_VALUES_TO_MATCH_REGEX) + ), + updateTestCaseById: jest.fn().mockImplementation(() => Promise.resolve()), + }; +}); + +describe('EditTestCaseModal Component', () => { + it('component should render', async () => { + render(); + + expect(await screen.findByTestId('edit-test-form')).toBeInTheDocument(); + expect(await screen.findByLabelText('label.table')).toBeInTheDocument(); + expect(await screen.findByLabelText('label.column')).toBeInTheDocument(); + expect(await screen.findByLabelText('label.name')).toBeInTheDocument(); + expect( + await screen.findByLabelText('label.display-name') + ).toBeInTheDocument(); + expect( + await screen.findByLabelText('label.test-entity') + ).toBeInTheDocument(); + expect( + await screen.findByText('RichTextEditor.component') + ).toBeInTheDocument(); + expect( + await screen.findByText('ParameterForm.component') + ).toBeInTheDocument(); + expect(await screen.findByText('label.cancel')).toBeInTheDocument(); + expect(await screen.findByText('label.submit')).toBeInTheDocument(); + }); + + it('table, name, test definition, should be disabled', async () => { + render(); + + expect(await screen.findByLabelText('label.name')).toBeDisabled(); + expect(await screen.findByLabelText('label.column')).toBeDisabled(); + expect(await screen.findByLabelText('label.table')).toBeDisabled(); + expect(await screen.findByLabelText('label.test-entity')).toBeDisabled(); + }); + + it('fields should have data based on testCase value', async () => { + render(); + + expect(await screen.findByLabelText('label.table')).toHaveValue( + 'dim_address' + ); + expect(await screen.findByLabelText('label.column')).toHaveValue( + 'last_name' + ); + expect(await screen.findByLabelText('label.name')).toHaveValue( + 'column_values_to_match_regex' + ); + expect(await screen.findByLabelText('label.test-entity')).toHaveValue( + 'columnValuesToMatchRegex' + ); + }); + + it('should call onCancel function, on click of cancel button', async () => { + render(); + + const cancelBtn = await screen.findByText('label.cancel'); + + await act(async () => { + fireEvent.click(cancelBtn); + }); + + expect(mockProps.onCancel).toHaveBeenCalled(); + }); + + it('should call onUpdate function, on click of submit button', async () => { + render(); + + const submitBtn = await screen.findByText('label.submit'); + + await act(async () => { + fireEvent.click(submitBtn); + }); + + expect(mockProps.onUpdate).toHaveBeenCalled(); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/EditTestCaseModal.tsx b/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/EditTestCaseModal.tsx index 799287a5cc8..dcf3f81407a 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/EditTestCaseModal.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/AddDataQualityTest/EditTestCaseModal.tsx @@ -198,6 +198,7 @@ const EditTestCaseModal: React.FC = ({ form.resetFields(); onCancel(); }} + cancelText={t('label.cancel')} closable={false} confirmLoading={isLoadingOnSave} maskClosable={false} @@ -212,21 +213,22 @@ const EditTestCaseModal: React.FC = ({ ) : (
- + {isColumn && ( - + )} = ({ {GenerateParamsField()} - + { }; useEffect(() => { - if (isUndefined(testSummary)) { - if (testCasePermission?.ViewAll || testCasePermission?.ViewBasic) { - fetchTestSummary(); - } + if ( + isUndefined(testSummary) && + (testCasePermission?.ViewAll || testCasePermission?.ViewBasic) + ) { + fetchTestSummary(); } else { - setSummary(testSummary); + setSummary(testSummary ?? INITIAL_TEST_SUMMARY); setIsLoading(false); } }, [testCasePermission]); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/SummaryPannel/SummaryPanel.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/SummaryPannel/SummaryPanel.test.tsx new file mode 100644 index 00000000000..2f854c09544 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/SummaryPannel/SummaryPanel.test.tsx @@ -0,0 +1,89 @@ +/* + * Copyright 2023 Collate. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { render, screen } from '@testing-library/react'; +import React from 'react'; +import { getTestCaseExecutionSummary } from 'rest/testAPI'; +import { SummaryPanel } from './SummaryPanel.component'; + +const testCasePermission = { + Create: true, + Delete: true, + ViewAll: true, + EditAll: true, + EditDescription: true, + EditDisplayName: true, + EditCustomFields: true, +}; +const mockSummary = { + total: 10, + success: 7, + aborted: 2, + failed: 1, +}; + +jest.mock('components/PermissionProvider/PermissionProvider', () => ({ + usePermissionProvider: jest.fn().mockImplementation(() => ({ + permissions: { + testCase: testCasePermission, + }, + })), +})); +jest.mock('components/common/SummaryCard/SummaryCard.component', () => { + return { + SummaryCard: jest + .fn() + .mockImplementation(() =>
SummaryCard.component
), + }; +}); +jest.mock('rest/testAPI', () => { + return { + getTestCaseExecutionSummary: jest + .fn() + .mockImplementation(() => Promise.resolve(mockSummary)), + }; +}); + +describe('SummaryPanel component', () => { + it('component should render', async () => { + render(); + + const summaryCards = await screen.findAllByText('SummaryCard.component'); + + expect(summaryCards).toHaveLength(4); + }); + + it('on page load getTestCaseExecutionSummary API should call', async () => { + const mockGetTestCaseExecutionSummary = + getTestCaseExecutionSummary as jest.Mock; + render(); + + expect(mockGetTestCaseExecutionSummary).toHaveBeenCalled(); + }); + + it('should not call getTestCaseExecutionSummary API, if testSummary data is provided', async () => { + const mockGetTestCaseExecutionSummary = + getTestCaseExecutionSummary as jest.Mock; + render(); + + expect(mockGetTestCaseExecutionSummary).not.toHaveBeenCalled(); + }); + + it('should not call getTestCaseExecutionSummary API, if there is no permission', async () => { + const mockGetTestCaseExecutionSummary = + getTestCaseExecutionSummary as jest.Mock; + testCasePermission.ViewAll = false; + render(); + + expect(mockGetTestCaseExecutionSummary).not.toHaveBeenCalled(); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/TestCaseStatusModal/TestCaseStatusModal.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/TestCaseStatusModal/TestCaseStatusModal.component.tsx index 2b52f836a3f..5975c5a0285 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/TestCaseStatusModal/TestCaseStatusModal.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/TestCaseStatusModal/TestCaseStatusModal.component.tsx @@ -51,6 +51,7 @@ export const TestCaseStatusModal = ({ return ( + data-testid="update-status-form" form={form} id="update-status-form" initialValues={data} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/TestCaseStatusModal/TestCaseStatusModal.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/TestCaseStatusModal/TestCaseStatusModal.test.tsx new file mode 100644 index 00000000000..057aa3fa7d1 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/TestCaseStatusModal/TestCaseStatusModal.test.tsx @@ -0,0 +1,97 @@ +/* + * Copyright 2023 Collate. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { act, fireEvent, render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { TestCaseFailureStatusType } from 'generated/tests/testCase'; +import React, { forwardRef } from 'react'; +import { TestCaseStatusModal } from './TestCaseStatusModal.component'; +import { TestCaseStatusModalProps } from './TestCaseStatusModal.interface'; + +const mockProps: TestCaseStatusModalProps = { + open: true, + onCancel: jest.fn(), + onSubmit: jest.fn().mockImplementation(() => Promise.resolve()), +}; + +jest.mock('components/common/rich-text-editor/RichTextEditor', () => { + return forwardRef(jest.fn().mockReturnValue(
RichTextEditor
)); +}); +jest.mock('generated/tests/testCase', () => ({ + ...jest.requireActual('generated/tests/testCase'), + TestCaseFailureStatusType: { + ACK: 'Ack', + New: 'New', + Resolved: 'Resolved', + }, +})); + +describe('TestCaseStatusModal component', () => { + it('component should render', async () => { + render(); + + expect(await screen.findByTestId('update-status-form')).toBeInTheDocument(); + expect(await screen.findByLabelText('label.status')).toBeInTheDocument(); + expect(await screen.findByText('label.cancel')).toBeInTheDocument(); + expect(await screen.findByText('label.submit')).toBeInTheDocument(); + }); + + it('should render test case reason and comment field, if status is resolved', async () => { + render( + + ); + + expect(await screen.findByLabelText('label.status')).toBeInTheDocument(); + expect(await screen.findByLabelText('label.reason')).toBeInTheDocument(); + expect(await screen.findByText('RichTextEditor')).toBeInTheDocument(); + }); + + it('should call onCancel function, on click of cancel button', async () => { + render( + + ); + const cancelBtn = await screen.findByText('label.cancel'); + await act(async () => { + fireEvent.click(cancelBtn); + }); + + expect(mockProps.onCancel).toHaveBeenCalled(); + }); + + it('should call onSubmit function, on click of save button', async () => { + render(); + const submitBtn = await screen.findByText('label.submit'); + const status = await screen.findByLabelText('label.status'); + + await act(async () => { + userEvent.click(status); + }); + + const statusOption = await screen.findAllByText('New'); + + await act(async () => { + fireEvent.click(statusOption[1]); + }); + + await act(async () => { + fireEvent.click(submitBtn); + }); + + expect(mockProps.onSubmit).toHaveBeenCalled(); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/OwnerLabel/OwnerLabel.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/OwnerLabel/OwnerLabel.component.tsx index 70b3f3458e0..11dbfb4d126 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/OwnerLabel/OwnerLabel.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/OwnerLabel/OwnerLabel.component.tsx @@ -40,11 +40,11 @@ export const OwnerLabel = ({ const profilePicture = useMemo(() => { if (isUndefined(owner)) { - return ; + return ; } return owner.type === OwnerType.TEAM ? ( - + ) : ( { + return jest.fn().mockReturnValue(
ProfilePicture.component
); +}); +jest.mock('../UserTeamSelectableList/UserTeamSelectableList.component', () => { + return { + UserTeamSelectableList: jest + .fn() + .mockReturnValue(
UserTeamSelectableList.component
), + }; +}); + +describe('OwnerLabel component', () => { + it('owner name with profile picture should render', async () => { + render(, { wrapper: MemoryRouter }); + + expect( + await screen.findByText('ProfilePicture.component') + ).toBeInTheDocument(); + expect(await screen.findByText(mockOwner.name)).toBeInTheDocument(); + }); + + it('should render displayName if provided', async () => { + render( + , + { wrapper: MemoryRouter } + ); + + expect( + await screen.findByText('ProfilePicture.component') + ).toBeInTheDocument(); + expect(await screen.findByText('displayName')).toBeInTheDocument(); + }); + + it('should render ownerDisplayName if provided', async () => { + render( + , + { wrapper: MemoryRouter } + ); + + expect( + await screen.findByText('ProfilePicture.component') + ).toBeInTheDocument(); + expect(await screen.findByText('ownerDisplayName')).toBeInTheDocument(); + expect(screen.queryByText(mockOwner.name)).not.toBeInTheDocument(); + }); + + it('should render no owner if owner is undefined', async () => { + render(, { wrapper: MemoryRouter }); + + expect(await screen.findByText('label.no-entity')).toBeInTheDocument(); + expect(await screen.findByTestId('no-owner-icon')).toBeInTheDocument(); + }); + + it('should render team icon and team name if owner is team', async () => { + render(, { wrapper: MemoryRouter }); + + expect(await screen.findByText(mockTeamOwner.name)).toBeInTheDocument(); + expect(await screen.findByTestId('team-owner-icon')).toBeInTheDocument(); + }); + + it('should render UserTeamSelectableList if onUpdate function is provided', async () => { + render(, { + wrapper: MemoryRouter, + }); + + expect( + await screen.findByText('UserTeamSelectableList.component') + ).toBeInTheDocument(); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/SummaryCard/SummaryCard.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/SummaryCard/SummaryCard.component.tsx index 74ee7637629..7a93ad1a53c 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/SummaryCard/SummaryCard.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/SummaryCard/SummaryCard.component.tsx @@ -37,19 +37,27 @@ export const SummaryCard = ({ if (isLoading) { return ( -
+
); } return ( - +
- + {title} - + {isNumber(value) ? formatNumberWithComma(value) : value}
@@ -57,6 +65,7 @@ export const SummaryCard = ({ {showProgressBar && ( `${percent}%`} percent={percent} type="circle" diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/SummaryCard/SummaryCard.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/SummaryCard/SummaryCard.test.tsx new file mode 100644 index 00000000000..eef84fcbcee --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/SummaryCard/SummaryCard.test.tsx @@ -0,0 +1,70 @@ +/* + * Copyright 2023 Collate. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { render, screen } from '@testing-library/react'; +import React from 'react'; +import { SummaryCard } from './SummaryCard.component'; +import { SummaryCardProps } from './SummaryCard.interface'; + +const mockProps: SummaryCardProps = { + title: 'title', + value: 10, + total: 100, +}; + +describe('SummaryCard component', () => { + it('component should render', async () => { + render(); + + expect( + await screen.findByTestId('summary-card-container') + ).toBeInTheDocument(); + expect(await screen.findByTestId('summary-card-title')).toBeInTheDocument(); + expect( + await screen.findByTestId('summary-card-description') + ).toBeInTheDocument(); + expect(await screen.findByRole('presentation')).toBeInTheDocument(); + }); + + it('should not render progress bar, if showProgressBar is false', async () => { + render(); + + expect(screen.queryByRole('presentation')).not.toBeInTheDocument(); + }); + + it('should not render skeleton loader, if isLoading is true', async () => { + render(); + + expect(await screen.findByTestId('skeleton-loading')).toBeInTheDocument(); + }); + + it('should render progress bar based on type', async () => { + render(); + + const progressBar = await screen.findByTestId('progress-bar'); + + expect(progressBar).toBeInTheDocument(); + expect(progressBar).toHaveClass('success'); + }); + + it('should render title and description based on props', async () => { + render(); + + const title = await screen.findByTestId('summary-card-title'); + const description = await screen.findByTestId('summary-card-description'); + + expect(title).toBeInTheDocument(); + expect(description).toBeInTheDocument(); + expect(title.textContent).toStrictEqual('summary title'); + expect(description.textContent).toStrictEqual('description'); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/src/mocks/TestSuite.mock.ts b/openmetadata-ui/src/main/resources/ui/src/mocks/TestSuite.mock.ts index d3b0c3963e7..885a03e7251 100644 --- a/openmetadata-ui/src/main/resources/ui/src/mocks/TestSuite.mock.ts +++ b/openmetadata-ui/src/main/resources/ui/src/mocks/TestSuite.mock.ts @@ -673,6 +673,41 @@ export const MOCK_SQL_TEST_CASE = { deleted: false, } as TestCase; +export const MOCK_TEST_DEFINITION_COLUMN_VALUES_TO_MATCH_REGEX = { + id: '4c69c0d7-c173-4f17-b939-737ce0510f66', + name: 'columnValuesToMatchRegex', + displayName: 'Column Values To Match Regex Pattern', + fullyQualifiedName: 'columnValuesToMatchRegex', + description: + 'This schema defines the test ColumnValuesToMatchRegex. Test the values in a column to match a given regular expression. ', + entityType: 'COLUMN', + testPlatforms: ['OpenMetadata'], + supportedDataTypes: [ + 'BYTES', + 'STRING', + 'MEDIUMTEXT', + 'TEXT', + 'CHAR', + 'VARCHAR', + ], + parameterDefinition: [ + { + name: 'regex', + displayName: 'RegEx Pattern', + dataType: 'STRING', + description: + 'The regular expression the column entries should match. For database without regex support (i.e. MSSQL, AzureSQL) this test will use `LIKE`.', + required: true, + optionValues: [], + }, + ], + version: 0.1, + updatedAt: 1682571176093, + updatedBy: 'admin', + href: 'href', + deleted: false, +}; + export const MOCK_CHART_COLLECTION_DATA = { data: [ { diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TestSuiteDetailsPage/TestSuiteDetailsPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TestSuiteDetailsPage/TestSuiteDetailsPage.component.tsx index 8c94d1161e5..d92b4545c09 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/TestSuiteDetailsPage/TestSuiteDetailsPage.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/TestSuiteDetailsPage/TestSuiteDetailsPage.component.tsx @@ -332,6 +332,7 @@ const TestSuiteDetailsPage = () => { {(testSuitePermissions.EditAll || testSuitePermissions.EditTests) && (