From fc4f955b9f59767a39e67be7b146da757fd3e747 Mon Sep 17 00:00:00 2001 From: Shailesh Parmar Date: Fri, 19 May 2023 10:37:40 +0530 Subject: [PATCH] Cypress: Added cypress test for update display name feature and delete service issue (#11643) * Cypress: Added cypress test for update display name feature and delete service issue * cypress for datamodel * rename cypress file * improve test for update displayName --- .../resources/ui/cypress/common/common.js | 19 +- .../ui/cypress/common/serviceUtils.js | 64 +++++ .../ui/cypress/constants/constants.js | 1 + .../constants/updateDisplayName.constant.js | 125 +++++++++ .../e2e/Features/updateDisplayName.spec.js | 256 ++++++++++++++++++ ...er.js => AddAndRemoveTierAndOwner.spec.js} | 0 .../EntityNameModal.component.tsx | 6 +- 7 files changed, 459 insertions(+), 12 deletions(-) create mode 100644 openmetadata-ui/src/main/resources/ui/cypress/common/serviceUtils.js create mode 100644 openmetadata-ui/src/main/resources/ui/cypress/constants/updateDisplayName.constant.js create mode 100644 openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/updateDisplayName.spec.js rename openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/{AddAndRemoveTierAndOwner.js => AddAndRemoveTierAndOwner.spec.js} (100%) diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/common.js b/openmetadata-ui/src/main/resources/ui/cypress/common/common.js index 4894fb01ff4..122c94d2a67 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/common/common.js +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/common.js @@ -564,7 +564,12 @@ export const searchEntity = (term, suggestionOverly = true) => { } }; -export const visitEntityDetailsPage = (term, serviceName, entity) => { +export const visitEntityDetailsPage = ( + term, + serviceName, + entity, + dataTestId +) => { interceptURL('GET', '/api/v1/*/name/*', 'getEntityDetails'); interceptURL( 'GET', @@ -573,7 +578,7 @@ export const visitEntityDetailsPage = (term, serviceName, entity) => { ); interceptURL('GET', `/api/v1/search/suggest?q=*&index=*`, 'searchQuery'); interceptURL('GET', `/api/v1/search/*`, 'explorePageSearch'); - + const id = dataTestId ?? `${serviceName}-${term}`; // searching term in search box cy.get('[data-testid="searchBox"]').scrollIntoView().should('be.visible'); cy.get('[data-testid="searchBox"]').type(term); @@ -581,13 +586,9 @@ export const visitEntityDetailsPage = (term, serviceName, entity) => { cy.get('[data-testid="suggestion-overlay"]').should('exist'); cy.get('body').then(($body) => { // checking if requested term is available in search suggestion - if ( - $body.find( - `[data-testid="${serviceName}-${term}"] [data-testid="data-name"]` - ).length - ) { + if ($body.find(`[data-testid="${id}"] [data-testid="data-name"]`).length) { // if term is available in search suggestion, redirecting to entity details page - cy.get(`[data-testid="${serviceName}-${term}"] [data-testid="data-name"]`) + cy.get(`[data-testid="${id}"] [data-testid="data-name"]`) .should('be.visible') .first() .click(); @@ -601,7 +602,7 @@ export const visitEntityDetailsPage = (term, serviceName, entity) => { cy.get(`[data-testid="${entity}-tab"]`).should('be.visible'); verifyResponseStatusCode('@explorePageTabSearch', 200); - cy.get(`[data-testid="${serviceName}-${term}"]`) + cy.get(`[data-testid="${id}"]`) .scrollIntoView() .should('be.visible') .click(); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/serviceUtils.js b/openmetadata-ui/src/main/resources/ui/cypress/common/serviceUtils.js new file mode 100644 index 00000000000..d2fcf0bd662 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/serviceUtils.js @@ -0,0 +1,64 @@ +/* + * 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 { interceptURL, verifyResponseStatusCode } from './common'; + +export const visitServiceDetailsPage = (service, verifyHeader = true) => { + // Click on settings page + interceptURL( + 'GET', + 'api/v1/teams/name/Organization?fields=*', + 'getSettingsPage' + ); + cy.get('[data-testid="appbar-item-settings"]').should('be.visible').click(); + verifyResponseStatusCode('@getSettingsPage', 200); + // Services page + interceptURL('GET', '/api/v1/services/*', 'getServices'); + + cy.get('.ant-menu-title-content') + .contains(service.type) + .should('be.visible') + .click(); + + verifyResponseStatusCode('@getServices', 200); + + // click on created service + cy.get(`[data-testid="service-name-${service.name}"]`) + .should('exist') + .should('be.visible') + .click(); + + if (verifyHeader) { + cy.get(`[data-testid="entity-header-name"]`) + .should('exist') + .should('be.visible') + .invoke('text') + .then((text) => { + expect(text).to.equal(service.name); + }); + } + + verifyResponseStatusCode('@getServices', 200); +}; + +export const createDataWithApi = (data, token) => { + data.map(({ method, url, body }) => { + cy.request({ + method, + url, + auth: { + bearer: token, + }, + body, + }); + }); +}; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/constants/constants.js b/openmetadata-ui/src/main/resources/ui/cypress/constants/constants.js index 4ab7b226ce9..5864ba192d1 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/constants/constants.js +++ b/openmetadata-ui/src/main/resources/ui/cypress/constants/constants.js @@ -295,6 +295,7 @@ export const SERVICE_TYPE = { Dashboard: 'Dashboard', Pipelines: 'Pipelines', MLModels: 'ML Models', + Storage: 'Storages', }; export const ENTITIES = { diff --git a/openmetadata-ui/src/main/resources/ui/cypress/constants/updateDisplayName.constant.js b/openmetadata-ui/src/main/resources/ui/cypress/constants/updateDisplayName.constant.js new file mode 100644 index 00000000000..2d78b3b585b --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/cypress/constants/updateDisplayName.constant.js @@ -0,0 +1,125 @@ +/* + * 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 { MYDATA_SUMMARY_OPTIONS, SERVICE_TYPE } from './constants'; + +export const SERVICES = { + databaseServices: { + type: SERVICE_TYPE.Database, + name: 'sample_data', + displayName: 'Sample Data', + }, + messagingServices: { + type: SERVICE_TYPE.Messaging, + name: 'sample_kafka', + displayName: 'Sample Kafka', + }, + dashboardServices: { + type: SERVICE_TYPE.Dashboard, + name: 'sample_looker', + displayName: 'Sample Looker', + }, + pipelineServices: { + type: SERVICE_TYPE.Pipelines, + name: 'sample_airflow', + displayName: 'Sample Airflow', + }, + mlmodelServices: { + type: SERVICE_TYPE.MLModels, + name: 'mlflow_svc', + displayName: 'ML Flow Service', + }, + storageServices: { + type: SERVICE_TYPE.Storage, + name: 's3_storage_sample', + displayName: 'Storage Sample Service', + }, +}; + +const DB_SERVICE = SERVICES.databaseServices.name; +const DATABASE_AND_SCHEMA = { + schema: 'shopify', + schemaDisplayName: 'Shopify Schema', + database: 'ecommerce_db', + databaseDisplayName: 'E-Commerce Database', +}; + +export const ENTITIES_DISPLAY_NAME = { + table: { + name: 'dim(shop)', + oldDisplayName: 'dim(shop)', + displayName: 'Dim Shop Test', + entity: MYDATA_SUMMARY_OPTIONS.tables, + serviceName: DB_SERVICE, + breadcrumb: [ + DATABASE_AND_SCHEMA.schemaDisplayName, + DATABASE_AND_SCHEMA.databaseDisplayName, + SERVICES.databaseServices.displayName, + ], + }, + topic: { + name: 'address_book', + oldDisplayName: 'address_book', + displayName: 'Kafka Address Book', + entity: MYDATA_SUMMARY_OPTIONS.topics, + serviceName: SERVICES.messagingServices.name, + breadcrumb: [SERVICES.messagingServices.displayName], + }, + dashboard: { + name: 'Customers dashboard', + oldDisplayName: 'Customers dashboard', + displayName: 'Looker Customers Dashboard', + entity: MYDATA_SUMMARY_OPTIONS.dashboards, + serviceName: SERVICES.dashboardServices.name, + breadcrumb: [SERVICES.dashboardServices.displayName], + }, + pipeline: { + name: 'dim_address_etl', + oldDisplayName: 'dim_address_etl', + displayName: 'Dim Address ETL', + entity: MYDATA_SUMMARY_OPTIONS.pipelines, + serviceName: SERVICES.pipelineServices.name, + breadcrumb: [SERVICES.pipelineServices.displayName], + }, + mlmodel: { + name: 'eta_predictions', + oldDisplayName: 'ETA Predictions', + displayName: 'Predictions ETA', + entity: MYDATA_SUMMARY_OPTIONS.mlmodels, + serviceName: SERVICES.mlmodelServices.name, + breadcrumb: [SERVICES.mlmodelServices.displayName], + }, + container: { + name: 'departments', + oldDisplayName: 'Company departments', + displayName: 'Company Departments Test', + entity: MYDATA_SUMMARY_OPTIONS.containers, + serviceName: SERVICES.storageServices.name, + breadcrumb: [SERVICES.storageServices.displayName], + }, +}; +export const DASHBOARD_DATA_MODEL = { + service: SERVICES.dashboardServices, + name: 'Operations View', + displayName: 'Operations View Dashboard', + breadcrumb: [SERVICES.dashboardServices.displayName], +}; + +export const SCHEMA_AND_DATABASE_DISPLAY_NAME = { + ...ENTITIES_DISPLAY_NAME.table, + ...DATABASE_AND_SCHEMA, + schemaBreadcrumb: [ + DATABASE_AND_SCHEMA.databaseDisplayName, + SERVICES.databaseServices.displayName, + ], + databaseBreadcrumb: [SERVICES.databaseServices.displayName], +}; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/updateDisplayName.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/updateDisplayName.spec.js new file mode 100644 index 00000000000..678e2a366dd --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/updateDisplayName.spec.js @@ -0,0 +1,256 @@ +/* + * 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 { + interceptURL, + verifyResponseStatusCode, + visitEntityDetailsPage, +} from '../../common/common'; +import { visitServiceDetailsPage } from '../../common/serviceUtils'; +import { MYDATA_SUMMARY_OPTIONS } from '../../constants/constants'; +import { + DASHBOARD_DATA_MODEL, + ENTITIES_DISPLAY_NAME, + SCHEMA_AND_DATABASE_DISPLAY_NAME, + SERVICES, +} from '../../constants/updateDisplayName.constant'; + +const updateDisplayName = (displayName, apiPath) => { + if (apiPath) { + interceptURL('PATCH', apiPath, 'patchDisplayName'); + } + cy.get('[data-testid="manage-button"]') + .should('exist') + .should('be.visible') + .click(); + + cy.get('[data-menu-id*="delete-button"]') + .should('exist') + .should('be.visible'); + cy.get('[data-testid="rename-button"]').should('be.visible').click(); + + cy.get('#name').should('be.visible').should('be.disabled'); + cy.get('#displayName').should('be.visible').should('not.be.disabled').clear(); + cy.get('.ant-modal-footer').should('contain', 'Cancel'); + cy.get('[data-testid="save-button"]').should('be.visible').click(); + cy.get('.ant-modal-body').should('contain', 'Display Name is required'); + cy.get('#displayName').type(displayName); + cy.get('[data-testid="save-button"]').should('be.visible').click(); + + if (apiPath) { + verifyResponseStatusCode('@patchDisplayName', 200); + } + + cy.get('[data-testid="entity-header-display-name"]').should( + 'contain', + displayName + ); +}; + +describe('Edit displayName for all the entities, services and verify breadcrumb', () => { + beforeEach(() => { + cy.login(); + }); + + Object.entries(SERVICES).map(([serviceType, service]) => { + it(`${service.type}`, () => { + visitServiceDetailsPage(service); + updateDisplayName( + service.displayName, + `/api/v1/services/${serviceType}/*` + ); + }); + }); + + it(`dataModel`, () => { + interceptURL( + 'GET', + '/api/v1/dashboard/datamodels?service=*', + 'dashboardDataModel' + ); + interceptURL( + 'GET', + '/api/v1/dashboard/datamodels/name/*', + 'dataModelDetails' + ); + visitServiceDetailsPage( + { + type: DASHBOARD_DATA_MODEL.service.type, + name: DASHBOARD_DATA_MODEL.service.displayName, + }, + false + ); + verifyResponseStatusCode('@dashboardDataModel', 200); + cy.get('[data-testid="Data Model"]').should('be.visible').click(); + cy.get('[data-testid="data-models-table"]') + .contains(DASHBOARD_DATA_MODEL.name) + .click(); + verifyResponseStatusCode('@dataModelDetails', 200); + updateDisplayName( + DASHBOARD_DATA_MODEL.displayName, + `/api/v1/dashboard/datamodels/*` + ); + DASHBOARD_DATA_MODEL.breadcrumb.map((value) => { + cy.get('[data-testid="breadcrumb"]').should('contain', value); + }); + }); + + it(`database`, () => { + interceptURL('GET', 'api/v1/databases/name/*', 'database'); + visitEntityDetailsPage( + SCHEMA_AND_DATABASE_DISPLAY_NAME.name, + SCHEMA_AND_DATABASE_DISPLAY_NAME.serviceName, + SCHEMA_AND_DATABASE_DISPLAY_NAME.entity + ); + cy.get('[data-testid="breadcrumb"]') + .contains(SCHEMA_AND_DATABASE_DISPLAY_NAME.database) + .click(); + verifyResponseStatusCode('@database', 200); + updateDisplayName( + SCHEMA_AND_DATABASE_DISPLAY_NAME.databaseDisplayName, + `/api/v1/databases/*` + ); + SCHEMA_AND_DATABASE_DISPLAY_NAME.databaseBreadcrumb.map((value) => { + cy.get('[data-testid="breadcrumb"]').should('contain', value); + }); + }); + + it(`databaseSchema`, () => { + interceptURL('GET', 'api/v1/databaseSchemas/name/*', 'databaseSchemas'); + visitEntityDetailsPage( + SCHEMA_AND_DATABASE_DISPLAY_NAME.name, + SCHEMA_AND_DATABASE_DISPLAY_NAME.serviceName, + SCHEMA_AND_DATABASE_DISPLAY_NAME.entity + ); + cy.get('[data-testid="breadcrumb"]') + .contains(SCHEMA_AND_DATABASE_DISPLAY_NAME.schema) + .click(); + verifyResponseStatusCode('@databaseSchemas', 200); + updateDisplayName( + SCHEMA_AND_DATABASE_DISPLAY_NAME.schemaDisplayName, + `/api/v1/databaseSchemas/*` + ); + SCHEMA_AND_DATABASE_DISPLAY_NAME.schemaBreadcrumb.map((value) => { + cy.get('[data-testid="breadcrumb"]').should('contain', value); + }); + }); + + Object.values(ENTITIES_DISPLAY_NAME).map((entity) => { + it(`${entity.entity}`, () => { + visitEntityDetailsPage(entity.name, entity.serviceName, entity.entity); + updateDisplayName(entity.displayName, `/api/v1/${entity.entity}/*`); + entity.breadcrumb.map((value) => { + cy.get('[data-testid="breadcrumb"]').should('contain', value); + }); + }); + }); +}); + +describe('Cleanup', () => { + beforeEach(() => { + cy.login(); + }); + + Object.values(ENTITIES_DISPLAY_NAME).map((entity) => { + it(`${entity.entity}`, () => { + if (entity.entity === MYDATA_SUMMARY_OPTIONS.dashboards) { + visitEntityDetailsPage( + entity.displayName, + entity.serviceName, + entity.entity + ); + } else { + visitEntityDetailsPage(entity.name, entity.serviceName, entity.entity); + } + updateDisplayName(entity.oldDisplayName, `/api/v1/${entity.entity}/*`); + }); + }); + + it(`databaseSchema`, () => { + interceptURL('GET', 'api/v1/databaseSchemas/name/*', 'databaseSchemas'); + visitEntityDetailsPage( + SCHEMA_AND_DATABASE_DISPLAY_NAME.name, + SCHEMA_AND_DATABASE_DISPLAY_NAME.serviceName, + SCHEMA_AND_DATABASE_DISPLAY_NAME.entity + ); + cy.get('[data-testid="breadcrumb"]') + .contains(SCHEMA_AND_DATABASE_DISPLAY_NAME.schemaDisplayName) + .click(); + verifyResponseStatusCode('@databaseSchemas', 200); + updateDisplayName( + SCHEMA_AND_DATABASE_DISPLAY_NAME.schema, + `/api/v1/databaseSchemas/*` + ); + }); + + it(`database`, () => { + interceptURL('GET', 'api/v1/databases/name/*', 'database'); + visitEntityDetailsPage( + SCHEMA_AND_DATABASE_DISPLAY_NAME.name, + SCHEMA_AND_DATABASE_DISPLAY_NAME.serviceName, + SCHEMA_AND_DATABASE_DISPLAY_NAME.entity + ); + cy.get('[data-testid="breadcrumb"]') + .contains(SCHEMA_AND_DATABASE_DISPLAY_NAME.databaseDisplayName) + .click(); + verifyResponseStatusCode('@database', 200); + updateDisplayName( + SCHEMA_AND_DATABASE_DISPLAY_NAME.database, + `/api/v1/databases/*` + ); + }); + + it(`dataModel`, () => { + interceptURL( + 'GET', + '/api/v1/dashboard/datamodels?service=*', + 'dashboardDataModel' + ); + interceptURL( + 'GET', + '/api/v1/dashboard/datamodels/name/*', + 'dataModelDetails' + ); + visitServiceDetailsPage( + { + type: DASHBOARD_DATA_MODEL.service.type, + name: DASHBOARD_DATA_MODEL.service.displayName, + }, + false + ); + verifyResponseStatusCode('@dashboardDataModel', 200); + cy.get('[data-testid="Data Model"]').should('be.visible').click(); + cy.get('[data-testid="data-models-table"]') + .contains(DASHBOARD_DATA_MODEL.name) + .click(); + verifyResponseStatusCode('@dataModelDetails', 200); + updateDisplayName( + DASHBOARD_DATA_MODEL.displayName, + `/api/v1/dashboard/datamodels/*` + ); + }); + + Object.entries(SERVICES).map(([serviceType, service]) => { + it(`${service.type}`, () => { + visitServiceDetailsPage( + { + type: service.type, + name: service.displayName, + }, + false + ); + updateDisplayName(service.name, `/api/v1/services/${serviceType}/*`); + }); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/AddAndRemoveTierAndOwner.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/AddAndRemoveTierAndOwner.spec.js similarity index 100% rename from openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/AddAndRemoveTierAndOwner.js rename to openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/AddAndRemoveTierAndOwner.spec.js diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Modals/EntityNameModal/EntityNameModal.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Modals/EntityNameModal/EntityNameModal.component.tsx index 1103c8cc051..b2382512ada 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Modals/EntityNameModal/EntityNameModal.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Modals/EntityNameModal/EntityNameModal.component.tsx @@ -68,7 +68,7 @@ const EntityNameModal: React.FC = ({ onCancel={onCancel}>
= ({ />