diff --git a/openmetadata-ui/src/main/resources/ui/playwright/constant/sidebar.ts b/openmetadata-ui/src/main/resources/ui/playwright/constant/sidebar.ts index 121e228ac67..ad1893b8c2d 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/constant/sidebar.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/constant/sidebar.ts @@ -20,6 +20,8 @@ export enum SidebarItem { DOMAIN = 'domain', GOVERNANCE = 'governance', GLOSSARY = 'glossary', + DOMAINS = 'domains-section', + DATA_PRODUCTS = 'data-products', TAGS = 'tags', INSIGHTS = 'data-insight', SETTINGS = 'settings', @@ -44,6 +46,7 @@ export const SIDEBAR_LIST_ITEMS = { [SidebarItem.GLOSSARY]: [SidebarItem.GOVERNANCE, SidebarItem.GLOSSARY], [SidebarItem.TAGS]: [SidebarItem.GOVERNANCE, SidebarItem.TAGS], [SidebarItem.METRICS]: [SidebarItem.GOVERNANCE, SidebarItem.METRICS], + [SidebarItem.DOMAIN]: [SidebarItem.DOMAINS, SidebarItem.DOMAIN], // Profile Dropdown 'user-name': ['dropdown-profile', 'user-name'], diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Domains.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Domains.spec.ts index 8c2096f6921..075e22cb7cf 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Domains.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Domains.spec.ts @@ -10,18 +10,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * 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 base, { APIRequestContext, expect, Page } from '@playwright/test'; import { Operation } from 'fast-json-patch'; import { get } from 'lodash'; @@ -169,6 +157,12 @@ test.describe('Domains', () => { await test.step('Create domain', async () => { await sidebarClick(page, SidebarItem.DOMAIN); + + await page.waitForLoadState('networkidle'); + await page.waitForSelector('[data-testid="loader"]', { + state: 'detached', + }); + await createDomain(page, domain.data, false); await verifyDomain(page, domain.data); }); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/domain.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/domain.ts index 8349afd02f1..5f26fc98f0e 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/domain.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/domain.ts @@ -33,13 +33,14 @@ import { NAME_MAX_LENGTH_VALIDATION_ERROR, NAME_VALIDATION_ERROR, redirectToHomePage, + toastNotification, uuid, } from './common'; import { addOwner, waitForAllLoadersToDisappear } from './entity'; import { sidebarClick } from './sidebar'; export const assignDomain = async (page: Page, domain: Domain['data']) => { - await page.getByTestId('add-domain').click(); + await page.getByTestId('add-entity-button').click(); await page.waitForSelector('[data-testid="loader"]', { state: 'detached' }); const searchDomain = page.waitForResponse( `/api/v1/search/query?q=*${encodeURIComponent(domain.name)}*` @@ -65,7 +66,7 @@ export const assignDomain = async (page: Page, domain: Domain['data']) => { }; export const updateDomain = async (page: Page, domain: Domain['data']) => { - await page.getByTestId('add-domain').click(); + await page.getByTestId('add-entity-button').click(); await page.waitForSelector('[data-testid="loader"]', { state: 'detached' }); await page.getByTestId('selectable-list').getByTestId('searchbar').clear(); const searchDomain = page.waitForResponse( @@ -84,7 +85,7 @@ export const updateDomain = async (page: Page, domain: Domain['data']) => { }; export const removeDomain = async (page: Page) => { - await page.getByTestId('add-domain').click(); + await page.getByTestId('add-entity-button').click(); await page.waitForSelector('[data-testid="loader"]', { state: 'detached' }); await expect(page.getByTestId('remove-owner').locator('path')).toBeVisible(); @@ -117,27 +118,24 @@ export const validateDomainForm = async (page: Page) => { await expect(page.locator('#name_help')).toHaveText(NAME_VALIDATION_ERROR); }; -export const selectDomain = async ( - page: Page, - domain: Domain['data'], - bWaitForResponse = true -) => { - const menuItem = page.getByRole('menuitem', { name: domain.displayName }); - const isSelected = await menuItem.evaluate((element) => { - return element.classList.contains('ant-menu-item-selected'); +export const selectDomain = async (page: Page, domain: Domain['data']) => { + const searchBox = page + .getByTestId('page-layout-v1') + .getByRole('textbox', { name: 'Search' }); + + const domainRes = page.waitForResponse( + '/api/v1/search/query?q=*&index=domain_search_index*' + ); + + await searchBox.fill(domain.name); + + await domainRes; + + await page.waitForSelector('[data-testid="loader"]', { + state: 'detached', }); - if (!isSelected) { - if (bWaitForResponse) { - const domainRes = page.waitForResponse( - '/api/v1/domains/name/*?fields=children%2Cowners%2Cparent%2Cexperts%2Ctags%2Cfollowers%2Cextension' - ); - await menuItem.click(); - await domainRes; - } else { - await menuItem.click(); - } - } + await page.getByRole('row', { name: domain.displayName }).click(); await page.waitForLoadState('networkidle'); @@ -220,7 +218,7 @@ export const selectDataProduct = async ( const goToAssetsTab = async (page: Page, domain: Domain['data']) => { await selectDomain(page, domain); await checkDomainDisplayName(page, domain.displayName); - await page.getByTestId('assets').click(); + await page.getByRole('tab', { name: /Assets/ }).click(); await waitForAllLoadersToDisappear(page); }; @@ -228,8 +226,8 @@ const fillCommonFormItems = async ( page: Page, entity: Domain['data'] | DataProduct['data'] | SubDomain['data'] ) => { - await page.locator('[data-testid="name"]').fill(entity.name); - await page.locator('[data-testid="display-name"]').fill(entity.displayName); + await page.locator('#root\\/name').fill(entity.name); + await page.locator('#root\\/displayName').fill(entity.displayName); await page.locator(descriptionBox).fill(entity.description); if (!isEmpty(entity.owners) && !isUndefined(entity.owners)) { await addOwner({ @@ -249,16 +247,11 @@ export const fillDomainForm = async ( isDomain = true ) => { await fillCommonFormItems(page, entity); - if (isDomain) { - await page.click('[data-testid="domainType"]'); - } else { - await page - .getByLabel('Add Sub Domain') - .getByTestId('domainType') - .locator('div') - .click(); - } - await page.getByTitle(entity.domainType).locator('div').click(); + + const domainTypeCombo = page.getByRole('combobox', { name: 'Domain Type' }); + await domainTypeCombo.click(); + + await page.getByRole('option', { name: entity.domainType }).click(); }; export const checkDomainDisplayName = async ( @@ -319,24 +312,29 @@ export const createDomain = async ( domain: Domain['data'], validate = false ) => { - await page.click('[data-testid="add-domain"]'); - await page.waitForSelector('[data-testid="form-heading"]'); + await page.click('[data-testid="add-entity-button"]'); - await expect(page.locator('[data-testid="form-heading"]')).toHaveText( - 'Add Domain' - ); + await page.waitForSelector('h6:has-text("Add Domain")', { timeout: 5000 }); - await page.click('[data-testid="save-domain"]'); + await expect(page.locator('h6:has-text("Add Domain")')).toBeVisible(); + + const saveButton = page.getByRole('button', { name: 'Save' }); if (validate) { + await saveButton.click(); await validateDomainForm(page); } await fillDomainForm(page, domain); const domainRes = page.waitForResponse('/api/v1/domains'); - await page.click('[data-testid="save-domain"]'); + await saveButton.click(); await domainRes; + + await toastNotification(page, /Domain created successfully/); + + await selectDomain(page, domain); + await checkDomainDisplayName(page, domain.displayName); await checkAssetsCount(page, 0); await checkDataProductCount(page, 0); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/atoms/table/useDataTable.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/atoms/table/useDataTable.tsx index 84a0afefc49..7ba16a392f8 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/atoms/table/useDataTable.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/atoms/table/useDataTable.tsx @@ -22,6 +22,7 @@ import { import { isEmpty } from 'lodash'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; +import Loader from '../../Loader/Loader'; import { TableViewConfig } from '../shared/types'; import { useTableRow } from './useTableRow'; @@ -73,7 +74,15 @@ export const useDataTable = ( - {isEmpty(listing.entities) && hasActiveFiltersOrSearch ? ( + {listing.loading ? ( + + + + + + ) : isEmpty(listing.entities) && hasActiveFiltersOrSearch ? ( = [ key: 'domains-section', title: 'label.domain-plural', icon: DomainsIcon, - dataTestId: `app-bar-item-${SidebarItem.DOMAINS_SECTION}`, + dataTestId: SidebarItem.DOMAINS_SECTION, children: [ { key: ROUTES.DOMAIN,