From ae884d54def6763d615e8eb704766f410425e7ac Mon Sep 17 00:00:00 2001 From: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com> Date: Tue, 16 Jan 2024 16:38:40 +0530 Subject: [PATCH] test(e2e): organise ingestion tests (#14649) * test(e2e): organise ingestion tests * fix ingestion tests * push all the service ingestions * fix name regexp issue * fix database spec * aut fixes * fix follow entity tests * fix follow test case * fix soft delete tests * fix tests * fix dashboard * fix left side bar issue --- .../src/main/resources/ui/cypress.config.ts | 5 +- .../cypress/common/Entities/ContainerClass.ts | 4 + .../cypress/common/Entities/DatabaseClass.ts | 4 + .../common/Entities/DatabaseSchemaClass.ts | 4 + .../ui/cypress/common/Entities/EntityClass.ts | 11 + .../common/Entities/SearchIndexClass.ts | 4 + .../common/Entities/ServiceBaseClass.ts | 413 ++++++++++++++++++ .../common/Entities/StoredProcedureClass.ts | 4 + .../common/Services/AirflowIngestionClass.ts | 45 ++ .../common/Services/BigQueryIngestionClass.ts | 91 ++++ .../common/Services/KafkaIngestionClass.ts | 52 +++ .../common/Services/MetabaseIngestionClass.ts | 65 +++ .../common/Services/MlFlowIngestionClass.ts | 55 +++ .../common/Services/MysqlIngestionClass.ts | 52 +++ .../common/Services/S3IngestionClass.ts | 49 +++ .../Services/SnowflakeIngestionClass.ts | 52 +++ .../common/Services/SupersetIngestionClass.ts | 59 +++ .../ui/cypress/common/Utils/Entity.ts | 54 ++- .../ui/cypress/common/Utils/Glossary.ts | 3 +- .../ui/cypress/common/Utils/Services.ts | 206 +++++++++ .../ui/cypress/common/serviceUtils.js | 7 - .../ui/cypress/constants/Entity.interface.ts | 3 + .../cypress/e2e/Features/ActivityFeed.spec.js | 1 - .../ui/cypress/e2e/Features/Following.spec.js | 208 --------- .../cypress/e2e/Features/QueryEntity.spec.js | 1 - .../e2e/Features/RecentlyViewed.spec.js | 1 - .../ui/cypress/e2e/Pages/Database.spec.ts | 4 + .../ui/cypress/e2e/Pages/Entity.spec.ts | 6 +- .../ui/cypress/e2e/Service/Airflow.spec.js | 75 ---- .../ui/cypress/e2e/Service/MlFlow.spec.js | 67 --- .../ui/cypress/e2e/Service/S3Storage.spec.js | 84 ---- .../e2e/Service/ServiceIngestion.spec.ts | 55 +++ .../ui/cypress/e2e/Service/bigquery.spec.js | 113 ----- .../ui/cypress/e2e/Service/glue.spec.js | 90 ---- .../ui/cypress/e2e/Service/kafka.spec.js | 88 ---- .../ui/cypress/e2e/Service/metabase.spec.js | 92 ---- .../ui/cypress/e2e/Service/mysql.spec.js | 80 ---- .../ui/cypress/e2e/Service/snowflake.spec.js | 87 ---- .../ui/cypress/e2e/Service/superset.spec.js | 90 ---- .../resources/ui/cypress/support/commands.js | 1 + .../Entity/EntityList/EntityList.tsx | 4 +- .../ExploreV1/ExploreV1.component.tsx | 2 +- .../DatabaseDetailsPage.tsx | 1 + .../DatabaseSchemaPage/SchemaTablesTab.tsx | 2 +- .../pages/MyDataPage/MyDataPage.component.tsx | 2 +- .../StoredProcedurePage.test.tsx | 4 + .../StoredProcedure/StoredProcedurePage.tsx | 2 + .../resources/ui/src/utils/SearchClassBase.ts | 2 +- 48 files changed, 1295 insertions(+), 1109 deletions(-) create mode 100644 openmetadata-ui/src/main/resources/ui/cypress/common/Entities/ServiceBaseClass.ts create mode 100644 openmetadata-ui/src/main/resources/ui/cypress/common/Services/AirflowIngestionClass.ts create mode 100644 openmetadata-ui/src/main/resources/ui/cypress/common/Services/BigQueryIngestionClass.ts create mode 100644 openmetadata-ui/src/main/resources/ui/cypress/common/Services/KafkaIngestionClass.ts create mode 100644 openmetadata-ui/src/main/resources/ui/cypress/common/Services/MetabaseIngestionClass.ts create mode 100644 openmetadata-ui/src/main/resources/ui/cypress/common/Services/MlFlowIngestionClass.ts create mode 100644 openmetadata-ui/src/main/resources/ui/cypress/common/Services/MysqlIngestionClass.ts create mode 100644 openmetadata-ui/src/main/resources/ui/cypress/common/Services/S3IngestionClass.ts create mode 100644 openmetadata-ui/src/main/resources/ui/cypress/common/Services/SnowflakeIngestionClass.ts create mode 100644 openmetadata-ui/src/main/resources/ui/cypress/common/Services/SupersetIngestionClass.ts create mode 100644 openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Services.ts delete mode 100644 openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/Following.spec.js delete mode 100644 openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/Airflow.spec.js delete mode 100644 openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/MlFlow.spec.js delete mode 100644 openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/S3Storage.spec.js create mode 100644 openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/ServiceIngestion.spec.ts delete mode 100644 openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/bigquery.spec.js delete mode 100644 openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/glue.spec.js delete mode 100644 openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/kafka.spec.js delete mode 100644 openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/metabase.spec.js delete mode 100644 openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/mysql.spec.js delete mode 100644 openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/snowflake.spec.js delete mode 100644 openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/superset.spec.js diff --git a/openmetadata-ui/src/main/resources/ui/cypress.config.ts b/openmetadata-ui/src/main/resources/ui/cypress.config.ts index 46f1f95cc5e..420460ea248 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress.config.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress.config.ts @@ -29,9 +29,6 @@ export default defineConfig({ setupNodeEvents(on, config) { return plugins(on, config); }, - specPattern: [ - 'cypress/new-tests/**/*.spec.{js,jsx,ts,tsx}', - 'cypress/e2e/**/*.{js,jsx,ts,tsx}', - ], + specPattern: ['cypress/e2e/**/*.{js,jsx,ts,tsx}'], }, }); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/ContainerClass.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/ContainerClass.ts index cdcfeee022b..5030e19723d 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/ContainerClass.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/ContainerClass.ts @@ -35,6 +35,10 @@ class ContainerClass extends EntityClass { }); } + followUnfollowEntity() { + // Skiping this since not working from backend + } + // Creation createEntity() { diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/DatabaseClass.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/DatabaseClass.ts index 689224306df..c73d76c9943 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/DatabaseClass.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/DatabaseClass.ts @@ -50,6 +50,10 @@ class DatabaseClass extends EntityClass { verifyResponseStatusCode('@fetchDatabase', 200); } + followUnfollowEntity() { + // Skiping this since not supported for database + } + // Creation createEntity() { diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/DatabaseSchemaClass.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/DatabaseSchemaClass.ts index c235eeb5ccd..ddeb9a2d2e4 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/DatabaseSchemaClass.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/DatabaseSchemaClass.ts @@ -62,6 +62,10 @@ class DatabaseSchemaClass extends EntityClass { verifyResponseStatusCode('@fetchDatabaseSchema', 200); } + followUnfollowEntity() { + // Skiping this since not supported for database + } + // Creation createEntity() { diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/EntityClass.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/EntityClass.ts index 7b5f6d0aa59..eed12640789 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/EntityClass.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/EntityClass.ts @@ -32,10 +32,13 @@ import { createEntityViaREST, deleteEntity, deleteEntityViaREST, + followEntity, hardDeleteEntity as hardDeleteEntityUtil, restoreEntity as restoreEntityUtil, + unfollowEntity, updateDescriptioForEntity, updateDisplayNameForEntity, + validateFollowedEntityToWidget, } from '../Utils/Entity'; import { assignGlossaryTerm, @@ -468,6 +471,14 @@ class EntityClass { deleteAnnoucement(); } + followUnfollowEntity() { + followEntity(this.endPoint); + validateFollowedEntityToWidget(this.entityName, true); + this.visitEntity(); + unfollowEntity(this.endPoint); + validateFollowedEntityToWidget(this.entityName, false); + } + // Custom property setCustomProperty(propertydetails: CustomProperty, value: string) { diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/SearchIndexClass.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/SearchIndexClass.ts index 56dca468020..3115ce4313b 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/SearchIndexClass.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/SearchIndexClass.ts @@ -35,6 +35,10 @@ class SearchIndexClass extends EntityClass { }); } + followUnfollowEntity() { + // Skiping this since not working from backend + } + // Creation createEntity() { diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/ServiceBaseClass.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/ServiceBaseClass.ts new file mode 100644 index 00000000000..6941ff1d6d7 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/ServiceBaseClass.ts @@ -0,0 +1,413 @@ +/* + * 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. + */ +import { + INVALID_NAMES, + NAME_VALIDATION_ERROR, +} from '../../constants/constants'; +import { + interceptURL, + replaceAllSpacialCharWith_, + toastNotification, + verifyResponseStatusCode, +} from '../common'; +import { visitEntityDetailsPage } from '../Utils/Entity'; +import { + deleteService, + getEntityTypeFromService, + retryIngestionRun, + Services, + testConnection, +} from '../Utils/Services'; + +const RETRIES_COUNT = 4; +const RETRY_TIMES = 4; +const BASE_WAIT_TIME = 20000; + +export const descriptionBox = + '.toastui-editor-md-container > .toastui-editor > .ProseMirror'; + +class ServiceBaseClass { + public category: Services; + protected serviceName: string; + public serviceType: string; + protected entityName: string; + protected shouldTestConnection: boolean; + protected shouldAddIngestion: boolean; + + constructor( + category: Services, + name: string, + serviceType: string, + entity: string, + shouldTestConnection = true, + shouldAddIngestion = true + ) { + this.category = category; + this.serviceName = name; + this.serviceType = serviceType; + this.entityName = entity; + this.shouldTestConnection = shouldTestConnection; + this.shouldAddIngestion = shouldAddIngestion; + } + + visitService() { + // Handle visit service here + } + + createService() { + // Handle create service here + // intercept the service requirement md file fetch request + interceptURL( + 'GET', + `en-US/*/${this.serviceType}.md`, + 'getServiceRequirements' + ); + + cy.get('[data-testid="add-service-button"]').click(); + + // Select Service in step 1 + this.serviceSetp1(this.serviceType); + + // Enter service name in step 2 + this.serviceSetp2(this.serviceName); + + // Connection Details in step 3 + cy.get('[data-testid="add-new-service-container"]') + .parent() + .parent() + .scrollTo('top', { + ensureScrollable: false, + }); + cy.contains('Connection Details').scrollIntoView().should('be.visible'); + + // Requirement panel should be visible and fetch the requirements md file + cy.get('[data-testid="service-requirements"]').should('be.visible'); + verifyResponseStatusCode('@getServiceRequirements', [200, 304], {}, true); + + this.fillConnectionDetails(); + + this.shouldTestConnection && testConnection(); + + this.submitService(this.serviceName); + + this.shouldAddIngestion && this.addIngestionPipeline(this.serviceName); + } + + serviceSetp1(serviceType: string) { + // Storing the created service name and the type of service + // Select Service in step 1 + cy.get(`[data-testid="${serviceType}"]`).click(); + cy.get('[data-testid="next-button"]').click(); + } + + serviceSetp2(serviceName: string) { + // validation should work + cy.get('[data-testid="next-button"]').click(); + + cy.get('#name_help').should('contain', 'Name is required'); + + // invalid name validation should work + cy.get('[data-testid="service-name"]').type( + INVALID_NAMES.WITH_SPECIAL_CHARS + ); + cy.get('#name_help').should('contain', NAME_VALIDATION_ERROR); + + cy.get('[data-testid="service-name"]').clear().type(serviceName); + interceptURL('GET', '/api/v1/services/ingestionPipelines/ip', 'ipApi'); + interceptURL( + 'GET', + 'api/v1/services/ingestionPipelines/*', + 'ingestionPipelineStatus' + ); + + cy.get('[data-testid="next-button"]').click(); + } + + fillConnectionDetails() { + // Handle fill connection details in respective service here + } + + fillIngestionDetails() { + // Handle fill ingestion details in respective service here + } + + validateIngestionDetails() { + // Handle validate ingestion details in respective service here + } + + addIngestionPipeline(serviceName: string) { + cy.get('[data-testid="add-ingestion-button"]').click(); + + // Add ingestion page + cy.get('[data-testid="add-ingestion-container"]').should('be.visible'); + + this.fillIngestionDetails(); + + cy.get('[data-testid="submit-btn"]').scrollIntoView().click(); + + // Go back and data should persist + cy.get('[data-testid="back-button"]').scrollIntoView().click(); + + this.validateIngestionDetails(); + + // Go Next + cy.get('[data-testid="submit-btn"]').scrollIntoView().click(); + + this.scheduleIngestion(); + + cy.contains(`${replaceAllSpacialCharWith_(serviceName)}_metadata`).should( + 'be.visible' + ); + + interceptURL( + 'GET', + '/api/v1/services/ingestionPipelines?*', + 'ingestionPipelines' + ); + interceptURL('GET', '/api/v1/services/*/name/*', 'serviceDetails'); + + cy.get('[data-testid="view-service-button"]').click(); + verifyResponseStatusCode('@serviceDetails', 200); + verifyResponseStatusCode('@ingestionPipelines', 200); + this.handleIngestionRetry(); + } + + submitService(serviceName: string) { + interceptURL( + 'GET', + '/api/v1/services/ingestionPipelines/status', + 'getIngestionPipelineStatus' + ); + cy.get('[data-testid="submit-btn"]').should('exist').click(); + verifyResponseStatusCode('@getIngestionPipelineStatus', 200); + + // check success + cy.get('[data-testid="success-line"]').should('be.visible'); + cy.contains(`"${serviceName}"`).should('be.visible'); + cy.contains('has been created successfully').should('be.visible'); + } + + scheduleIngestion(hasRetryCount = true) { + interceptURL( + 'POST', + '/api/v1/services/ingestionPipelines', + 'createIngestionPipelines' + ); + interceptURL( + 'POST', + '/api/v1/services/ingestionPipelines/deploy/*', + 'deployPipeline' + ); + interceptURL( + 'GET', + '/api/v1/services/ingestionPipelines/status', + 'getIngestionPipelineStatus' + ); + // Schedule & Deploy + cy.get('[data-testid="cron-type"]').should('be.visible').click(); + cy.get('.ant-select-item-option-content').contains('Hour').click(); + + if (hasRetryCount) { + cy.get('#retries') + .scrollIntoView() + .clear() + .type(RETRIES_COUNT + ''); + } + + cy.get('[data-testid="deploy-button"]').click(); + + verifyResponseStatusCode('@createIngestionPipelines', 201); + verifyResponseStatusCode('@deployPipeline', 200, { + responseTimeout: 50000, + }); + verifyResponseStatusCode('@getIngestionPipelineStatus', 200); + // check success + cy.get('[data-testid="success-line"]', { timeout: 15000 }).should( + 'be.visible' + ); + cy.contains('has been created and deployed successfully').should( + 'be.visible' + ); + } + + handleIngestionRetry = (ingestionType = 'metadata') => { + let timer = BASE_WAIT_TIME; + const rowIndex = ingestionType === 'metadata' ? 1 : 2; + + interceptURL( + 'GET', + '/api/v1/services/ingestionPipelines?*', + 'ingestionPipelines' + ); + interceptURL( + 'GET', + '/api/v1/services/ingestionPipelines/*/pipelineStatus?startTs=*&endTs=*', + 'pipelineStatuses' + ); + interceptURL('GET', '/api/v1/services/*/name/*', 'serviceDetails'); + interceptURL('GET', '/api/v1/permissions?limit=100', 'allPermissions'); + + // ingestions page + let retryCount = 0; + const testIngestionsTab = () => { + // click on the tab only for the first time + if (retryCount === 0) { + cy.get('[data-testid="ingestions"]').should('exist').and('be.visible'); + cy.get('[data-testid="ingestions"] >> [data-testid="count"]').should( + 'have.text', + rowIndex + ); + cy.get('[data-testid="ingestions"]').click(); + + if (ingestionType === 'metadata') { + verifyResponseStatusCode('@pipelineStatuses', 200, { + responseTimeout: 50000, + }); + } + } + }; + const checkSuccessState = () => { + testIngestionsTab(); + + if (retryCount !== 0) { + cy.wait('@allPermissions').then(() => { + cy.wait('@serviceDetails').then(() => { + verifyResponseStatusCode('@ingestionPipelines', 200); + verifyResponseStatusCode('@pipelineStatuses', 200, { + responseTimeout: 50000, + }); + }); + }); + } + + retryCount++; + + cy.get(`[data-row-key*="${ingestionType}"]`) + .find('[data-testid="pipeline-status"]') + .as('checkRun'); + // the latest run should be success + cy.get('@checkRun').then(($ingestionStatus) => { + const text = $ingestionStatus.text(); + if ( + text !== 'Success' && + text !== 'Failed' && + retryCount <= RETRY_TIMES + ) { + // retry after waiting with log1 method [20s,40s,80s,160s,320s] + cy.wait(timer); + timer *= 2; + cy.reload(); + checkSuccessState(); + } else { + cy.get('@checkRun').should('contain', 'Success'); + } + }); + }; + + checkSuccessState(); + }; + + updateService() { + this.updateDescriptionForIngestedTables(); + } + + updateDescriptionForIngestedTables() { + const description = `${this.entityName} description`; + interceptURL( + 'GET', + `/api/v1/services/ingestionPipelines?fields=*&service=*`, + 'ingestionPipelines' + ); + interceptURL('GET', `/api/v1/*?service=*&fields=*`, 'serviceDetails'); + interceptURL( + 'GET', + `/api/v1/system/config/pipeline-service-client`, + 'pipelineServiceClient' + ); + interceptURL( + 'GET', + `/api/v1/services/ingestionPipelines/*/pipelineStatus?*`, + 'pipelineStatus' + ); + // Navigate to ingested table + visitEntityDetailsPage({ + term: this.entityName, + serviceName: this.serviceName, + entity: getEntityTypeFromService(this.category), + }); + + // update description + cy.get('[data-testid="edit-description"]').click(); + cy.get(descriptionBox).click().clear().type(description); + interceptURL('PATCH', '/api/v1/*/*', 'updateEntity'); + cy.get('[data-testid="save"]').click(); + verifyResponseStatusCode('@updateEntity', 200); + + // re-run ingestion flow + cy.sidebarClick('app-bar-item-settings'); + + // Services page + cy.get('.ant-menu-title-content').contains(this.category).click(); + interceptURL( + 'GET', + 'api/v1/search/query?q=*&from=0&size=15&index=*', + 'searchService' + ); + cy.get('[data-testid="searchbar"]').type(this.serviceName); + + verifyResponseStatusCode('@searchService', 200); + + // click on created service + cy.get(`[data-testid="service-name-${this.serviceName}"]`).click(); + + verifyResponseStatusCode('@serviceDetails', 200); + verifyResponseStatusCode('@ingestionPipelines', 200); + verifyResponseStatusCode('@pipelineServiceClient', 200); + cy.get('[data-testid="ingestions"]').click(); + verifyResponseStatusCode('@pipelineStatus', 200); + + interceptURL( + 'POST', + '/api/v1/services/ingestionPipelines/trigger/*', + 'checkRun' + ); + cy.get( + `[data-row-key*="${replaceAllSpacialCharWith_( + this.serviceName + )}_metadata"] [data-testid="run"]` + ).click(); + verifyResponseStatusCode('@checkRun', 200); + + toastNotification(`Pipeline triggered successfully!`); + + // Wait for success + retryIngestionRun(); + + // Navigate to table name + visitEntityDetailsPage({ + term: this.entityName, + serviceName: this.serviceName, + entity: getEntityTypeFromService(this.category), + }); + cy.get('[data-testid="markdown-parser"]') + .first() + .invoke('text') + .should('contain', description); + } + + deleteService() { + deleteService(this.category, this.serviceName); + } +} + +export default ServiceBaseClass; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/StoredProcedureClass.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/StoredProcedureClass.ts index c362360a7e8..72d6287fab0 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/StoredProcedureClass.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Entities/StoredProcedureClass.ts @@ -65,6 +65,10 @@ class StoreProcedureClass extends EntityClass { }); } + followUnfollowEntity() { + // Skiping this since not supported for store procedure + } + // Cleanup override cleanup() { super.cleanup(); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Services/AirflowIngestionClass.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Services/AirflowIngestionClass.ts new file mode 100644 index 00000000000..1fc7cdecc13 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Services/AirflowIngestionClass.ts @@ -0,0 +1,45 @@ +/* + * 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. + */ +import ServiceBaseClass from '../Entities/ServiceBaseClass'; +import { Services } from '../Utils/Services'; + +class MetabaseIngestionClass extends ServiceBaseClass { + name: string; + serviceName: string; + serviceType: string; + + constructor() { + super(Services.Pipeline, 'cypress-Airflow', 'Airflow', 'index_metadata'); + } + + createService() { + super.createService(); + } + + updateService() { + // Backend issue for udpating displayName + } + + fillConnectionDetails() { + cy.get('#root\\/hostPort').type(Cypress.env('airflowHostPort')); + cy.get('#root\\/connection__oneof_select') + .scrollIntoView() + .select('BackendConnection'); + } + + deleteService() { + super.deleteService(); + } +} + +export default MetabaseIngestionClass; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Services/BigQueryIngestionClass.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Services/BigQueryIngestionClass.ts new file mode 100644 index 00000000000..7ed9777b280 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Services/BigQueryIngestionClass.ts @@ -0,0 +1,91 @@ +/* + * 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. + */ +import { checkServiceFieldSectionHighlighting } from '../common'; +import ServiceBaseClass from '../Entities/ServiceBaseClass'; +import { Services } from '../Utils/Services'; + +class MetabaseIngestionClass extends ServiceBaseClass { + name: string; + filterPattern; + + constructor() { + super(Services.Database, 'cypress-BigQuery', 'BigQuery', 'testtable'); + + this.filterPattern = 'testschema'; + } + + createService() { + super.createService(); + } + + updateService() { + // super.updateService(); + // Issue with searching ingested data + } + + fillConnectionDetails() { + const clientEmail = Cypress.env('bigqueryClientEmail'); + cy.get('.form-group > #root\\/credentials\\/gcpConfig\\/type') + .scrollIntoView() + .type('service_account'); + checkServiceFieldSectionHighlighting('type'); + cy.get('#root\\/credentials\\/gcpConfig\\/projectId') + .scrollIntoView() + .type(Cypress.env('bigqueryProjectId')); + checkServiceFieldSectionHighlighting('projectId'); + cy.get('#root\\/credentials\\/gcpConfig\\/privateKeyId') + .scrollIntoView() + .type(Cypress.env('bigqueryPrivateKeyId')); + checkServiceFieldSectionHighlighting('privateKeyId'); + cy.get('#root\\/credentials\\/gcpConfig\\/privateKey') + .scrollIntoView() + .type(Cypress.env('bigqueryPrivateKey')); + checkServiceFieldSectionHighlighting('privateKey'); + cy.get('#root\\/credentials\\/gcpConfig\\/clientEmail') + .scrollIntoView() + .type(clientEmail); + checkServiceFieldSectionHighlighting('clientEmail'); + cy.get('#root\\/credentials\\/gcpConfig\\/clientId') + .scrollIntoView() + .type(Cypress.env('bigqueryClientId')); + checkServiceFieldSectionHighlighting('clientId'); + cy.get('#root\\/credentials\\/gcpConfig\\/clientX509CertUrl') + .scrollIntoView() + .type( + `https://www.googleapis.com/robot/v1/metadata/x509/${encodeURIComponent( + clientEmail + )}` + ); + checkServiceFieldSectionHighlighting('clientX509CertUrl'); + cy.get('[data-testid="add-item-Taxonomy Project IDs"]') + .scrollIntoView() + .click(); + checkServiceFieldSectionHighlighting('taxonomyProjectID'); + cy.get('#root\\/taxonomyProjectID\\/0') + .scrollIntoView() + .type(Cypress.env('bigqueryProjectIdTaxonomy')); + checkServiceFieldSectionHighlighting('taxonomyProjectID'); + } + + fillIngestionDetails() { + cy.get('#root\\/schemaFilterPattern\\/includes') + .scrollIntoView() + .type(`${this.filterPattern}{enter}`); + } + + deleteService() { + super.deleteService(); + } +} + +export default MetabaseIngestionClass; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Services/KafkaIngestionClass.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Services/KafkaIngestionClass.ts new file mode 100644 index 00000000000..ac04138fe0f --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Services/KafkaIngestionClass.ts @@ -0,0 +1,52 @@ +/* + * 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. + */ +import { checkServiceFieldSectionHighlighting } from '../common'; +import ServiceBaseClass from '../Entities/ServiceBaseClass'; +import { Services } from '../Utils/Services'; + +class KafkaIngestionClass extends ServiceBaseClass { + constructor() { + super(Services.Messaging, 'cypress-Kafka', 'Kafka', '__transaction_state'); + } + + createService() { + super.createService(); + } + + updateService() { + super.updateService(); + } + + fillConnectionDetails() { + cy.get('#root\\/bootstrapServers').type( + Cypress.env('kafkaBootstrapServers') + ); + checkServiceFieldSectionHighlighting('bootstrapServers'); + cy.get('#root\\/schemaRegistryURL').type( + Cypress.env('kafkaSchemaRegistryUrl') + ); + checkServiceFieldSectionHighlighting('schemaRegistryURL'); + } + + fillIngestionDetails() { + cy.get('#root\\/topicFilterPattern\\/includes') + .scrollIntoView() + .type(`${this.entityName}{enter}`); + } + + deleteService() { + super.deleteService(); + } +} + +export default KafkaIngestionClass; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Services/MetabaseIngestionClass.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Services/MetabaseIngestionClass.ts new file mode 100644 index 00000000000..16fecb00f84 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Services/MetabaseIngestionClass.ts @@ -0,0 +1,65 @@ +/* + * 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. + */ +import { checkServiceFieldSectionHighlighting } from '../common'; +import ServiceBaseClass from '../Entities/ServiceBaseClass'; +import { Services } from '../Utils/Services'; + +class MetabaseIngestionClass extends ServiceBaseClass { + name: string; + tableName = 'jaffle_shop dashboard'; + constructor() { + super( + Services.Dashboard, + 'cypress-Metabase', + 'Metabase', + 'jaffle_shop dashboard' + ); + this.tableName = 'jaffle_shop dashboard'; + } + + createService() { + super.createService(); + } + + updateService() { + // Backend issue for searching with displayName + // super.updateService(); + } + + fillConnectionDetails() { + cy.get('#root\\/username') + .scrollIntoView() + .type(Cypress.env('metabaseUsername')); + checkServiceFieldSectionHighlighting('username'); + cy.get('#root\\/password') + .scrollIntoView() + .type(Cypress.env('metabasePassword')); + checkServiceFieldSectionHighlighting('password'); + cy.get('#root\\/hostPort') + .scrollIntoView() + .type(Cypress.env('metabaseHostPort')); + checkServiceFieldSectionHighlighting('hostPort'); + } + + fillIngestionDetails() { + cy.get('#root\\/dashboardFilterPattern\\/includes') + .scrollIntoView() + .type(`${this.tableName}{enter}`); + } + + deleteService() { + super.deleteService(); + } +} + +export default MetabaseIngestionClass; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Services/MlFlowIngestionClass.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Services/MlFlowIngestionClass.ts new file mode 100644 index 00000000000..482d9735855 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Services/MlFlowIngestionClass.ts @@ -0,0 +1,55 @@ +/* + * 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. + */ +import { checkServiceFieldSectionHighlighting } from '../common'; +import ServiceBaseClass from '../Entities/ServiceBaseClass'; +import { Services } from '../Utils/Services'; + +class MlFlowIngestionClass extends ServiceBaseClass { + constructor() { + super( + Services.MLModels, + 'cypress-Ml-Model', + 'Mlflow', + 'ElasticnetWineModel', + false, + false + ); + } + + createService() { + super.createService(); + } + + updateService() { + // Do nothing here + } + + fillConnectionDetails() { + cy.get('#root\\/trackingUri').type('mlModelTrackingUri'); + checkServiceFieldSectionHighlighting('trackingUri'); + cy.get('#root\\/registryUri').type('mlModelRegistryUri'); + checkServiceFieldSectionHighlighting('registryUri'); + } + + fillIngestionDetails() { + cy.get('#root\\/mlModelFilterPattern\\/includes') + .scrollIntoView() + .type(`${this.entityName}{enter}`); + } + + deleteService() { + super.deleteService(); + } +} + +export default MlFlowIngestionClass; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Services/MysqlIngestionClass.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Services/MysqlIngestionClass.ts new file mode 100644 index 00000000000..b323c06e26c --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Services/MysqlIngestionClass.ts @@ -0,0 +1,52 @@ +/* + * 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. + */ +import { checkServiceFieldSectionHighlighting } from '../common'; +import ServiceBaseClass from '../Entities/ServiceBaseClass'; +import { Services } from '../Utils/Services'; + +class MysqlIngestionClass extends ServiceBaseClass { + name: string; + tableFilter: string; + constructor() { + super(Services.Database, 'cypress-mysql', 'Mysql', 'bot_entity'); + this.tableFilter = 'bot_entity{enter} alert_entity{enter} chart_entity'; + } + + createService() { + super.createService(); + } + + fillConnectionDetails() { + cy.get('#root\\/username').type(Cypress.env('mysqlUsername')); + checkServiceFieldSectionHighlighting('username'); + cy.get('#root\\/authType\\/password').type(Cypress.env('mysqlPassword')); + checkServiceFieldSectionHighlighting('password'); + cy.get('#root\\/hostPort').type(Cypress.env('mysqlHostPort')); + checkServiceFieldSectionHighlighting('hostPort'); + } + + fillIngestionDetails() { + cy.get('#root\\/tableFilterPattern\\/includes') + .scrollIntoView() + .type(this.tableFilter); + } + + validateIngestionDetails() { + const tables = this.tableFilter.replace(/{enter} /g, ''); + cy.get('.ant-select-selection-item-content') + .then((content) => content.text()) + .should('deep.eq', tables); + } +} + +export default MysqlIngestionClass; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Services/S3IngestionClass.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Services/S3IngestionClass.ts new file mode 100644 index 00000000000..0e7b2255a0e --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Services/S3IngestionClass.ts @@ -0,0 +1,49 @@ +/* + * 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. + */ +import { checkServiceFieldSectionHighlighting } from '../common'; +import ServiceBaseClass from '../Entities/ServiceBaseClass'; +import { Services } from '../Utils/Services'; + +class S3IngestionClass extends ServiceBaseClass { + name: string; + constructor() { + super(Services.Storage, 'cypress-s3-storage', 'S3', 'cypress-bucket'); + } + + createService() { + super.createService(); + } + + updateService() { + super.updateService(); + } + + fillConnectionDetails() { + cy.get('#root\\/awsConfig\\/awsAccessKeyId').type( + Cypress.env('s3StorageAccessKeyId') + ); + checkServiceFieldSectionHighlighting('awsAccessKeyId'); + cy.get('#root\\/awsConfig\\/awsSecretAccessKey').type( + Cypress.env('s3StorageSecretAccessKey') + ); + checkServiceFieldSectionHighlighting('awsSecretAccessKey'); + cy.get('#root\\/awsConfig\\/awsRegion').type('us'); + checkServiceFieldSectionHighlighting('awsRegion'); + cy.get('#root\\/awsConfig\\/endPointURL').type( + Cypress.env('s3StorageEndPointUrl') + ); + checkServiceFieldSectionHighlighting('endPointURL'); + } +} + +export default S3IngestionClass; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Services/SnowflakeIngestionClass.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Services/SnowflakeIngestionClass.ts new file mode 100644 index 00000000000..40add43e4bd --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Services/SnowflakeIngestionClass.ts @@ -0,0 +1,52 @@ +/* + * 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. + */ +import { checkServiceFieldSectionHighlighting } from '../common'; +import ServiceBaseClass from '../Entities/ServiceBaseClass'; +import { Services } from '../Utils/Services'; + +class SnowflakeIngestionClass extends ServiceBaseClass { + schema: string; + constructor() { + super(Services.Database, 'cypress-Snowflake', 'Snowflake', 'CUSTOMER'); + this.schema = 'TPCH_SF1000'; + } + + createService() { + super.createService(); + } + + fillConnectionDetails() { + cy.get('#root\\/username').type(Cypress.env('snowflakeUsername')); + checkServiceFieldSectionHighlighting('username'); + cy.get('#root\\/password').type(Cypress.env('snowflakePassword')); + checkServiceFieldSectionHighlighting('password'); + cy.get('#root\\/account').type(Cypress.env('snowflakeAccount')); + checkServiceFieldSectionHighlighting('account'); + cy.get('#root\\/database').type(Cypress.env('snowflakeDatabase')); + checkServiceFieldSectionHighlighting('database'); + cy.get('#root\\/warehouse').type(Cypress.env('snowflakeWarehouse')); + checkServiceFieldSectionHighlighting('warehouse'); + } + + fillIngestionDetails() { + cy.get('#root\\/schemaFilterPattern\\/includes') + .scrollIntoView() + .type(`${this.schema}{enter}`); + } + + deleteService() { + super.deleteService(); + } +} + +export default SnowflakeIngestionClass; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Services/SupersetIngestionClass.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Services/SupersetIngestionClass.ts new file mode 100644 index 00000000000..6b09171712b --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Services/SupersetIngestionClass.ts @@ -0,0 +1,59 @@ +/* + * 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. + */ +import ServiceBaseClass from '../Entities/ServiceBaseClass'; +import { Services } from '../Utils/Services'; + +class SupersetIngestionClass extends ServiceBaseClass { + constructor() { + super( + Services.Dashboard, + 'cypress-Superset', + 'Superset', + "World Bank's Data" + ); + } + + createService() { + super.createService(); + } + + updateService() { + // Issue with searching ingested data + } + + fillConnectionDetails() { + cy.get('#root\\/connection\\/username') + .scrollIntoView() + .type(Cypress.env('supersetUsername')); + cy.get('#root\\/connection\\/password') + .scrollIntoView() + .type(Cypress.env('supersetPassword')); + cy.get('#root\\/hostPort') + .scrollIntoView() + .focus() + .clear() + .type(Cypress.env('supersetHostPort')); + } + + fillIngestionDetails() { + cy.get('#root\\/dashboardFilterPattern\\/includes') + .scrollIntoView() + .type(`${this.entityName}{enter}`); + } + + deleteService() { + super.deleteService(); + } +} + +export default SupersetIngestionClass; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Entity.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Entity.ts index 4b04de5092c..a4ec3305ff4 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Entity.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Entity.ts @@ -14,7 +14,6 @@ import { DELETE_TERM } from '../../constants/constants'; import { EntityType, EXPLORE_PAGE_TABS, - SEARCH_INDEX, } from '../../constants/Entity.interface'; import { ENTITIES_WITHOUT_FOLLOWING_BUTTON, @@ -177,11 +176,6 @@ export const visitEntityDetailsPage = ({ interceptURL('GET', '/api/v1/*/name/*', 'getEntityDetails'); } - interceptURL( - 'GET', - `/api/v1/search/query?q=**&index=${SEARCH_INDEX[entity]}&from=*&size=**`, - 'explorePageTabSearch' - ); interceptURL( 'GET', `/api/v1/search/query?q=**&from=*&size=*&index=all`, @@ -221,9 +215,9 @@ export const visitEntityDetailsPage = ({ cy.get(`[data-testid="${tabName}-tab"]`).click(); - verifyResponseStatusCode('@explorePageTabSearch', 200); - - cy.get(`[data-testid="${id}"] [data-testid="entity-link"]`) + cy.get(`[data-testid="${id}"] [data-testid="entity-link"]`, { + timeout: 10000, + }) .scrollIntoView() .click(); } @@ -441,7 +435,11 @@ export const deleteEntity = (entityName: string, endPoint: EntityType) => { toastNotification('deleted successfully!'); cy.reload(); - cy.get('[data-testid="deleted-badge"]').should('have.text', 'Deleted'); + + cy.get('[data-testid="deleted-badge"]', { timeout: 10000 }).should( + 'have.text', + 'Deleted' + ); deletedEntityCommonChecks({ entityType: endPoint, deleted: true }); @@ -471,8 +469,7 @@ export const deleteEntity = (entityName: string, endPoint: EntityType) => { '1' ); - cy.get('.ant-table-row > :nth-child(1)').should('contain', entityName); - cy.get('.ant-table-row > :nth-child(1)').contains(entityName).click(); + cy.get(`[data-testid=${entityName}]`).click(); } restoreEntity(); @@ -555,3 +552,36 @@ export const updateDescriptioForEntity = ( '[data-testid="asset-description-container"] [data-testid="viewer-container"]' ).should('contain', description); }; + +export const followEntity = (entityType: EntityType) => { + interceptURL('PUT', `/api/v1/${entityType}/*/followers`, 'waitAfterFollow'); + + cy.get('[data-testid="entity-follow-button"]').scrollIntoView().click(); + + verifyResponseStatusCode('@waitAfterFollow', 200); +}; + +export const validateFollowedEntityToWidget = ( + entityName: string, + isFollowed = true +) => { + interceptURL('GET', '/api/v1/users/*?fields=follows*', 'getFollowedEntities'); + cy.goToHomePage(); + + verifyResponseStatusCode('@getFollowedEntities', 200, { timeout: 10000 }); + cy.get(`[data-testid="following-${entityName}"]`).should( + isFollowed ? 'be.visible' : 'not.exist' + ); +}; + +export const unfollowEntity = (entityType: EntityType) => { + interceptURL( + 'DELETE', + `/api/v1/${entityType}/*/followers/*`, + 'waitAfterUnFollow' + ); + + cy.get('[data-testid="entity-follow-button"]').scrollIntoView().click(); + + verifyResponseStatusCode('@waitAfterUnFollow', 200); +}; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Glossary.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Glossary.ts index d3667228669..6721fda6056 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Glossary.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Glossary.ts @@ -10,7 +10,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { EntityType } from '../../new-tests/base/EntityClass'; + +import { EntityType } from '../../constants/Entity.interface'; import { interceptURL, verifyResponseStatusCode } from '../common'; export const assignGlossaryTerm = ( diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Services.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Services.ts new file mode 100644 index 00000000000..76ca9eb6f9e --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/Services.ts @@ -0,0 +1,206 @@ +/* + * 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. + */ +import { DELETE_TERM } from '../../constants/constants'; +import { EntityType } from '../../constants/Entity.interface'; +import { + interceptURL, + toastNotification, + verifyResponseStatusCode, +} from '../common'; + +export enum Services { + Database = 'Databases', + Messaging = 'Messaging', + Dashboard = 'Dashboards', + Pipeline = 'Pipelines', + MLModels = 'ML Models', + Storage = 'Storages', + Search = 'Search', +} + +export const RETRY_TIMES = 4; +export const BASE_WAIT_TIME = 20000; + +export const goToServiceListingPage = (services: Services) => { + interceptURL( + 'GET', + 'api/v1/teams/name/Organization?fields=*', + 'getSettingsPage' + ); + // Click on settings page + cy.sidebarClick('app-bar-item-settings'); + verifyResponseStatusCode('@getSettingsPage', 200); + // Services page + interceptURL('GET', '/api/v1/services/*', 'getServiceList'); + cy.get(`[data-testid="global-setting-left-panel"]`) + .contains(services) + .click(); + + verifyResponseStatusCode('@getServiceList', 200); +}; + +export const getEntityTypeFromService = (service: Services) => { + switch (service) { + case Services.Dashboard: + return EntityType.DashboardService; + case Services.Database: + return EntityType.DatabaseService; + case Services.Storage: + return EntityType.StorageService; + case Services.Messaging: + return EntityType.MessagingService; + case Services.Search: + return EntityType.SearchService; + case Services.MLModels: + return EntityType.MlModelService; + case Services.Pipeline: + return EntityType.PipelineService; + default: + return EntityType.DatabaseService; + } +}; + +export const retryIngestionRun = () => { + interceptURL('GET', '/api/v1/services/*/name/*', 'serviceDetails'); + interceptURL( + 'GET', + '/api/v1/services/ingestionPipelines/*/pipelineStatus/*', + 'pipelineStatus' + ); + let timer = BASE_WAIT_TIME; + let retryCount = 0; + const testIngestionsTab = () => { + cy.get('[data-testid="ingestions"]').scrollIntoView().should('be.visible'); + cy.get('[data-testid="ingestions"] >> [data-testid="count"]').should( + 'have.text', + '1' + ); + if (retryCount === 0) { + cy.wait(1000); + cy.get('[data-testid="ingestions"]').should('be.visible'); + } + }; + + const checkSuccessState = () => { + testIngestionsTab(); + retryCount++; + + // the latest run should be success + cy.get('[data-testid="pipeline-status"]').then(($ingestionStatus) => { + if ($ingestionStatus.text() !== 'Success' && retryCount <= RETRY_TIMES) { + // retry after waiting with log1 method [20s,40s,80s,160s,320s] + cy.wait(timer); + timer *= 2; + cy.reload(); + verifyResponseStatusCode('@serviceDetails', 200); + verifyResponseStatusCode('@pipelineStatus', 200); + checkSuccessState(); + } else { + cy.get('[data-testid="pipeline-status"]').should('contain', 'Success'); + } + }); + }; + + checkSuccessState(); +}; + +export const deleteService = (typeOfService: Services, serviceName: string) => { + interceptURL( + 'GET', + 'api/v1/search/query?q=*&from=0&size=15&index=*', + 'searchService' + ); + cy.get('[data-testid="searchbar"]').type(serviceName); + + verifyResponseStatusCode('@searchService', 200); + + // click on created service + cy.get(`[data-testid="service-name-${serviceName}"]`).click(); + + cy.get(`[data-testid="entity-header-display-name"]`) + .invoke('text') + .then((text) => { + expect(text).to.equal(serviceName); + }); + + // Clicking on permanent delete radio button and checking the service name + cy.get('[data-testid="manage-button"]').click(); + + cy.get('[data-menu-id*="delete-button"]').should('be.visible'); + cy.get('[data-testid="delete-button-title"]').click(); + + // Clicking on permanent delete radio button and checking the service name + cy.get('[data-testid="hard-delete-option"]').contains(serviceName).click(); + + cy.get('[data-testid="confirmation-text-input"]').type(DELETE_TERM); + interceptURL( + 'DELETE', + `/api/v1/${getEntityTypeFromService(typeOfService)}/*`, + 'deleteService' + ); + interceptURL( + 'GET', + '/api/v1/services/*/name/*?fields=owner', + 'serviceDetails' + ); + + cy.get('[data-testid="confirm-button"]').click(); + verifyResponseStatusCode('@deleteService', 200); + + // Closing the toast notification + toastNotification(`Service deleted successfully!`); + + cy.get(`[data-testid="service-name-${serviceName}"]`).should('not.exist'); +}; + +export const testConnection = () => { + // Test the connection + interceptURL( + 'GET', + '/api/v1/services/testConnectionDefinitions/name/*', + 'testConnectionStepDefinition' + ); + + interceptURL('POST', '/api/v1/automations/workflows', 'createWorkflow'); + + interceptURL( + 'POST', + '/api/v1/automations/workflows/trigger/*', + 'triggerWorkflow' + ); + + interceptURL('GET', '/api/v1/automations/workflows/*', 'getWorkflow'); + + cy.get('[data-testid="test-connection-btn"]').should('exist').click(); + + verifyResponseStatusCode('@testConnectionStepDefinition', 200); + + verifyResponseStatusCode('@createWorkflow', 201); + // added extra buffer time as triggerWorkflow API can take up to 2minute to provide result + verifyResponseStatusCode('@triggerWorkflow', 200, { + responseTimeout: 120000, + }); + cy.get('[data-testid="test-connection-modal"]').should('exist'); + cy.get('.ant-modal-footer > .ant-btn-primary') + .should('exist') + .contains('OK') + .click(); + verifyResponseStatusCode('@getWorkflow', 200); + cy.get('[data-testid="messag-text"]').then(($message) => { + if ($message.text().includes('partially successful')) { + cy.contains('Test connection partially successful').should('exist'); + } else { + cy.contains('Connection test was successful').should('exist'); + } + }); +}; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/serviceUtils.js b/openmetadata-ui/src/main/resources/ui/cypress/common/serviceUtils.js index f0125b5436c..40a8c69019a 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/common/serviceUtils.js +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/serviceUtils.js @@ -24,16 +24,9 @@ export const searchServiceFromSettingPage = (service) => { }; export const visitServiceDetailsPage = (service, verifyHeader = true) => { - // Click on settings page - interceptURL( - 'GET', - 'api/v1/teams/name/Organization?fields=*', - 'getSettingsPage' - ); cy.sidebarClick('app-bar-item-settings'); - verifyResponseStatusCode('@getSettingsPage', 200); // Services page interceptURL('GET', '/api/v1/services/*', 'getServices'); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/constants/Entity.interface.ts b/openmetadata-ui/src/main/resources/ui/cypress/constants/Entity.interface.ts index fb4a26c2401..80baa51afac 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/constants/Entity.interface.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/constants/Entity.interface.ts @@ -29,6 +29,7 @@ export enum EntityType { PipelineService = 'services/pipelineServices', MessagingService = 'services/messagingServices', SearchService = 'services/searchServices', + MetadataService = 'services/metadataServices', Database = 'databases', DatabaseSchema = 'databaseSchemas', DataModel = 'dashboard/datamodels', @@ -48,6 +49,7 @@ export const EXPLORE_PAGE_TABS: Record< | EntityType.DatabaseSchema | EntityType.GlossaryTerm | EntityType.Domain + | EntityType.MetadataService >, string > = { @@ -76,6 +78,7 @@ export const SEARCH_INDEX: Record< | EntityType.Database | EntityType.DatabaseSchema | EntityType.GlossaryTerm + | EntityType.MetadataService >, string > = { diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/ActivityFeed.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/ActivityFeed.spec.js index 155d551b3ac..2e80ec44181 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/ActivityFeed.spec.js +++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/ActivityFeed.spec.js @@ -77,7 +77,6 @@ describe('Activity feed', () => { beforeEach(() => { cy.login(); - cy.get("[data-testid='welcome-screen-close-btn']").click(); }); it('Create feed', () => { diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/Following.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/Following.spec.js deleted file mode 100644 index 305e3bd85b7..00000000000 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/Following.spec.js +++ /dev/null @@ -1,208 +0,0 @@ -/* - * 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 { - createEntityTable, - createSingleLevelEntity, - hardDeleteService, -} from '../../common/EntityUtils'; -import { - DASHBOARD_DATA_MODEL_DETAILS, - DATABASE_SERVICE, - SINGLE_LEVEL_SERVICE, - STORED_PROCEDURE_DETAILS, - VISIT_ENTITIES_DATA, -} from '../../constants/EntityConstant'; -import { SERVICE_CATEGORIES } from '../../constants/service.constants'; - -// eslint-disable-next-line spaced-comment -/// - -// Update list if we support this for other entities too -const FOLLOWING_ENTITIES = [ - VISIT_ENTITIES_DATA.table, - VISIT_ENTITIES_DATA.dashboard, - VISIT_ENTITIES_DATA.topic, - VISIT_ENTITIES_DATA.pipeline, - VISIT_ENTITIES_DATA.mlmodel, - VISIT_ENTITIES_DATA.storedProcedure, - VISIT_ENTITIES_DATA.dataModel, -]; - -const followEntity = ({ term, serviceName, entity }, isUnfollow) => { - visitEntityDetailsPage({ term, serviceName, entity }); - - if (entity === 'dashboardDataModel') { - interceptURL( - isUnfollow ? 'DELETE' : 'PUT', - isUnfollow - ? '/api/v1/dashboard/datamodels/*/followers/*' - : '/api/v1/dashboard/datamodels/*/followers', - 'waitAfterFollow' - ); - } else { - interceptURL( - isUnfollow ? 'DELETE' : 'PUT', - isUnfollow ? '/api/v1/*/*/followers/*' : '/api/v1/*/*/followers', - 'waitAfterFollow' - ); - } - - interceptURL( - isUnfollow ? 'DELETE' : 'PUT', - isUnfollow ? '/api/v1/*/*/followers/*' : '/api/v1/*/*/followers', - 'waitAfterFollow' - ); - cy.get('[data-testid="entity-follow-button"]') - .scrollIntoView() - .should('be.visible') - .click(); - - verifyResponseStatusCode('@waitAfterFollow', 200); -}; - -describe('Following data assets', () => { - before(() => { - cy.login(); - cy.getAllLocalStorage().then((data) => { - const token = Object.values(data)[0].oidcIdToken; - - createEntityTable({ - token, - ...DATABASE_SERVICE, - tables: [DATABASE_SERVICE.entity], - }); - SINGLE_LEVEL_SERVICE.forEach((data) => { - createSingleLevelEntity({ - token, - ...data, - entity: [data.entity], - }); - }); - - // creating data model - cy.request({ - method: 'POST', - url: `/api/v1/dashboard/datamodels`, - headers: { Authorization: `Bearer ${token}` }, - body: DASHBOARD_DATA_MODEL_DETAILS, - }); - // creating stored procedure - cy.request({ - method: 'POST', - url: `/api/v1/storedProcedures`, - headers: { Authorization: `Bearer ${token}` }, - body: STORED_PROCEDURE_DETAILS, - }); - }); - }); - - after(() => { - cy.login(); - cy.getAllLocalStorage().then((data) => { - const token = Object.values(data)[0].oidcIdToken; - - hardDeleteService({ - token, - serviceFqn: DATABASE_SERVICE.service.name, - serviceType: SERVICE_CATEGORIES.DATABASE_SERVICES, - }); - SINGLE_LEVEL_SERVICE.forEach((data) => { - hardDeleteService({ - token, - serviceFqn: data.service.name, - serviceType: data.serviceType, - }); - }); - }); - }); - - beforeEach(() => { - cy.login(); - cy.get("[data-testid='welcome-screen-close-btn']").click(); - }); - - it('following section should be present', () => { - cy.get('[data-testid="following-widget"]') - .scrollIntoView() - .should('be.visible'); - - cy.get('[data-testid="following-widget"]').contains( - 'You have not followed anything yet.' - ); - cy.get(`[data-testid="following-widget"] .right-panel-list-item`).should( - 'have.length', - 0 - ); - }); - - // Follow entity - FOLLOWING_ENTITIES.map((entity, index) => { - it(`following section should have ${entity.term} followed`, () => { - followEntity(entity); - - interceptURL( - 'GET', - '/api/v1/feed?type=Announcement&activeAnnouncement=true', - 'getAnnoucemenets' - ); - - cy.clickOnLogo(); - verifyResponseStatusCode('@getAnnoucemenets', 200); - - if (index < 5) { - cy.get(`[data-testid="following-${entity.displayName}"]`).should( - 'be.visible' - ); - } - - // Checking count of following - cy.get(`[data-testid="following-data"]`).should('contain', index + 1); - }); - }); - - // UnFollow entity - FOLLOWING_ENTITIES.map((entity, index) => { - it(`unfollowing entity ${entity.term} should removed from following section`, () => { - followEntity(entity, true); - - interceptURL( - 'GET', - '/api/v1/feed?type=Announcement&activeAnnouncement=true', - 'getAnnoucemenets' - ); - - cy.clickOnLogo(); - verifyResponseStatusCode('@getAnnoucemenets', 200); - - cy.get(`[data-testid="following-${entity.displayName}"]`).should( - 'not.exist' - ); - - if (index === FOLLOWING_ENTITIES.length - 1) { - // Checking count of following - cy.get(`[data-testid="following-data"]`).should('not.exist'); - } else { - // Checking count of following - cy.get(`[data-testid="following-data"]`).should( - 'contain', - FOLLOWING_ENTITIES.length - (index + 1) - ); - } - }); - }); -}); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/QueryEntity.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/QueryEntity.spec.js index 142749d89b7..d9751afeddd 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/QueryEntity.spec.js +++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/QueryEntity.spec.js @@ -82,7 +82,6 @@ describe('Query Entity', () => { beforeEach(() => { cy.login(); - cy.get("[data-testid='welcome-screen-close-btn']").click(); }); it('Create query', () => { diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/RecentlyViewed.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/RecentlyViewed.spec.js index 585cbffc35f..5003c10a3f9 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/RecentlyViewed.spec.js +++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Features/RecentlyViewed.spec.js @@ -92,7 +92,6 @@ describe('Recently viwed data assets', () => { beforeEach(() => { cy.login(); - cy.get("[data-testid='welcome-screen-close-btn']").click(); }); it('recently view section should be present', () => { diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Database.spec.ts b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Database.spec.ts index 84a96d46fc3..6a8dd719dd0 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Database.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Database.spec.ts @@ -102,6 +102,10 @@ entities.forEach((entity) => { entity.downVote(); }); + it(`follow unfollow entity`, () => { + entity.followUnfollowEntity(); + }); + Object.values(CustomPropertyType).forEach((type) => { it(`Set ${type} Custom Property `, () => { entity.setCustomProperty( diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Entity.spec.ts b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Entity.spec.ts index e6ff9d75411..a6cd9dad411 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Entity.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Entity.spec.ts @@ -130,7 +130,11 @@ entities.forEach((entity) => { }); } - it(`Update displayName`, () => { + it(`follow unfollow entity`, () => { + entity.followUnfollowEntity(); + }); + + it.skip(`Update displayName`, () => { entity.renameEntity(); }); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/Airflow.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/Airflow.spec.js deleted file mode 100644 index 0b93cc55f9c..00000000000 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/Airflow.spec.js +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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. - */ -// eslint-disable-next-line spaced-comment -/// - -import { - deleteCreatedService, - goToAddNewServicePage, - testServiceCreationAndIngestion, - updateDescriptionForIngestedTables, - uuid, -} from '../../common/common'; -import { - API_SERVICE, - DATA_ASSETS, - SERVICE_TYPE, -} from '../../constants/constants'; - -const serviceType = 'Airflow'; -const serviceName = `${serviceType}-ct-test-${uuid()}`; -const tableName = 'index_metadata'; -const description = `This is ${tableName} description`; - -const connectionInput = () => { - cy.get('#root\\/hostPort').type(Cypress.env('airflowHostPort')); - cy.get('#root\\/connection__oneof_select') - .scrollIntoView() - .select('BackendConnection'); -}; - -describe('Airflow Ingestion', () => { - beforeEach(() => { - cy.login(); - }); - - it('add and ingest data', () => { - goToAddNewServicePage(SERVICE_TYPE.Pipeline); - - testServiceCreationAndIngestion({ - serviceType, - connectionInput, - serviceName, - type: SERVICE_TYPE.Pipeline, - serviceCategory: SERVICE_TYPE.Pipeline, - }); - }); - - it.skip('Update pipeline description and verify description after re-run', () => { - updateDescriptionForIngestedTables( - serviceName, - tableName, - description, - SERVICE_TYPE.Pipeline, - DATA_ASSETS.pipelines - ); - }); - - it('delete created service', () => { - deleteCreatedService( - SERVICE_TYPE.Pipeline, - serviceName, - API_SERVICE.pipelineServices - ); - }); -}); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/MlFlow.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/MlFlow.spec.js deleted file mode 100644 index a5fbbeefc98..00000000000 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/MlFlow.spec.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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 { - checkServiceFieldSectionHighlighting, - deleteCreatedService, - goToAddNewServicePage, - testServiceCreationAndIngestion, - uuid, -} from '../../common/common'; -import { API_SERVICE, SERVICE_TYPE } from '../../constants/constants'; - -const serviceType = 'Mlflow'; -const serviceName = `${serviceType}-ct-test-${uuid()}`; -const modelName = 'ElasticnetWineModel'; - -const connectionInput = () => { - cy.get('#root\\/trackingUri').type('mlModelTrackingUri'); - checkServiceFieldSectionHighlighting('trackingUri'); - cy.get('#root\\/registryUri').type('mlModelRegistryUri'); - checkServiceFieldSectionHighlighting('registryUri'); -}; - -const addIngestionInput = () => { - cy.get('#root\\/mlModelFilterPattern\\/includes') - .scrollIntoView() - .type(`${modelName}{enter}`); -}; - -describe('ML Flow Ingestion', () => { - beforeEach(() => { - cy.login(); - }); - - it('add and ingest data', () => { - goToAddNewServicePage(SERVICE_TYPE.MLModels); - - testServiceCreationAndIngestion({ - serviceType, - connectionInput, - addIngestionInput, - serviceName, - type: SERVICE_TYPE.MLModels, - serviceCategory: 'MlModel', - shouldAddIngestion: false, - allowTestConnection: false, - }); - }); - - it('delete created service', () => { - deleteCreatedService( - SERVICE_TYPE.MLModels, - serviceName, - API_SERVICE.mlmodelServices, - 'Mlmodel' - ); - }); -}); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/S3Storage.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/S3Storage.spec.js deleted file mode 100644 index b27f4371a05..00000000000 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/S3Storage.spec.js +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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 { - checkServiceFieldSectionHighlighting, - deleteCreatedService, - goToAddNewServicePage, - testServiceCreationAndIngestion, - updateDescriptionForIngestedTables, - uuid, -} from '../../common/common'; -import { - API_SERVICE, - DATA_ASSETS, - SERVICE_TYPE, -} from '../../constants/constants'; - -const serviceType = 'S3'; -const serviceName = `${serviceType}-ct-test-${uuid()}`; -const tableName = 'cypress-bucket'; -const description = `This is ${tableName} description`; - -const connectionInput = () => { - cy.get('#root\\/awsConfig\\/awsAccessKeyId').type( - Cypress.env('s3StorageAccessKeyId') - ); - checkServiceFieldSectionHighlighting('awsAccessKeyId'); - cy.get('#root\\/awsConfig\\/awsSecretAccessKey').type( - Cypress.env('s3StorageSecretAccessKey') - ); - checkServiceFieldSectionHighlighting('awsSecretAccessKey'); - cy.get('#root\\/awsConfig\\/awsRegion').type('us'); - checkServiceFieldSectionHighlighting('awsRegion'); - cy.get('#root\\/awsConfig\\/endPointURL').type( - Cypress.env('s3StorageEndPointUrl') - ); - checkServiceFieldSectionHighlighting('endPointURL'); -}; - -describe('S3Storage Ingestion', () => { - beforeEach(() => { - cy.login(); - }); - - it('add and ingest data', () => { - goToAddNewServicePage(SERVICE_TYPE.Storage); - - testServiceCreationAndIngestion({ - serviceType, - connectionInput, - serviceName, - type: SERVICE_TYPE.Storage, - serviceCategory: SERVICE_TYPE.Storage, - }); - }); - - it('Update container description and verify description after re-run', () => { - updateDescriptionForIngestedTables( - serviceName, - tableName, - description, - SERVICE_TYPE.Storage, - DATA_ASSETS.containers - ); - }); - - // Todo: unskip below test once issue is fixed https://github.com/open-metadata/OpenMetadata/issues/11700 - it.skip('delete created service', () => { - deleteCreatedService( - SERVICE_TYPE.Storage, - serviceName, - API_SERVICE.storageServices - ); - }); -}); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/ServiceIngestion.spec.ts b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/ServiceIngestion.spec.ts new file mode 100644 index 00000000000..d603058e3dd --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/ServiceIngestion.spec.ts @@ -0,0 +1,55 @@ +/* + * 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. + */ +import AirflowIngestionClass from '../../common/Services/AirflowIngestionClass'; +import BigQueryIngestionClass from '../../common/Services/BigQueryIngestionClass'; +import KafkaIngestionClass from '../../common/Services/KafkaIngestionClass'; +import MetabaseIngestionClass from '../../common/Services/MetabaseIngestionClass'; +import MlFlowIngestionClass from '../../common/Services/MlFlowIngestionClass'; +import MysqlIngestionClass from '../../common/Services/MysqlIngestionClass'; +import S3IngestionClass from '../../common/Services/S3IngestionClass'; +import SnowflakeIngestionClass from '../../common/Services/SnowflakeIngestionClass'; +import SupersetIngestionClass from '../../common/Services/SupersetIngestionClass'; +import { goToServiceListingPage } from '../../common/Utils/Services'; + +const services = [ + new S3IngestionClass(), + new MetabaseIngestionClass(), + new MysqlIngestionClass(), + new AirflowIngestionClass(), + new BigQueryIngestionClass(), + new KafkaIngestionClass(), + new MlFlowIngestionClass(), + new SnowflakeIngestionClass(), + new SupersetIngestionClass(), +]; + +services.forEach((service) => { + describe(`${service.serviceType} Ingestion`, () => { + beforeEach(() => { + cy.login(); + goToServiceListingPage(service.category); + }); + + it(`Create & Ingest ${service.serviceType} service`, () => { + service.createService(); + }); + + it(`Update description and verify description after re-run`, () => { + service.updateService(); + }); + + it(`Delete ${service.serviceType} service`, () => { + service.deleteService(); + }); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/bigquery.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/bigquery.spec.js deleted file mode 100644 index 0113b9dc94e..00000000000 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/bigquery.spec.js +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2022 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 { - checkServiceFieldSectionHighlighting, - deleteCreatedService, - goToAddNewServicePage, - testServiceCreationAndIngestion, - updateDescriptionForIngestedTables, - uuid, -} from '../../common/common'; -import { API_SERVICE, SERVICE_TYPE } from '../../constants/constants'; - -const serviceType = 'BigQuery'; -const serviceName = `${serviceType}-ct-test-${uuid()}`; -const tableName = 'testtable'; -const description = `This is ${serviceName} description`; -const filterPattern = 'testschema'; - -describe('BigQuery Ingestion', () => { - beforeEach(() => { - cy.login(); - }); - - it('add and ingest data', () => { - goToAddNewServicePage(SERVICE_TYPE.Database); - const connectionInput = () => { - const clientEmail = Cypress.env('bigqueryClientEmail'); - cy.get('.form-group > #root\\/credentials\\/gcpConfig\\/type') - .scrollIntoView() - .type('service_account'); - checkServiceFieldSectionHighlighting('type'); - cy.get('#root\\/credentials\\/gcpConfig\\/projectId') - .scrollIntoView() - .type(Cypress.env('bigqueryProjectId')); - checkServiceFieldSectionHighlighting('projectId'); - cy.get('#root\\/credentials\\/gcpConfig\\/privateKeyId') - .scrollIntoView() - .type(Cypress.env('bigqueryPrivateKeyId')); - checkServiceFieldSectionHighlighting('privateKeyId'); - cy.get('#root\\/credentials\\/gcpConfig\\/privateKey') - .scrollIntoView() - .type(Cypress.env('bigqueryPrivateKey')); - checkServiceFieldSectionHighlighting('privateKey'); - cy.get('#root\\/credentials\\/gcpConfig\\/clientEmail') - .scrollIntoView() - .type(clientEmail); - checkServiceFieldSectionHighlighting('clientEmail'); - cy.get('#root\\/credentials\\/gcpConfig\\/clientId') - .scrollIntoView() - .type(Cypress.env('bigqueryClientId')); - checkServiceFieldSectionHighlighting('clientId'); - cy.get('#root\\/credentials\\/gcpConfig\\/clientX509CertUrl') - .scrollIntoView() - .type( - `https://www.googleapis.com/robot/v1/metadata/x509/${encodeURIComponent( - clientEmail - )}` - ); - checkServiceFieldSectionHighlighting('clientX509CertUrl'); - cy.get('[data-testid="add-item-Taxonomy Project IDs"]') - .scrollIntoView() - .click(); - checkServiceFieldSectionHighlighting('taxonomyProjectID'); - cy.get('#root\\/taxonomyProjectID\\/0') - .scrollIntoView() - .type(Cypress.env('bigqueryProjectIdTaxonomy')); - checkServiceFieldSectionHighlighting('taxonomyProjectID'); - }; - - const addIngestionInput = () => { - cy.get('#root\\/schemaFilterPattern\\/includes') - .scrollIntoView() - .type(`${filterPattern}{enter}`); - }; - - testServiceCreationAndIngestion({ - serviceType, - connectionInput, - addIngestionInput, - serviceName, - serviceCategory: SERVICE_TYPE.Database, - }); - }); - - it('Update table description and verify description after re-run', () => { - updateDescriptionForIngestedTables( - serviceName, - tableName, - description, - SERVICE_TYPE.Database, - 'tables' - ); - }); - - it('delete created service', () => { - deleteCreatedService( - SERVICE_TYPE.Database, - serviceName, - API_SERVICE.databaseServices - ); - }); -}); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/glue.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/glue.spec.js deleted file mode 100644 index dfc3e877728..00000000000 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/glue.spec.js +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2022 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 { - checkServiceFieldSectionHighlighting, - deleteCreatedService, - goToAddNewServicePage, - testServiceCreationAndIngestion, - updateDescriptionForIngestedTables, - uuid, -} from '../../common/common'; -import { API_SERVICE, SERVICE_TYPE } from '../../constants/constants'; - -const serviceType = 'Glue'; -const serviceName = `${serviceType}-ct-test-${uuid()}`; -const tableName = 'cloudfront_logs2'; -const description = `This is ${serviceName} description`; -const filterPattern = 'default'; - -// We do not have creds for glue to validate -describe.skip('Glue Ingestion', () => { - beforeEach(() => { - cy.login(); - }); - - it('add and ingest data', () => { - goToAddNewServicePage(SERVICE_TYPE.Database); - const connectionInput = () => { - cy.get('#root\\/awsConfig\\/awsAccessKeyId') - .scrollIntoView() - .type(Cypress.env('glueAwsAccessKeyId')); - checkServiceFieldSectionHighlighting('awsAccessKeyId'); - cy.get('#root\\/awsConfig\\/awsSecretAccessKey') - .scrollIntoView() - .type(Cypress.env('glueAwsSecretAccessKey')); - checkServiceFieldSectionHighlighting('awsSecretAccessKey'); - cy.get('#root\\/awsConfig\\/awsRegion') - .scrollIntoView() - .type(Cypress.env('glueAwsRegion')); - checkServiceFieldSectionHighlighting('awsRegion'); - cy.get('#root\\/awsConfig\\/endPointURL') - .scrollIntoView() - .type(Cypress.env('glueEndPointURL')); - checkServiceFieldSectionHighlighting('endPointURL'); - }; - - const addIngestionInput = () => { - cy.get('#root\\/schemaFilterPattern\\/includes') - .scrollIntoView() - .type(`${filterPattern}{enter}`); - }; - - testServiceCreationAndIngestion({ - serviceType, - connectionInput, - addIngestionInput, - serviceName, - testIngestionButton: false, - serviceCategory: SERVICE_TYPE.Database, - }); - }); - - it('Update table description and verify description after re-run', () => { - updateDescriptionForIngestedTables( - serviceName, - tableName, - description, - SERVICE_TYPE.Database, - 'tables' - ); - }); - - it('delete created service', () => { - deleteCreatedService( - SERVICE_TYPE.Database, - serviceName, - API_SERVICE.databaseServices - ); - }); -}); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/kafka.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/kafka.spec.js deleted file mode 100644 index 280916d9a26..00000000000 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/kafka.spec.js +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2022 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 { - checkServiceFieldSectionHighlighting, - deleteCreatedService, - goToAddNewServicePage, - testServiceCreationAndIngestion, - updateDescriptionForIngestedTables, - uuid, -} from '../../common/common'; -import { API_SERVICE, SERVICE_TYPE } from '../../constants/constants'; - -const serviceType = 'Kafka'; -const serviceName = `${serviceType}-ct-test-${uuid()}`; -const topicName = '__transaction_state'; -const description = `This is ${serviceName} description`; - -describe('Kafka Ingestion', () => { - beforeEach(() => { - cy.login(); - }); - - it('add and ingest data', () => { - goToAddNewServicePage(SERVICE_TYPE.Messaging); - - // Select Dashboard services - cy.get('[data-testid="service-category"]').should('be.visible').click(); - cy.get('.ant-select-item-option-content') - .contains('Messaging Services') - .click(); - - const connectionInput = () => { - cy.get('#root\\/bootstrapServers').type( - Cypress.env('kafkaBootstrapServers') - ); - checkServiceFieldSectionHighlighting('bootstrapServers'); - cy.get('#root\\/schemaRegistryURL').type( - Cypress.env('kafkaSchemaRegistryUrl') - ); - checkServiceFieldSectionHighlighting('schemaRegistryURL'); - }; - - const addIngestionInput = () => { - cy.get('#root\\/topicFilterPattern\\/includes') - .scrollIntoView() - - .type(`${topicName}{enter}`); - }; - - testServiceCreationAndIngestion({ - serviceType: 'Kafka', - connectionInput, - addIngestionInput, - serviceName, - type: 'messaging', - serviceCategory: SERVICE_TYPE.Messaging, - }); - }); - - it('Update table description and verify description after re-run', () => { - updateDescriptionForIngestedTables( - serviceName, - topicName, - description, - SERVICE_TYPE.Messaging, - 'topics' - ); - }); - - it('delete created service', () => { - deleteCreatedService( - SERVICE_TYPE.Messaging, - serviceName, - API_SERVICE.messagingServices - ); - }); -}); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/metabase.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/metabase.spec.js deleted file mode 100644 index 9839ea12340..00000000000 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/metabase.spec.js +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2022 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 { - checkServiceFieldSectionHighlighting, - deleteCreatedService, - goToAddNewServicePage, - testServiceCreationAndIngestion, - updateDescriptionForIngestedTables, - uuid, -} from '../../common/common'; -import { API_SERVICE, SERVICE_TYPE } from '../../constants/constants'; - -const serviceType = 'Metabase'; -const serviceName = `${serviceType}-ct-test-${uuid()}`; -const tableName = 'jaffle_shop dashboard'; -const description = `This is ${serviceName} description`; - -describe('Metabase Ingestion', () => { - beforeEach(() => { - cy.login(); - }); - - it('add and ingest data', () => { - goToAddNewServicePage(SERVICE_TYPE.Dashboard); - - // Select Dashboard services - cy.get('[data-testid="service-category"]').should('be.visible').click(); - cy.get('.ant-select-item-option-content') - .contains('Dashboard Services') - .click(); - - const connectionInput = () => { - cy.get('#root\\/username') - .scrollIntoView() - .type(Cypress.env('metabaseUsername')); - checkServiceFieldSectionHighlighting('username'); - cy.get('#root\\/password') - .scrollIntoView() - .type(Cypress.env('metabasePassword')); - checkServiceFieldSectionHighlighting('password'); - cy.get('#root\\/hostPort') - .scrollIntoView() - .type(Cypress.env('metabaseHostPort')); - checkServiceFieldSectionHighlighting('hostPort'); - }; - - const addIngestionInput = () => { - cy.get('#root\\/dashboardFilterPattern\\/includes') - .scrollIntoView() - - .type(`${tableName}{enter}`); - }; - - testServiceCreationAndIngestion({ - serviceType, - connectionInput, - addIngestionInput, - serviceName, - type: 'dashboard', - serviceCategory: SERVICE_TYPE.Dashboard, - }); - }); - - it.skip('Update table description and verify description after re-run', () => { - updateDescriptionForIngestedTables( - serviceName, - tableName, - description, - SERVICE_TYPE.Dashboard, - 'dashboards' - ); - }); - - it('delete created service', () => { - deleteCreatedService( - SERVICE_TYPE.Dashboard, - serviceName, - API_SERVICE.dashboardServices - ); - }); -}); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/mysql.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/mysql.spec.js deleted file mode 100644 index 3812190624e..00000000000 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/mysql.spec.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2022 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 { - deleteCreatedService, - goToAddNewServicePage, - mySqlConnectionInput, - testServiceCreationAndIngestion, - updateDescriptionForIngestedTables, - uuid, -} from '../../common/common'; -import { - API_SERVICE, - SERVICE_TYPE, - TEAM_ENTITY, -} from '../../constants/constants'; - -const serviceType = 'Mysql'; -const serviceName = `${serviceType}.ct%test-${uuid()}`; -const tableName = TEAM_ENTITY; -const description = `This is ${tableName} description`; - -describe('MySQL Ingestion', () => { - beforeEach(() => { - cy.login(); - }); - - it('add and ingest data', () => { - goToAddNewServicePage(SERVICE_TYPE.Database); - - const addIngestionInput = () => { - cy.get('#root\\/schemaFilterPattern\\/includes') - .scrollIntoView() - .type(`${Cypress.env('mysqlDatabaseSchema')}{enter}`); - }; - - const viewIngestionInput = () => { - cy.get('.ant-select-selection-item-content') - .scrollIntoView() - .contains(`${Cypress.env('mysqlDatabaseSchema')}`); - }; - - testServiceCreationAndIngestion({ - serviceType, - connectionInput: mySqlConnectionInput, - addIngestionInput, - serviceName, - serviceCategory: SERVICE_TYPE.Database, - viewIngestionInput, - }); - }); - - it('Update table description and verify description after re-run', () => { - updateDescriptionForIngestedTables( - serviceName, - tableName, - description, - SERVICE_TYPE.Database, - 'tables' - ); - }); - - it('delete created service', () => { - deleteCreatedService( - SERVICE_TYPE.Database, - serviceName, - API_SERVICE.databaseServices - ); - }); -}); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/snowflake.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/snowflake.spec.js deleted file mode 100644 index 8ca595b4e15..00000000000 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/snowflake.spec.js +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2022 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 { - checkServiceFieldSectionHighlighting, - deleteCreatedService, - goToAddNewServicePage, - testServiceCreationAndIngestion, - updateDescriptionForIngestedTables, - uuid, -} from '../../common/common'; -import { API_SERVICE, SERVICE_TYPE } from '../../constants/constants'; - -const serviceType = 'Snowflake'; -const serviceName = `${serviceType}-ct-test-${uuid()}`; -const tableName = 'CUSTOMER'; -const schema = 'TPCH_SF1000'; -const description = `This is ${serviceName} description`; -const entityFqn = `${serviceName}.${Cypress.env( - 'snowflakeDatabase' -)}.${schema}.${tableName}`; - -describe('Snowflake Ingestion', () => { - beforeEach(() => { - cy.login(); - }); - - it('add and ingest data', { defaultCommandTimeout: 8000 }, () => { - goToAddNewServicePage(SERVICE_TYPE.Database); - const connectionInput = () => { - cy.get('#root\\/username').type(Cypress.env('snowflakeUsername')); - checkServiceFieldSectionHighlighting('username'); - cy.get('#root\\/password').type(Cypress.env('snowflakePassword')); - checkServiceFieldSectionHighlighting('password'); - cy.get('#root\\/account').type(Cypress.env('snowflakeAccount')); - checkServiceFieldSectionHighlighting('account'); - cy.get('#root\\/database').type(Cypress.env('snowflakeDatabase')); - checkServiceFieldSectionHighlighting('database'); - cy.get('#root\\/warehouse').type(Cypress.env('snowflakeWarehouse')); - checkServiceFieldSectionHighlighting('warehouse'); - }; - - const addIngestionInput = () => { - cy.get('#root\\/schemaFilterPattern\\/includes') - .scrollIntoView() - - .type(`${schema}{enter}`); - }; - - testServiceCreationAndIngestion({ - serviceType, - connectionInput, - addIngestionInput, - serviceName, - serviceCategory: SERVICE_TYPE.Database, - }); - }); - - it('Update table description and verify description after re-run', () => { - updateDescriptionForIngestedTables( - serviceName, - tableName, - description, - SERVICE_TYPE.Database, - 'tables', - entityFqn - ); - }); - - it('delete created service', () => { - deleteCreatedService( - SERVICE_TYPE.Database, - serviceName, - API_SERVICE.databaseServices - ); - }); -}); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/superset.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/superset.spec.js deleted file mode 100644 index 8ea3f16cae6..00000000000 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Service/superset.spec.js +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2022 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 { - deleteCreatedService, - goToAddNewServicePage, - testServiceCreationAndIngestion, - updateDescriptionForIngestedTables, - uuid, -} from '../../common/common'; -import { API_SERVICE, SERVICE_TYPE } from '../../constants/constants'; - -const serviceType = 'Superset'; -const serviceName = `${serviceType}-ct-test-${uuid()}`; -const tableName = "World Bank's Data"; -const description = `This is ${serviceName} description`; - -describe('Superset Ingestion', () => { - beforeEach(() => { - cy.login(); - }); - - it('add and ingest data', () => { - goToAddNewServicePage(SERVICE_TYPE.Dashboard); - - // Select Dashboard services - cy.get('[data-testid="service-category"]').should('be.visible').click(); - cy.get('.ant-select-item-option-content') - .contains('Dashboard Services') - .click(); - - const connectionInput = () => { - cy.get('#root\\/connection\\/username') - .scrollIntoView() - .type(Cypress.env('supersetUsername')); - cy.get('#root\\/connection\\/password') - .scrollIntoView() - .type(Cypress.env('supersetPassword')); - cy.get('#root\\/hostPort') - .scrollIntoView() - .focus() - .clear() - .type(Cypress.env('supersetHostPort')); - }; - - const addIngestionInput = () => { - cy.get('#root\\/dashboardFilterPattern\\/includes') - .scrollIntoView() - - .type(`${tableName}{enter}`); - }; - - testServiceCreationAndIngestion({ - serviceType, - connectionInput, - addIngestionInput, - serviceName, - type: 'dashboard', - serviceCategory: SERVICE_TYPE.Dashboard, - }); - }); - - it('Update table description and verify description after re-run', () => { - updateDescriptionForIngestedTables( - serviceName, - tableName, - description, - SERVICE_TYPE.Dashboard, - 'dashboards' - ); - }); - - it('delete created service', () => { - deleteCreatedService( - SERVICE_TYPE.Dashboard, - serviceName, - API_SERVICE.dashboardServices - ); - }); -}); diff --git a/openmetadata-ui/src/main/resources/ui/cypress/support/commands.js b/openmetadata-ui/src/main/resources/ui/cypress/support/commands.js index 1c9803631d6..a520d101769 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/support/commands.js +++ b/openmetadata-ui/src/main/resources/ui/cypress/support/commands.js @@ -126,6 +126,7 @@ Cypress.Commands.add('storeSession', (username, password) => { .replaceAll('.', '_')}`; cy.setCookie(versionCookie, 'true'); + window.localStorage.setItem('loggedInUsers', 'admin'); }); }); }); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityList/EntityList.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityList/EntityList.tsx index 956c68380c0..22a164f3d8d 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityList/EntityList.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityList/EntityList.tsx @@ -62,9 +62,7 @@ export const EntityListWithV1: FunctionComponent = ({ return (
= ({
{tabItems.length > 0 && ( - + {t('label.data-asset-plural')} diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseDetailsPage/DatabaseDetailsPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseDetailsPage/DatabaseDetailsPage.tsx index 2accc50a88d..a57522991fb 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseDetailsPage/DatabaseDetailsPage.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseDetailsPage/DatabaseDetailsPage.tsx @@ -197,6 +197,7 @@ const DatabaseDetails: FunctionComponent = () => { setIsDatabaseDetailsLoading(true); getDatabaseDetailsByFQN(databaseFQN, { fields: 'owner,tags,domain,votes', + include: Include.All, }) .then((res) => { if (res) { diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseSchemaPage/SchemaTablesTab.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseSchemaPage/SchemaTablesTab.tsx index 469cd4bb94b..4b174851d8b 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseSchemaPage/SchemaTablesTab.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseSchemaPage/SchemaTablesTab.tsx @@ -80,7 +80,7 @@ function SchemaTablesTab({
{ setIsLoadingOwnedData(true); try { const userData = await getUserById(currentUser?.id, { - fields: 'follows, owns', + fields: 'follows,owns', }); if (userData) { diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/StoredProcedure/StoredProcedurePage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/StoredProcedure/StoredProcedurePage.test.tsx index 38f4fee0029..82482719268 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/StoredProcedure/StoredProcedurePage.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/StoredProcedure/StoredProcedurePage.test.tsx @@ -160,6 +160,7 @@ describe('StoredProcedure component', () => { expect(getStoredProceduresByFqn).toHaveBeenCalledWith('fqn', { fields: STORED_PROCEDURE_DEFAULT_FIELDS, + include: 'all', }); }); @@ -178,6 +179,7 @@ describe('StoredProcedure component', () => { expect(getStoredProceduresByFqn).toHaveBeenCalledWith('fqn', { fields: STORED_PROCEDURE_DEFAULT_FIELDS, + include: 'all', }); }); @@ -208,6 +210,7 @@ describe('StoredProcedure component', () => { expect(getStoredProceduresByFqn).toHaveBeenCalledWith('fqn', { fields: STORED_PROCEDURE_DEFAULT_FIELDS, + include: 'all', }); expect(await screen.findByText('testDataAssetsHeader')).toBeInTheDocument(); @@ -234,6 +237,7 @@ describe('StoredProcedure component', () => { expect(getStoredProceduresByFqn).toHaveBeenCalledWith('fqn', { fields: STORED_PROCEDURE_DEFAULT_FIELDS, + include: 'all', }); expect(await screen.findByText('testSchemaEditor')).toBeInTheDocument(); diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/StoredProcedure/StoredProcedurePage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/StoredProcedure/StoredProcedurePage.tsx index 0cf5853ef0e..93af998b720 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/StoredProcedure/StoredProcedurePage.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/StoredProcedure/StoredProcedurePage.tsx @@ -57,6 +57,7 @@ import { StoredProcedure, StoredProcedureCodeObject, } from '../../generated/entity/data/storedProcedure'; +import { Include } from '../../generated/type/include'; import { TagLabel } from '../../generated/type/tagLabel'; import { postThread } from '../../rest/feedsAPI'; import { @@ -172,6 +173,7 @@ const StoredProcedurePage = () => { try { const response = await getStoredProceduresByFqn(storedProcedureFQN, { fields: STORED_PROCEDURE_DEFAULT_FIELDS, + include: Include.All, }); setStoredProcedure(response); diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/SearchClassBase.ts b/openmetadata-ui/src/main/resources/ui/src/utils/SearchClassBase.ts index 13046fc7f73..10c61ffef94 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/SearchClassBase.ts +++ b/openmetadata-ui/src/main/resources/ui/src/utils/SearchClassBase.ts @@ -80,7 +80,7 @@ class SearchClassBase { path: 'dashboards', }, [SearchIndex.DASHBOARD_DATA_MODEL]: { - label: i18n.t('label.data-model-plural'), + label: i18n.t('label.dashboard-data-model-plural'), sortingFields: entitySortingFields, sortField: INITIAL_SORT_FIELD, path: 'dashboardDataModel',