diff --git a/openmetadata-ui/src/main/resources/ui/playwright/constant/config.ts b/openmetadata-ui/src/main/resources/ui/playwright/constant/config.ts new file mode 100644 index 000000000000..558cbefca464 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/playwright/constant/config.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2024 Collate. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const PLAYWRIGHT_INGESTION_TAG_OBJ = { + tag: '@ingestion', +}; diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/IncidentManager.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/IncidentManager.spec.ts index e8d89b35df8c..5cdeeff59616 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/IncidentManager.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/IncidentManager.spec.ts @@ -11,6 +11,7 @@ * limitations under the License. */ import test, { expect } from '@playwright/test'; +import { PLAYWRIGHT_INGESTION_TAG_OBJ } from '../../constant/config'; import { SidebarItem } from '../../constant/sidebar'; import { TableClass } from '../../support/entity/TableClass'; import { UserClass } from '../../support/user/UserClass'; @@ -39,7 +40,7 @@ test.use({ storageState: 'playwright/.auth/admin.json' }); test.describe.configure({ mode: 'serial' }); -test.describe('Incident Manager', () => { +test.describe('Incident Manager', PLAYWRIGHT_INGESTION_TAG_OBJ, () => { test.beforeAll(async ({ browser }) => { // since we need to poll for the pipeline status, we need to increase the timeout test.setTimeout(90000); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/TestSuiteMultiPipeline.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/TestSuiteMultiPipeline.spec.ts index fb016273d8ee..8bc297a543c6 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/TestSuiteMultiPipeline.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/TestSuiteMultiPipeline.spec.ts @@ -11,99 +11,206 @@ * limitations under the License. */ import { expect, test } from '@playwright/test'; +import { PLAYWRIGHT_INGESTION_TAG_OBJ } from '../../constant/config'; import { TableClass } from '../../support/entity/TableClass'; import { getApiContext, redirectToHomePage, uuid } from '../../utils/common'; // use the admin user to login test.use({ storageState: 'playwright/.auth/admin.json' }); -test('TestSuite multi pipeline support', async ({ page }) => { - test.slow(true); - - await redirectToHomePage(page); - const { apiContext, afterAction } = await getApiContext(page); - const table = new TableClass(); - await table.create(apiContext); - await table.visitEntityPage(page); - const testCaseName = `multi-pipeline-test-${uuid()}`; - const pipelineName = `test suite pipeline 2`; - - await test.step('Create a new pipeline', async () => { - await page.getByText('Profiler & Data Quality').click(); - await page - .getByRole('menuitem', { - name: 'Table Profile', - }) - .click(); - await page.getByTestId('profiler-add-table-test-btn').click(); - await page.getByTestId('test-case').click(); - await page.getByTestId('test-case-name').clear(); - await page.getByTestId('test-case-name').fill(testCaseName); - await page.getByTestId('test-type').locator('div').click(); - await page.getByText('Table Column Count To Equal').click(); - await page.getByPlaceholder('Enter a Count').fill('13'); - await page.getByTestId('submit-test').click(); - - await expect(page.getByTestId('add-ingestion-button')).toBeVisible(); - await expect(page.getByTestId('add-ingestion-button')).toContainText( - 'Add Ingestion' - ); - - await page.getByTestId('add-ingestion-button').click(); - await page.getByTestId('select-all-test-cases').click(); - await page.getByTestId('cron-type').getByText('Hour').click(); - await page.getByTitle('Day').click(); - await page.getByTestId('deploy-button').click(); - - await expect(page.getByTestId('view-service-button')).toBeVisible(); - - await page.waitForSelector('[data-testid="body-text"]', { - state: 'detached', +test( + 'TestSuite multi pipeline support', + PLAYWRIGHT_INGESTION_TAG_OBJ, + async ({ page }) => { + test.slow(true); + + await redirectToHomePage(page); + const { apiContext, afterAction } = await getApiContext(page); + const table = new TableClass(); + await table.create(apiContext); + await table.visitEntityPage(page); + const testCaseName = `multi-pipeline-test-${uuid()}`; + const pipelineName = `test suite pipeline 2`; + + await test.step('Create a new pipeline', async () => { + await page.getByText('Profiler & Data Quality').click(); + await page + .getByRole('menuitem', { + name: 'Table Profile', + }) + .click(); + await page.getByTestId('profiler-add-table-test-btn').click(); + await page.getByTestId('test-case').click(); + await page.getByTestId('test-case-name').clear(); + await page.getByTestId('test-case-name').fill(testCaseName); + await page.getByTestId('test-type').locator('div').click(); + await page.getByText('Table Column Count To Equal').click(); + await page.getByPlaceholder('Enter a Count').fill('13'); + await page.getByTestId('submit-test').click(); + + await expect(page.getByTestId('add-ingestion-button')).toBeVisible(); + await expect(page.getByTestId('add-ingestion-button')).toContainText( + 'Add Ingestion' + ); + + await page.getByTestId('add-ingestion-button').click(); + await page.getByTestId('select-all-test-cases').click(); + await page.getByTestId('cron-type').getByText('Hour').click(); + await page.getByTitle('Day').click(); + await page.getByTestId('deploy-button').click(); + + await expect(page.getByTestId('view-service-button')).toBeVisible(); + + await page.waitForSelector('[data-testid="body-text"]', { + state: 'detached', + }); + + await expect(page.getByTestId('success-line')).toContainText( + /has been created and deployed successfully/ + ); + + await page.getByTestId('view-service-button').click(); + await page.getByRole('menuitem', { name: 'Data Quality' }).click(); + await page.getByRole('tab', { name: 'Pipeline' }).click(); + await page.getByTestId('add-pipeline-button').click(); + + await page.fill('[data-testid="pipeline-name"]', pipelineName); + + await page.getByTestId(testCaseName).click(); + + await page.getByTestId('cron-type').locator('div').click(); + await page.getByTitle('Week').click(); + + await expect(page.getByTestId('deploy-button')).toBeVisible(); + + await page.getByTestId('deploy-button').click(); + + await page.waitForSelector('[data-testid="body-text"]', { + state: 'detached', + }); + + await expect(page.getByTestId('success-line')).toContainText( + /has been created and deployed successfully/ + ); + await expect(page.getByTestId('view-service-button')).toContainText( + 'View Test Suite' + ); + await expect(page.getByTestId('view-service-button')).toBeVisible(); + + await page.getByTestId('view-service-button').click(); }); - await expect(page.getByTestId('success-line')).toContainText( - /has been created and deployed successfully/ - ); - - await page.getByTestId('view-service-button').click(); - await page.getByRole('menuitem', { name: 'Data Quality' }).click(); - await page.getByRole('tab', { name: 'Pipeline' }).click(); - await page.getByTestId('add-pipeline-button').click(); - - await page.fill('[data-testid="pipeline-name"]', pipelineName); - - await page.getByTestId(testCaseName).click(); - - await page.getByTestId('cron-type').locator('div').click(); - await page.getByTitle('Week').click(); - - await expect(page.getByTestId('deploy-button')).toBeVisible(); - - await page.getByTestId('deploy-button').click(); + await test.step('Update the pipeline', async () => { + await page.getByRole('tab', { name: 'Pipeline' }).click(); + await page + .getByRole('row', { + name: new RegExp(pipelineName), + }) + .getByTestId('more-actions') + .click(); + + await page + .locator( + '[data-testid="actions-dropdown"]:visible [data-testid="edit-button"]' + ) + .click(); + + await expect(page.getByRole('checkbox').first()).toBeVisible(); + + await page + .getByTestId('week-segment-day-option-container') + .getByText('W') + .click(); + await page.getByTestId('deploy-button').click(); + await page.waitForSelector('[data-testid="body-text"]', { + state: 'detached', + }); + + await expect(page.getByTestId('success-line')).toContainText( + /has been updated and deployed successfully/ + ); + + await page.getByTestId('view-service-button').click(); + }); - await page.waitForSelector('[data-testid="body-text"]', { - state: 'detached', + await test.step('Delete the pipeline', async () => { + await page.getByRole('tab', { name: 'Pipeline' }).click(); + await page + .getByRole('row', { + name: new RegExp(pipelineName), + }) + .getByTestId('more-actions') + .click(); + + await page + .locator( + '[data-testid="actions-dropdown"]:visible [data-testid="delete-button"]' + ) + .click(); + + await page.getByTestId('confirmation-text-input').fill('DELETE'); + const deleteRes = page.waitForResponse( + '/api/v1/services/ingestionPipelines/*?hardDelete=true' + ); + await page.getByTestId('confirm-button').click(); + await deleteRes; + + await page.getByTestId('more-actions').click(); + + await page + .locator( + '[data-testid="actions-dropdown"]:visible [data-testid="delete-button"]' + ) + .click(); + await page.getByTestId('confirmation-text-input').fill('DELETE'); + await page.getByTestId('confirm-button').click(); + await deleteRes; + + await expect( + page.getByTestId('assign-error-placeholder-Pipeline') + ).toContainText( + "Add a pipeline to automate the data quality tests at a regular schedule. It's advisable to align the schedule with the frequency of table loads for optimal results" + ); + await expect(page.getByTestId('add-placeholder-button')).toBeVisible(); }); - await expect(page.getByTestId('success-line')).toContainText( - /has been created and deployed successfully/ - ); - await expect(page.getByTestId('view-service-button')).toContainText( - 'View Test Suite' + await table.delete(apiContext); + await afterAction(); + } +); + +test( + "Edit the pipeline's test case", + PLAYWRIGHT_INGESTION_TAG_OBJ, + async ({ page }) => { + test.slow(true); + + await redirectToHomePage(page); + const { apiContext, afterAction } = await getApiContext(page); + const table = new TableClass(); + await table.create(apiContext); + for (let index = 0; index < 4; index++) { + await table.createTestCase(apiContext); + } + const testCaseNames = [ + table.testCasesResponseData[0]?.['name'], + table.testCasesResponseData[1]?.['name'], + ]; + const pipeline = await table.createTestSuitePipeline( + apiContext, + testCaseNames ); - await expect(page.getByTestId('view-service-button')).toBeVisible(); - - await page.getByTestId('view-service-button').click(); - }); + await table.visitEntityPage(page); + await page.getByText('Profiler & Data Quality').click(); + await page.getByRole('menuitem', { name: 'Data Quality' }).click(); - await test.step('Update the pipeline', async () => { await page.getByRole('tab', { name: 'Pipeline' }).click(); await page .getByRole('row', { - name: new RegExp(pipelineName), + name: new RegExp(pipeline?.['name']), }) .getByTestId('more-actions') - .click(); + .click({ force: true }); await page .locator( @@ -111,12 +218,16 @@ test('TestSuite multi pipeline support', async ({ page }) => { ) .click(); - await expect(page.getByRole('checkbox').first()).toBeVisible(); + for (const testCaseName of testCaseNames) { + await expect(page.getByTestId(`checkbox-${testCaseName}`)).toBeChecked(); + } + + await page.getByTestId(`checkbox-${testCaseNames[0]}`).click(); + + await expect( + page.getByTestId(`checkbox-${testCaseNames[0]}`) + ).not.toBeChecked(); - await page - .getByTestId('week-segment-day-option-container') - .getByText('W') - .click(); await page.getByTestId('deploy-button').click(); await page.waitForSelector('[data-testid="body-text"]', { state: 'detached', @@ -127,129 +238,29 @@ test('TestSuite multi pipeline support', async ({ page }) => { ); await page.getByTestId('view-service-button').click(); - }); - await test.step('Delete the pipeline', async () => { await page.getByRole('tab', { name: 'Pipeline' }).click(); await page .getByRole('row', { - name: new RegExp(pipelineName), + name: new RegExp(pipeline?.['name']), }) .getByTestId('more-actions') .click(); await page .locator( - '[data-testid="actions-dropdown"]:visible [data-testid="delete-button"]' - ) - .click(); - - await page.getByTestId('confirmation-text-input').fill('DELETE'); - const deleteRes = page.waitForResponse( - '/api/v1/services/ingestionPipelines/*?hardDelete=true' - ); - await page.getByTestId('confirm-button').click(); - await deleteRes; - - await page.getByTestId('more-actions').click(); - - await page - .locator( - '[data-testid="actions-dropdown"]:visible [data-testid="delete-button"]' + '[data-testid="actions-dropdown"]:visible [data-testid="edit-button"]' ) .click(); - await page.getByTestId('confirmation-text-input').fill('DELETE'); - await page.getByTestId('confirm-button').click(); - await deleteRes; await expect( - page.getByTestId('assign-error-placeholder-Pipeline') - ).toContainText( - "Add a pipeline to automate the data quality tests at a regular schedule. It's advisable to align the schedule with the frequency of table loads for optimal results" - ); - await expect(page.getByTestId('add-placeholder-button')).toBeVisible(); - }); - - await table.delete(apiContext); - await afterAction(); -}); - -test("Edit the pipeline's test case", async ({ page }) => { - test.slow(true); - - await redirectToHomePage(page); - const { apiContext, afterAction } = await getApiContext(page); - const table = new TableClass(); - await table.create(apiContext); - for (let index = 0; index < 4; index++) { - await table.createTestCase(apiContext); - } - const testCaseNames = [ - table.testCasesResponseData[0]?.['name'], - table.testCasesResponseData[1]?.['name'], - ]; - const pipeline = await table.createTestSuitePipeline( - apiContext, - testCaseNames - ); - await table.visitEntityPage(page); - await page.getByText('Profiler & Data Quality').click(); - await page.getByRole('menuitem', { name: 'Data Quality' }).click(); - - await page.getByRole('tab', { name: 'Pipeline' }).click(); - await page - .getByRole('row', { - name: new RegExp(pipeline?.['name']), - }) - .getByTestId('more-actions') - .click({ force: true }); - - await page - .locator( - '[data-testid="actions-dropdown"]:visible [data-testid="edit-button"]' - ) - .click(); - - for (const testCaseName of testCaseNames) { - await expect(page.getByTestId(`checkbox-${testCaseName}`)).toBeChecked(); - } + page.getByTestId(`checkbox-${testCaseNames[0]}`) + ).not.toBeChecked(); + await expect( + page.getByTestId(`checkbox-${testCaseNames[1]}`) + ).toBeChecked(); - await page.getByTestId(`checkbox-${testCaseNames[0]}`).click(); - - await expect( - page.getByTestId(`checkbox-${testCaseNames[0]}`) - ).not.toBeChecked(); - - await page.getByTestId('deploy-button').click(); - await page.waitForSelector('[data-testid="body-text"]', { - state: 'detached', - }); - - await expect(page.getByTestId('success-line')).toContainText( - /has been updated and deployed successfully/ - ); - - await page.getByTestId('view-service-button').click(); - - await page.getByRole('tab', { name: 'Pipeline' }).click(); - await page - .getByRole('row', { - name: new RegExp(pipeline?.['name']), - }) - .getByTestId('more-actions') - .click(); - - await page - .locator( - '[data-testid="actions-dropdown"]:visible [data-testid="edit-button"]' - ) - .click(); - - await expect( - page.getByTestId(`checkbox-${testCaseNames[0]}`) - ).not.toBeChecked(); - await expect(page.getByTestId(`checkbox-${testCaseNames[1]}`)).toBeChecked(); - - await table.delete(apiContext); - await afterAction(); -}); + await table.delete(apiContext); + await afterAction(); + } +); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/DataQualityAndProfiler.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/DataQualityAndProfiler.spec.ts index fd30546e6267..88fbc7f0f15d 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/DataQualityAndProfiler.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/DataQualityAndProfiler.spec.ts @@ -12,6 +12,7 @@ */ import { expect, Page, test } from '@playwright/test'; import { getCurrentMillis } from '../../../src/utils/date-time/DateTimeUtils'; +import { PLAYWRIGHT_INGESTION_TAG_OBJ } from '../../constant/config'; import { SidebarItem } from '../../constant/sidebar'; import { Domain } from '../../support/domain/Domain'; import { TableClass } from '../../support/entity/TableClass'; @@ -65,7 +66,7 @@ test.beforeEach(async ({ page }) => { await redirectToHomePage(page); }); -test('Table test case', async ({ page }) => { +test('Table test case', PLAYWRIGHT_INGESTION_TAG_OBJ, async ({ page }) => { test.slow(); const NEW_TABLE_TEST_CASE = { @@ -164,7 +165,7 @@ test('Table test case', async ({ page }) => { }); }); -test('Column test case', async ({ page }) => { +test('Column test case', PLAYWRIGHT_INGESTION_TAG_OBJ, async ({ page }) => { test.slow(); const NEW_COLUMN_TEST_CASE = { @@ -249,314 +250,328 @@ test('Column test case', async ({ page }) => { }); }); -test('Profiler matrix and test case graph should visible', async ({ page }) => { - const DATA_QUALITY_TABLE = { - term: 'dim_address', - serviceName: 'sample_data', - testCaseName: 'column_value_max_to_be_between', - }; - - await visitEntityPage({ - page, - searchTerm: DATA_QUALITY_TABLE.term, - dataTestId: `${DATA_QUALITY_TABLE.serviceName}-${DATA_QUALITY_TABLE.term}`, - }); - await page.waitForSelector(`[data-testid="entity-header-display-name"]`); - - await expect( - page.locator(`[data-testid="entity-header-display-name"]`) - ).toContainText(DATA_QUALITY_TABLE.term); - - const profilerResponse = page.waitForResponse( - `/api/v1/tables/*/tableProfile/latest` - ); - await page.click('[data-testid="profiler"]'); - await profilerResponse; - await page.waitForTimeout(1000); - await page - .getByRole('menuitem', { - name: 'Column Profile', - }) - .click(); - const getProfilerInfo = page.waitForResponse( - '/api/v1/tables/*/columnProfile?*' - ); - await page.locator('[data-row-key="shop_id"]').getByText('shop_id').click(); - await getProfilerInfo; - - await expect(page.locator('#count_graph')).toBeVisible(); - await expect(page.locator('#proportion_graph')).toBeVisible(); - await expect(page.locator('#math_graph')).toBeVisible(); - await expect(page.locator('#sum_graph')).toBeVisible(); - - await page - .getByRole('menuitem', { - name: 'Data Quality', - }) - .click(); - - await page.waitForSelector( - `[data-testid="${DATA_QUALITY_TABLE.testCaseName}"]` - ); - const getTestCaseDetails = page.waitForResponse( - '/api/v1/dataQuality/testCases/name/*?fields=*' - ); - const getTestResult = page.waitForResponse( - '/api/v1/dataQuality/testCases/*/testCaseResult?*' - ); - await page - .locator(`[data-testid="${DATA_QUALITY_TABLE.testCaseName}"]`) - .getByText(DATA_QUALITY_TABLE.testCaseName) - .click(); - - await getTestCaseDetails; - await getTestResult; - - await expect( - page.locator(`#${DATA_QUALITY_TABLE.testCaseName}_graph`) - ).toBeVisible(); -}); - -test('TestCase with Array params value', async ({ page }) => { - test.slow(); - - const testCase = table2.testCasesResponseData[0]; - const testCaseName = testCase?.['name']; - await visitDataQualityTab(page, table2); +test( + 'Profiler matrix and test case graph should visible', + PLAYWRIGHT_INGESTION_TAG_OBJ, + async ({ page }) => { + const DATA_QUALITY_TABLE = { + term: 'dim_address', + serviceName: 'sample_data', + testCaseName: 'column_value_max_to_be_between', + }; + + await visitEntityPage({ + page, + searchTerm: DATA_QUALITY_TABLE.term, + dataTestId: `${DATA_QUALITY_TABLE.serviceName}-${DATA_QUALITY_TABLE.term}`, + }); + await page.waitForSelector(`[data-testid="entity-header-display-name"]`); - await test.step( - 'Array params value should be visible while editing the test case', - async () => { - await expect( - page.locator(`[data-testid="${testCaseName}"]`) - ).toBeVisible(); - await expect( - page.locator(`[data-testid="edit-${testCaseName}"]`) - ).toBeVisible(); + await expect( + page.locator(`[data-testid="entity-header-display-name"]`) + ).toContainText(DATA_QUALITY_TABLE.term); - await page.click(`[data-testid="edit-${testCaseName}"]`); + const profilerResponse = page.waitForResponse( + `/api/v1/tables/*/tableProfile/latest` + ); + await page.click('[data-testid="profiler"]'); + await profilerResponse; + await page.waitForTimeout(1000); + await page + .getByRole('menuitem', { + name: 'Column Profile', + }) + .click(); + const getProfilerInfo = page.waitForResponse( + '/api/v1/tables/*/columnProfile?*' + ); + await page.locator('[data-row-key="shop_id"]').getByText('shop_id').click(); + await getProfilerInfo; - await expect( - page.locator('#tableTestForm_params_allowedValues_0_value') - ).toHaveValue('gmail'); - await expect( - page.locator('#tableTestForm_params_allowedValues_1_value') - ).toHaveValue('yahoo'); - await expect( - page.locator('#tableTestForm_params_allowedValues_2_value') - ).toHaveValue('collate'); - } - ); + await expect(page.locator('#count_graph')).toBeVisible(); + await expect(page.locator('#proportion_graph')).toBeVisible(); + await expect(page.locator('#math_graph')).toBeVisible(); + await expect(page.locator('#sum_graph')).toBeVisible(); - await test.step('Validate patch request for edit test case', async () => { - await page.fill( - '#tableTestForm_displayName', - 'Table test case display name' - ); + await page + .getByRole('menuitem', { + name: 'Data Quality', + }) + .click(); - await expect(page.locator('#tableTestForm_table')).toHaveValue( - table2.entityResponseData?.['name'] - ); - await expect(page.locator('#tableTestForm_column')).toHaveValue('email'); - await expect(page.locator('#tableTestForm_name')).toHaveValue(testCaseName); - await expect(page.locator('#tableTestForm_testDefinition')).toHaveValue( - 'Column Values To Be In Set' + await page.waitForSelector( + `[data-testid="${DATA_QUALITY_TABLE.testCaseName}"]` ); - - // Edit test case display name - const updateTestCaseResponse = page.waitForResponse( - (response) => - response.url().includes('/api/v1/dataQuality/testCases/') && - response.request().method() === 'PATCH' - ); - await page.click('.ant-modal-footer >> text=Submit'); - const updateResponse1 = await updateTestCaseResponse; - const body1 = await updateResponse1.request().postData(); - - expect(body1).toEqual( - JSON.stringify([ - { - op: 'add', - path: '/displayName', - value: 'Table test case display name', - }, - ]) + const getTestCaseDetails = page.waitForResponse( + '/api/v1/dataQuality/testCases/name/*?fields=*' ); - - // Edit test case description - await page.click(`[data-testid="edit-${testCaseName}"]`); - await page.fill(descriptionBox, 'Test case description'); - const updateTestCaseResponse2 = page.waitForResponse( - (response) => - response.url().includes('/api/v1/dataQuality/testCases/') && - response.request().method() === 'PATCH' + const getTestResult = page.waitForResponse( + '/api/v1/dataQuality/testCases/*/testCaseResult?*' ); - await page.click('.ant-modal-footer >> text=Submit'); - const updateResponse2 = await updateTestCaseResponse2; - const body2 = await updateResponse2.request().postData(); + await page + .locator(`[data-testid="${DATA_QUALITY_TABLE.testCaseName}"]`) + .getByText(DATA_QUALITY_TABLE.testCaseName) + .click(); - expect(body2).toEqual( - JSON.stringify([ - { op: 'add', path: '/description', value: 'Test case description' }, - ]) - ); + await getTestCaseDetails; + await getTestResult; - // Edit test case parameter values - await page.click(`[data-testid="edit-${testCaseName}"]`); - await page.fill('#tableTestForm_params_allowedValues_0_value', 'test'); - const updateTestCaseResponse3 = page.waitForResponse( - (response) => - response.url().includes('/api/v1/dataQuality/testCases/') && - response.request().method() === 'PATCH' - ); - await page.click('.ant-modal-footer >> text=Submit'); - const updateResponse3 = await updateTestCaseResponse3; - const body3 = await updateResponse3.request().postData(); - - expect(body3).toEqual( - JSON.stringify([ - { - op: 'replace', - path: '/parameterValues/0/value', - value: '["test","yahoo","collate"]', - }, - ]) + await expect( + page.locator(`#${DATA_QUALITY_TABLE.testCaseName}_graph`) + ).toBeVisible(); + } +); + +test( + 'TestCase with Array params value', + PLAYWRIGHT_INGESTION_TAG_OBJ, + async ({ page }) => { + test.slow(); + + const testCase = table2.testCasesResponseData[0]; + const testCaseName = testCase?.['name']; + await visitDataQualityTab(page, table2); + + await test.step( + 'Array params value should be visible while editing the test case', + async () => { + await expect( + page.locator(`[data-testid="${testCaseName}"]`) + ).toBeVisible(); + await expect( + page.locator(`[data-testid="edit-${testCaseName}"]`) + ).toBeVisible(); + + await page.click(`[data-testid="edit-${testCaseName}"]`); + + await expect( + page.locator('#tableTestForm_params_allowedValues_0_value') + ).toHaveValue('gmail'); + await expect( + page.locator('#tableTestForm_params_allowedValues_1_value') + ).toHaveValue('yahoo'); + await expect( + page.locator('#tableTestForm_params_allowedValues_2_value') + ).toHaveValue('collate'); + } ); - }); - await test.step( - 'Update test case display name from Data Quality page', - async () => { - const getTestCase = page.waitForResponse( - '/api/v1/dataQuality/testCases/search/list?*' + await test.step('Validate patch request for edit test case', async () => { + await page.fill( + '#tableTestForm_displayName', + 'Table test case display name' ); - await sidebarClick(page, SidebarItem.DATA_QUALITY); - await page.click('[data-testid="by-test-cases"]'); - await getTestCase; - const searchTestCaseResponse = page.waitForResponse( - `/api/v1/dataQuality/testCases/search/list?*q=*${testCaseName}*` + + await expect(page.locator('#tableTestForm_table')).toHaveValue( + table2.entityResponseData?.['name'] ); - await page.fill( - '[data-testid="test-case-container"] [data-testid="searchbar"]', + await expect(page.locator('#tableTestForm_column')).toHaveValue('email'); + await expect(page.locator('#tableTestForm_name')).toHaveValue( testCaseName ); - await searchTestCaseResponse; - await page.waitForSelector('.ant-spin', { - state: 'detached', - }); - await page.click(`[data-testid="edit-${testCaseName}"]`); - await page.waitForSelector('.ant-modal-title'); - - await expect(page.locator('#tableTestForm_displayName')).toHaveValue( - 'Table test case display name' + await expect(page.locator('#tableTestForm_testDefinition')).toHaveValue( + 'Column Values To Be In Set' ); - await page.locator('#tableTestForm_displayName').clear(); - await page.fill('#tableTestForm_displayName', 'Updated display name'); + // Edit test case display name + const updateTestCaseResponse = page.waitForResponse( + (response) => + response.url().includes('/api/v1/dataQuality/testCases/') && + response.request().method() === 'PATCH' + ); await page.click('.ant-modal-footer >> text=Submit'); - await toastNotification(page, 'Test case updated successfully.'); + const updateResponse1 = await updateTestCaseResponse; + const body1 = await updateResponse1.request().postData(); + + expect(body1).toEqual( + JSON.stringify([ + { + op: 'add', + path: '/displayName', + value: 'Table test case display name', + }, + ]) + ); - await expect(page.locator(`[data-testid="${testCaseName}"]`)).toHaveText( - 'Updated display name' + // Edit test case description + await page.click(`[data-testid="edit-${testCaseName}"]`); + await page.fill(descriptionBox, 'Test case description'); + const updateTestCaseResponse2 = page.waitForResponse( + (response) => + response.url().includes('/api/v1/dataQuality/testCases/') && + response.request().method() === 'PATCH' ); - } - ); -}); + await page.click('.ant-modal-footer >> text=Submit'); + const updateResponse2 = await updateTestCaseResponse2; + const body2 = await updateResponse2.request().postData(); -test('Update profiler setting modal', async ({ page }) => { - const profilerSetting = { - profileSample: '60', - sampleDataCount: '100', - profileQuery: 'select * from table', - excludeColumns: 'user_id', - includeColumns: 'shop_id', - partitionColumnName: 'name', - partitionIntervalType: 'COLUMN-VALUE', - partitionValues: 'test', - }; + expect(body2).toEqual( + JSON.stringify([ + { op: 'add', path: '/description', value: 'Test case description' }, + ]) + ); - await table1.visitEntityPage(page); - await page.getByTestId('profiler').click(); - await page - .getByTestId('profiler-tab-left-panel') - .getByText('Table Profile') - .click(); - - await page.click('[data-testid="profiler-setting-btn"]'); - await page.waitForSelector('.ant-modal-body'); - await page.locator('[data-testid="slider-input"]').clear(); - await page - .locator('[data-testid="slider-input"]') - .fill(profilerSetting.profileSample); - - await page.locator('[data-testid="sample-data-count-input"]').clear(); - await page - .locator('[data-testid="sample-data-count-input"]') - .fill(profilerSetting.sampleDataCount); - await page.locator('[data-testid="exclude-column-select"]').click(); - await page.keyboard.type(`${profilerSetting.excludeColumns}`); - await page.keyboard.press('Enter'); - await page.locator('.CodeMirror-scroll').click(); - await page.keyboard.type(profilerSetting.profileQuery); - - await page.locator('[data-testid="include-column-select"]').click(); - await page - .locator('.ant-select-dropdown') - .locator( - `[title="${profilerSetting.includeColumns}"]:not(.ant-select-dropdown-hidden)` - ) - .last() - .click(); - await page.locator('[data-testid="enable-partition-switch"]').click(); - await page.locator('[data-testid="interval-type"]').click(); - await page - .locator('.ant-select-dropdown') - .locator( - `[title="${profilerSetting.partitionIntervalType}"]:not(.ant-select-dropdown-hidden)` - ) - .click(); - - await page.locator('#includeColumnsProfiler_partitionColumnName').click(); - await page - .locator('.ant-select-dropdown') - .locator( - `[title="${profilerSetting.partitionColumnName}"]:not(.ant-select-dropdown-hidden)` - ) - .last() - .click(); - await page - .locator('[data-testid="partition-value"]') - .fill(profilerSetting.partitionValues); - - const updateTableProfilerConfigResponse = page.waitForResponse( - (response) => - response.url().includes('/api/v1/tables/') && - response.url().includes('/tableProfilerConfig') && - response.request().method() === 'PUT' - ); - await page.getByRole('button', { name: 'Save' }).click(); - const updateResponse = await updateTableProfilerConfigResponse; - const requestBody = await updateResponse.request().postData(); + // Edit test case parameter values + await page.click(`[data-testid="edit-${testCaseName}"]`); + await page.fill('#tableTestForm_params_allowedValues_0_value', 'test'); + const updateTestCaseResponse3 = page.waitForResponse( + (response) => + response.url().includes('/api/v1/dataQuality/testCases/') && + response.request().method() === 'PATCH' + ); + await page.click('.ant-modal-footer >> text=Submit'); + const updateResponse3 = await updateTestCaseResponse3; + const body3 = await updateResponse3.request().postData(); + + expect(body3).toEqual( + JSON.stringify([ + { + op: 'replace', + path: '/parameterValues/0/value', + value: '["test","yahoo","collate"]', + }, + ]) + ); + }); - expect(requestBody).toEqual( - JSON.stringify({ - excludeColumns: ['user_id'], + await test.step( + 'Update test case display name from Data Quality page', + async () => { + const getTestCase = page.waitForResponse( + '/api/v1/dataQuality/testCases/search/list?*' + ); + await sidebarClick(page, SidebarItem.DATA_QUALITY); + await page.click('[data-testid="by-test-cases"]'); + await getTestCase; + const searchTestCaseResponse = page.waitForResponse( + `/api/v1/dataQuality/testCases/search/list?*q=*${testCaseName}*` + ); + await page.fill( + '[data-testid="test-case-container"] [data-testid="searchbar"]', + testCaseName + ); + await searchTestCaseResponse; + await page.waitForSelector('.ant-spin', { + state: 'detached', + }); + await page.click(`[data-testid="edit-${testCaseName}"]`); + await page.waitForSelector('.ant-modal-title'); + + await expect(page.locator('#tableTestForm_displayName')).toHaveValue( + 'Table test case display name' + ); + + await page.locator('#tableTestForm_displayName').clear(); + await page.fill('#tableTestForm_displayName', 'Updated display name'); + await page.click('.ant-modal-footer >> text=Submit'); + await toastNotification(page, 'Test case updated successfully.'); + + await expect( + page.locator(`[data-testid="${testCaseName}"]`) + ).toHaveText('Updated display name'); + } + ); + } +); + +test( + 'Update profiler setting modal', + PLAYWRIGHT_INGESTION_TAG_OBJ, + async ({ page }) => { + const profilerSetting = { + profileSample: '60', + sampleDataCount: '100', profileQuery: 'select * from table', - profileSample: 60, - profileSampleType: 'PERCENTAGE', - includeColumns: [{ columnName: 'shop_id' }], - partitioning: { - partitionColumnName: 'name', - partitionIntervalType: 'COLUMN-VALUE', - partitionValues: ['test'], - enablePartitioning: true, - }, - sampleDataCount: 100, - }) - ); -}); + excludeColumns: 'user_id', + includeColumns: 'shop_id', + partitionColumnName: 'name', + partitionIntervalType: 'COLUMN-VALUE', + partitionValues: 'test', + }; + + await table1.visitEntityPage(page); + await page.getByTestId('profiler').click(); + await page + .getByTestId('profiler-tab-left-panel') + .getByText('Table Profile') + .click(); + + await page.click('[data-testid="profiler-setting-btn"]'); + await page.waitForSelector('.ant-modal-body'); + await page.locator('[data-testid="slider-input"]').clear(); + await page + .locator('[data-testid="slider-input"]') + .fill(profilerSetting.profileSample); + + await page.locator('[data-testid="sample-data-count-input"]').clear(); + await page + .locator('[data-testid="sample-data-count-input"]') + .fill(profilerSetting.sampleDataCount); + await page.locator('[data-testid="exclude-column-select"]').click(); + await page.keyboard.type(`${profilerSetting.excludeColumns}`); + await page.keyboard.press('Enter'); + await page.locator('.CodeMirror-scroll').click(); + await page.keyboard.type(profilerSetting.profileQuery); + + await page.locator('[data-testid="include-column-select"]').click(); + await page + .locator('.ant-select-dropdown') + .locator( + `[title="${profilerSetting.includeColumns}"]:not(.ant-select-dropdown-hidden)` + ) + .last() + .click(); + await page.locator('[data-testid="enable-partition-switch"]').click(); + await page.locator('[data-testid="interval-type"]').click(); + await page + .locator('.ant-select-dropdown') + .locator( + `[title="${profilerSetting.partitionIntervalType}"]:not(.ant-select-dropdown-hidden)` + ) + .click(); + + await page.locator('#includeColumnsProfiler_partitionColumnName').click(); + await page + .locator('.ant-select-dropdown') + .locator( + `[title="${profilerSetting.partitionColumnName}"]:not(.ant-select-dropdown-hidden)` + ) + .last() + .click(); + await page + .locator('[data-testid="partition-value"]') + .fill(profilerSetting.partitionValues); + + const updateTableProfilerConfigResponse = page.waitForResponse( + (response) => + response.url().includes('/api/v1/tables/') && + response.url().includes('/tableProfilerConfig') && + response.request().method() === 'PUT' + ); + await page.getByRole('button', { name: 'Save' }).click(); + const updateResponse = await updateTableProfilerConfigResponse; + const requestBody = await updateResponse.request().postData(); + + expect(requestBody).toEqual( + JSON.stringify({ + excludeColumns: ['user_id'], + profileQuery: 'select * from table', + profileSample: 60, + profileSampleType: 'PERCENTAGE', + includeColumns: [{ columnName: 'shop_id' }], + partitioning: { + partitionColumnName: 'name', + partitionIntervalType: 'COLUMN-VALUE', + partitionValues: ['test'], + enablePartitioning: true, + }, + sampleDataCount: 100, + }) + ); + } +); -test('TestCase filters', async ({ page }) => { +test('TestCase filters', PLAYWRIGHT_INGESTION_TAG_OBJ, async ({ page }) => { test.setTimeout(360000); const { apiContext, afterAction } = await getApiContext(page); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/ServiceIngestion.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/ServiceIngestion.spec.ts index ff873b49b520..2bfecbae4ec9 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/ServiceIngestion.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/ServiceIngestion.spec.ts @@ -12,6 +12,7 @@ */ import test, { expect } from '@playwright/test'; +import { PLAYWRIGHT_INGESTION_TAG_OBJ } from '../../constant/config'; import { MYSQL, POSTGRES, REDSHIFT } from '../../constant/service'; import { GlobalSettingOptions } from '../../constant/settings'; import AirflowIngestionClass from '../../support/entity/ingestion/AirflowIngestionClass'; @@ -60,43 +61,49 @@ services.forEach((ServiceClass) => { timeout: 11 * 60 * 1000, }); - test.describe.serial(service.serviceType, { tag: '@ingestion' }, async () => { - test.beforeEach('Visit entity details page', async ({ page }) => { - await redirectToHomePage(page); - await settingClick( + test.describe.serial( + service.serviceType, + PLAYWRIGHT_INGESTION_TAG_OBJ, + async () => { + test.beforeEach('Visit entity details page', async ({ page }) => { + await redirectToHomePage(page); + await settingClick( + page, + service.category as unknown as SettingOptionsType + ); + }); + + test(`Create & Ingest ${service.serviceType} service`, async ({ page, - service.category as unknown as SettingOptionsType - ); - }); - - test(`Create & Ingest ${service.serviceType} service`, async ({ page }) => { - await service.createService(page); - }); - - test(`Update description and verify description after re-run`, async ({ - page, - }) => { - await service.updateService(page); - }); - - test(`Update schedule options and verify`, async ({ page }) => { - await service.updateScheduleOptions(page); - }); - - if ( - [POSTGRES.serviceType, REDSHIFT.serviceType, MYSQL].includes( - service.serviceType - ) - ) { - test(`Service specific tests`, async ({ page }) => { - await service.runAdditionalTests(page, test); + }) => { + await service.createService(page); }); - } - test(`Delete ${service.serviceType} service`, async ({ page }) => { - await service.deleteService(page); - }); - }); + test(`Update description and verify description after re-run`, async ({ + page, + }) => { + await service.updateService(page); + }); + + test(`Update schedule options and verify`, async ({ page }) => { + await service.updateScheduleOptions(page); + }); + + if ( + [POSTGRES.serviceType, REDSHIFT.serviceType, MYSQL].includes( + service.serviceType + ) + ) { + test(`Service specific tests`, async ({ page }) => { + await service.runAdditionalTests(page, test); + }); + } + + test(`Delete ${service.serviceType} service`, async ({ page }) => { + await service.deleteService(page); + }); + } + ); }); test.describe('Service form', () => {