diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/EntityUtils.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/EntityUtils.ts index 1f69a9390c6..f15466c289e 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/common/EntityUtils.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/EntityUtils.ts @@ -23,6 +23,13 @@ import { } from '../constants/EntityConstant'; import { uuid } from './common'; +type ColumnType = { + name: string; + description: string; + dataType: string; + dataTypeDisplay: string; +}; + /** * create full hierarchy of database service (service > database > schema > tables) */ @@ -137,15 +144,19 @@ export const hardDeleteService = ({ serviceFqn, token, serviceType }) => { }); }; -export const generateRandomTable = () => { +export const generateRandomTable = ( + tableName?: string, + columns?: ColumnType[] +) => { const id = uuid(); - const name = `cypress-table-${id}`; + const name = tableName ?? `cypress-table-${id}`; const table = { name, description: `cypress-table-description-${id}`, displayName: name, columns: [ + ...(columns ?? []), { name: `cypress-column-${id}`, description: `cypress-column-description-${id}`, diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/DataQuality.ts b/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/DataQuality.ts index 62a3f999005..86a9209bf14 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/DataQuality.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/common/Utils/DataQuality.ts @@ -41,6 +41,14 @@ const testCase2 = { testSuite: testSuite.name, }; const filterTable = generateRandomTable(); +const customTable = generateRandomTable(`cypress-table-${uuid()}-COLUMN`, [ + { + name: `user_id`, + description: `cypress-column-description`, + dataType: 'STRING', + dataTypeDisplay: 'string', + }, +]); const filterTableFqn = `${filterTable.databaseSchema}.${filterTable.name}`; const filterTableTestSuite = { @@ -57,6 +65,7 @@ export const DATA_QUALITY_TEST_CASE_DATA = { testCase1, testCase2, filterTable, + customTable, filterTableTestCases: testCases, }; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/constants/constants.ts b/openmetadata-ui/src/main/resources/ui/cypress/constants/constants.ts index e7138801961..d186d47c579 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/constants/constants.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/constants/constants.ts @@ -224,7 +224,6 @@ export const RECENT_SEARCH_TITLE = 'Recent Search Terms'; export const RECENT_VIEW_TITLE = 'Recent Views'; export const MY_DATA_TITLE = 'My Data'; export const FOLLOWING_TITLE = 'Following'; -export const TEAM_ENTITY = 'alert_entity'; export const NO_SEARCHED_TERMS = 'No searched terms'; export const DELETE_TERM = 'DELETE'; @@ -251,7 +250,7 @@ export const NEW_TABLE_TEST_CASE = { export const NEW_COLUMN_TEST_CASE = { name: 'id_column_value_lengths_to_be_between', - column: 'id', + column: 'user_id', type: 'columnValueLengthsToBeBetween', label: 'Column Value Lengths To Be Between', min: '3', @@ -261,7 +260,7 @@ export const NEW_COLUMN_TEST_CASE = { export const NEW_COLUMN_TEST_CASE_WITH_NULL_TYPE = { name: 'id_column_values_to_be_not_null', - column: 'id', + column: 'user_id', type: 'columnValuesToBeNotNull', label: 'Column Values To Be Not Null', description: 'New table test case for columnValuesToBeNotNull', diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/DataQualityAndProfiler.spec.ts b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/DataQualityAndProfiler.spec.ts index 3875c53c7e2..99bbbde60f6 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/DataQualityAndProfiler.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/DataQualityAndProfiler.spec.ts @@ -40,18 +40,18 @@ import { NEW_COLUMN_TEST_CASE_WITH_NULL_TYPE, NEW_TABLE_TEST_CASE, NEW_TEST_SUITE, - TEAM_ENTITY, } from '../../constants/constants'; import { EntityType, SidebarItem } from '../../constants/Entity.interface'; import { DATABASE_SERVICE } from '../../constants/EntityConstant'; import { SERVICE_CATEGORIES } from '../../constants/service.constants'; import { GlobalSettingOptions } from '../../constants/settings.constant'; -const serviceName = `cypress-mysql`; const OWNER1 = 'Aaron Johnson'; const OWNER2 = 'Cynthia Meyer'; -const { testCase1, testCase2, filterTable, filterTableTestCases } = +const { testCase1, testCase2, filterTable, filterTableTestCases, customTable } = DATA_QUALITY_TEST_CASE_DATA; +const TEAM_ENTITY = customTable.name; +const serviceName = DATABASE_SERVICE.service.name; const goToProfilerTab = (data?: { service: string; entityName: string }) => { interceptURL( 'GET', @@ -111,7 +111,7 @@ describe( createEntityTable({ token, ...DATABASE_SERVICE, - tables: [DATABASE_SERVICE.entity, filterTable], + tables: [DATABASE_SERVICE.entity, filterTable, customTable], }); prepareDataQualityTestCases(token); @@ -143,13 +143,17 @@ describe( }); it('Add Profiler ingestion', () => { + const data = { + entityName: 'alert_entity', + service: 'cypress-mysql', + }; interceptURL( 'POST', '/api/v1/services/ingestionPipelines/deploy/*', 'deployIngestion' ); - goToProfilerTab(); + goToProfilerTab(data); cy.get('[data-testid="no-profiler-placeholder"]').should('be.visible'); cy.clickOnLogo(); @@ -162,8 +166,8 @@ describe( '/api/v1/system/config/pipeline-service-client', 'airflow' ); - searchServiceFromSettingPage(serviceName); - cy.get(`[data-testid="service-name-${serviceName}"]`) + searchServiceFromSettingPage(data.service); + cy.get(`[data-testid="service-name-${data.service}"]`) .should('exist') .click(); cy.get('[data-testid="tabs"]').should('exist'); @@ -204,16 +208,18 @@ describe( }); it('Verifying profiler ingestion', () => { - goToProfilerTab(); + goToProfilerTab({ + entityName: 'alert_entity', + service: 'cypress-mysql', + }); cy.get('[data-testid="no-profiler-placeholder"]').should('not.exist'); }); it('Add table test case', () => { - const term = TEAM_ENTITY; goToProfilerTab(); interceptURL( 'GET', - `api/v1/tables/name/${serviceName}.*.${term}?include=all`, + `api/v1/tables/name/${serviceName}.*.${TEAM_ENTITY}?include=all`, 'addTableTestPage' ); verifyResponseStatusCode('@systemProfile', 200); @@ -984,7 +990,7 @@ describe( // Test case filter by test type interceptURL( 'GET', - `/api/v1/dataQuality/testCases/search/list?*testCaseType=column*entityLink=*${filterTable.name}*`, + `/api/v1/dataQuality/testCases/search/list?*testCaseType=column*`, 'testCaseTypeByColumn' ); cy.get('[data-testid="test-case-type-select-filter"]').click(); @@ -994,7 +1000,7 @@ describe( interceptURL( 'GET', - `/api/v1/dataQuality/testCases/search/list?*testCaseType=table*entityLink=*${filterTable.name}*`, + `/api/v1/dataQuality/testCases/search/list?*testCaseType=table*`, 'testCaseTypeByTable' ); cy.get('[data-testid="test-case-type-select-filter"]').click(); @@ -1009,7 +1015,7 @@ describe( // Test case filter by status interceptURL( 'GET', - `/api/v1/dataQuality/testCases/search/list?*testCaseStatus=Success*entityLink=*${filterTable.name}*`, + `/api/v1/dataQuality/testCases/search/list?*testCaseStatus=Success*`, 'testCaseStatusBySuccess' ); cy.get('[data-testid="status-select-filter"]').click(); @@ -1019,7 +1025,7 @@ describe( interceptURL( 'GET', - `/api/v1/dataQuality/testCases/search/list?*testCaseStatus=Failed*entityLink=*${filterTable.name}*`, + `/api/v1/dataQuality/testCases/search/list?*testCaseStatus=Failed*`, 'testCaseStatusByFailed' ); cy.get('[data-testid="status-select-filter"]').click(); @@ -1030,7 +1036,7 @@ describe( // Test case filter by platform interceptURL( 'GET', - `/api/v1/dataQuality/testCases/search/list?*testPlatforms=DBT*entityLink=*${filterTable.name}*`, + `/api/v1/dataQuality/testCases/search/list?*testPlatforms=DBT*`, 'testCasePlatformByDBT' ); cy.get('[data-testid="platform-select-filter"]').click(); @@ -1045,7 +1051,7 @@ describe( interceptURL( 'GET', - `/api/v1/dataQuality/testCases/search/list?*testPlatforms=OpenMetadata*entityLink=*${filterTable.name}*`, + `/api/v1/dataQuality/testCases/search/list?*testPlatforms=OpenMetadata*`, 'testCasePlatformByOpenMetadata' ); cy.get('[data-testid="platform-select-filter"]').click(); diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/EntityLink.test.ts b/openmetadata-ui/src/main/resources/ui/src/utils/EntityLink.test.ts index c0c088595cf..e96b47a97e6 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/EntityLink.test.ts +++ b/openmetadata-ui/src/main/resources/ui/src/utils/EntityLink.test.ts @@ -18,6 +18,7 @@ const entityLinkWithColumn = '<#E::table::sample_data.ecommerce_db.shopify.dim_address::columns::address_id::tags>'; const entityLinkWithNestedColumn = '<#E::table::sample_data.ecommerce_db.shopify.dim_address::columns::"address_id.city"::tags>'; +const tableFqn = 'sample_data.ecommerce_db.shopify.dim_address'; describe('Test EntityLink', () => { it('Should split the entityLink into parts', () => { @@ -103,4 +104,30 @@ describe('Test EntityLink', () => { 'sample_data.ecommerce_db.shopify.dim_address."address_id.city"' ); }); + + it('Should return the entity link for table without column name', () => { + const entityLink = EntityLink.getTableEntityLink(tableFqn); + + expect(entityLink).toStrictEqual( + '<#E::table::sample_data.ecommerce_db.shopify.dim_address>' + ); + }); + + it('Should return the entity link for table without column name, if empty string is pass', () => { + const columnName = ''; + const entityLink = EntityLink.getTableEntityLink(tableFqn, columnName); + + expect(entityLink).toStrictEqual( + '<#E::table::sample_data.ecommerce_db.shopify.dim_address>' + ); + }); + + it('Should return the entity link for table with column name', () => { + const columnName = 'address_id'; + const entityLink = EntityLink.getTableEntityLink(tableFqn, columnName); + + expect(entityLink).toStrictEqual( + '<#E::table::sample_data.ecommerce_db.shopify.dim_address::columns::address_id>' + ); + }); }); diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/EntityLink.ts b/openmetadata-ui/src/main/resources/ui/src/utils/EntityLink.ts index 5107d526456..20ef73c7f6c 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/EntityLink.ts +++ b/openmetadata-ui/src/main/resources/ui/src/utils/EntityLink.ts @@ -101,7 +101,7 @@ export default class EntityLink { * @param string | undefined columnName * @returns entity link for table */ - static getTableEntityLink(tableFqn: string, columnName: string) { + static getTableEntityLink(tableFqn: string, columnName?: string) { if (columnName) { return `<#E${ENTITY_LINK_SEPARATOR}table${ENTITY_LINK_SEPARATOR}${tableFqn}${ENTITY_LINK_SEPARATOR}columns${ENTITY_LINK_SEPARATOR}${columnName}>`; } else { diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/TableUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/TableUtils.tsx index 336fe3b04d1..859ee38a79c 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/TableUtils.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/utils/TableUtils.tsx @@ -83,6 +83,7 @@ import { getTableFQNFromColumnFQN, sortTagsCaseInsensitive, } from './CommonUtils'; +import EntityLink from './EntityLink'; import serviceUtilClassBase from './ServiceUtilClassBase'; import { ordinalize } from './StringsUtils'; import { TableFieldsInfoCommonEntities } from './TableUtils.interface'; @@ -410,18 +411,13 @@ export const getDataTypeString = (dataType: string): string => { }; export const generateEntityLink = (fqn: string, includeColumn = false) => { - const columnLink = '<#E::table::ENTITY_FQN::columns::COLUMN>'; - const tableLink = '<#E::table::ENTITY_FQN>'; - if (includeColumn) { const tableFqn = getTableFQNFromColumnFQN(fqn); const columnName = getPartialNameFromTableFQN(fqn, [FqnPart.NestedColumn]); - return columnLink - .replace('ENTITY_FQN', tableFqn) - .replace('COLUMN', columnName); + return EntityLink.getTableEntityLink(tableFqn, columnName); } else { - return tableLink.replace('ENTITY_FQN', fqn); + return EntityLink.getTableEntityLink(fqn); } };