diff --git a/openmetadata-ui/src/main/resources/ui/playwright/support/entity/DatabaseSchemaClass.ts b/openmetadata-ui/src/main/resources/ui/playwright/support/entity/DatabaseSchemaClass.ts index 38aa8de0b95..d69e094fa3c 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/support/entity/DatabaseSchemaClass.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/support/entity/DatabaseSchemaClass.ts @@ -130,13 +130,22 @@ export class DatabaseSchemaClass extends EntityClass { false ); + await page.waitForLoadState('networkidle'); + + // Wait for the database to be visible before clicking + await page.getByTestId(this.database.name).waitFor({ state: 'visible' }); + const databaseResponse = page.waitForResponse( `/api/v1/databases/name/*${this.database.name}?**` ); await page.getByTestId(this.database.name).click(); await databaseResponse; + + // Wait for database schema to be visible + await page.getByTestId(this.entity.name).waitFor({ state: 'visible' }); + const databaseSchemaResponse = page.waitForResponse( - `/api/v1/databaseSchemas/name/*${this.entity}?*` + `/api/v1/databaseSchemas/name/*${this.entity.name}?*` ); await page.getByTestId(this.entity.name).click(); await databaseSchemaResponse; diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/common.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/common.ts index 8f1c8210440..efb01c39140 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/common.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/common.ts @@ -170,22 +170,31 @@ export const assignDomain = async ( ) => { await page.getByTestId('add-domain').click(); await page.waitForSelector('[data-testid="loader"]', { state: 'detached' }); + const searchDomain = page.waitForResponse( `/api/v1/search/query?q=*${encodeURIComponent(domain.name)}*` ); + await page .getByTestId('domain-selectable-tree') .getByTestId('searchbar') .fill(domain.name); + await searchDomain; - await page.getByTestId(`tag-${domain.fullyQualifiedName}`).click(); + // Wait for the tag element to be visible and ensure page is still valid + const tagSelector = page.getByTestId(`tag-${domain.fullyQualifiedName}`); + await tagSelector.waitFor({ state: 'visible' }); + await tagSelector.click(); const patchReq = page.waitForResponse( (req) => req.request().method() === 'PATCH' ); - await page.getByTestId('saveAssociatedTag').click(); + await page + .getByTestId('domain-selectable-tree') + .getByTestId('saveAssociatedTag') + .click(); await patchReq; await page.waitForSelector('[data-testid="loader"]', { state: 'detached' }); @@ -221,7 +230,10 @@ export const updateDomain = async ( (req) => req.request().method() === 'PATCH' ); - await page.getByTestId('saveAssociatedTag').click(); + await page + .getByTestId('domain-selectable-tree') + .getByTestId('saveAssociatedTag') + .click(); await patchReq; await page.waitForSelector('[data-testid="loader"]', { state: 'detached' }); @@ -247,7 +259,10 @@ export const removeDomain = async ( (req) => req.request().method() === 'PATCH' ); - await page.getByTestId('saveAssociatedTag').click(); + await page + .getByTestId('domain-selectable-tree') + .getByTestId('saveAssociatedTag') + .click(); await patchReq; await page.waitForSelector('[data-testid="loader"]', { state: 'detached' }); @@ -281,13 +296,20 @@ export const assignDataProduct = async ( await searchDataProduct; await page.getByTestId(`tag-${dataProduct.fullyQualifiedName}`).click(); - await expect(page.getByTestId('saveAssociatedTag')).toBeEnabled(); + await expect( + page + .getByTestId('data-product-dropdown-actions') + .getByTestId('saveAssociatedTag') + ).toBeEnabled(); const patchReq = page.waitForResponse( (req) => req.request().method() === 'PATCH' ); - await page.getByTestId('saveAssociatedTag').click(); + await page + .getByTestId('data-product-dropdown-actions') + .getByTestId('saveAssociatedTag') + .click(); await patchReq; await expect( @@ -320,13 +342,20 @@ export const removeDataProduct = async ( .locator('svg') .click(); - await expect(page.getByTestId('saveAssociatedTag')).toBeEnabled(); + await expect( + page + .getByTestId('data-product-dropdown-actions') + .getByTestId('saveAssociatedTag') + ).toBeEnabled(); const patchReq = page.waitForResponse( (req) => req.request().method() === 'PATCH' ); - await page.getByTestId('saveAssociatedTag').click(); + await page + .getByTestId('data-product-dropdown-actions') + .getByTestId('saveAssociatedTag') + .click(); await patchReq; await expect( diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/entity.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/entity.ts index 6a340ce56dc..400427ef8dd 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/entity.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/entity.ts @@ -94,7 +94,10 @@ export const visitEntityPage = async (data: { await waitForSearchResponse; await page.getByTestId(dataTestId).getByTestId('data-name').click(); - + await page.waitForLoadState('networkidle'); + await page.waitForSelector('[data-testid="loader"]', { + state: 'detached', + }); await page.getByTestId('searchBox').clear(); }; @@ -144,8 +147,13 @@ export const addOwner = async ({ await page.getByRole('listitem', { name: owner, exact: true }).click(); await patchRequest; } else { - await page.getByRole('listitem', { name: owner, exact: true }).click(); + const ownerItem = page.getByRole('listitem', { + name: owner, + exact: true, + }); + await ownerItem.waitFor({ state: 'visible' }); + await ownerItem.click(); const patchRequest = page.waitForResponse(`/api/v1/${endpoint}/*`); await page.getByTestId('selectable-list-update-btn').click(); await patchRequest; @@ -260,9 +268,10 @@ export const removeOwner = async ({ await patchRequest; - await expect( - page.getByTestId(dataTestId ?? 'owner-link').getByTestId(ownerName) - ).not.toBeVisible(); + await page + .getByTestId(dataTestId ?? 'owner-link') + .getByTestId(ownerName) + .waitFor({ state: 'hidden' }); }; export const addMultiOwner = async (data: { @@ -345,6 +354,9 @@ export const addMultiOwner = async (data: { name: ownerName, exact: true, }); + await ownerItem.waitFor({ state: 'visible' }); + + // Wait for the item to exist and be visible before clicking if (type === 'Teams') { if (isSelectableInsideForm) { @@ -544,11 +556,19 @@ export const assignTag = async ( .getByTestId(action === 'Add' ? 'add-tag' : 'edit-button') .click(); + // Wait for the form to be visible and stable + await page.locator('#tagsForm_tags').waitFor({ + state: 'visible', + }); + const searchTags = page.waitForResponse( `/api/v1/search/query?q=*${encodeURIComponent(tag)}*` ); + await page.locator('#tagsForm_tags').fill(tag); + await searchTags; + await page .getByTestId(`tag-${tagFqn ? `${tagFqn}` : tag}`) .first() @@ -742,13 +762,16 @@ export const assignGlossaryTerm = async ( .getByTestId('glossary-container') .getByTestId(action === 'Add' ? 'add-tag' : 'edit-button') .click(); - const searchGlossaryTerm = page.waitForResponse( `/api/v1/search/query?q=*${encodeURIComponent(glossaryTerm.displayName)}*` ); + // Wait for the form to be visible before proceeding + await page.locator('#tagsForm_tags').waitFor({ state: 'visible' }); + // Fill the input first await page.locator('#tagsForm_tags').fill(glossaryTerm.displayName); await searchGlossaryTerm; + await page.getByTestId(`tag-${glossaryTerm.fullyQualifiedName}`).click(); await page.waitForSelector( @@ -756,11 +779,18 @@ export const assignGlossaryTerm = async ( { state: 'visible' } ); - await expect(page.getByTestId('saveAssociatedTag')).toBeEnabled(); + await expect( + page.getByTestId('custom-drop-down-menu').getByTestId('saveAssociatedTag') + ).toBeEnabled(); - await page.getByTestId('saveAssociatedTag').click(); + await page + .getByTestId('custom-drop-down-menu') + .getByTestId('saveAssociatedTag') + .click(); - await expect(page.getByTestId('saveAssociatedTag')).not.toBeVisible(); + await expect( + page.getByTestId('custom-drop-down-menu').getByTestId('saveAssociatedTag') + ).not.toBeVisible(); await expect( page @@ -861,9 +891,14 @@ export const removeGlossaryTerm = async ( { state: 'visible' } ); - await expect(page.getByTestId('saveAssociatedTag')).toBeEnabled(); + await expect( + page.getByTestId('custom-drop-down-menu').getByTestId('saveAssociatedTag') + ).toBeEnabled(); - await page.getByTestId('saveAssociatedTag').click(); + await page + .getByTestId('custom-drop-down-menu') + .getByTestId('saveAssociatedTag') + .click(); await patchRequest; await expect( @@ -968,14 +1003,18 @@ export const unFollowEntity = async ( page: Page, endpoint: EntityTypeEndpoint ) => { + await page.waitForLoadState('networkidle'); + + const followButton = page.getByTestId('entity-follow-button'); + + await followButton.waitFor({ state: 'visible' }); + + await expect(followButton).toContainText('Unfollow'); + const unFollowResponse = page.waitForResponse( `/api/v1/${endpoint}/*/followers/*` ); - await page.waitForLoadState('networkidle'); - await page.waitForSelector('[data-testid="loader"]', { - state: 'detached', - }); - await page.getByTestId('entity-follow-button').click(); + await followButton.click(); await unFollowResponse; await expect(page.getByTestId('entity-follow-button')).toContainText( @@ -1346,9 +1385,16 @@ export const removeDisplayNameForEntityChildren = async ( await page.locator('#displayName').fill(''); - const updateRequest = page.waitForResponse((req) => - ['PUT', 'PATCH'].includes(req.request().method()) - ); + const updateRequest = page.waitForResponse((response) => { + const method = response.request().method(); + const url = response.url(); + + // Check Analytics Api Does Not Intterupt With PUT CAll + return ( + (method === 'PUT' || method === 'PATCH') && + !url.includes('api/v1/analytics/web/events/collect') + ); + }); await page.click('[data-testid="save-button"]'); await updateRequest; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataProducts/DataProductsSelectList/DataProductsSelectList.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataProducts/DataProductsSelectList/DataProductsSelectList.tsx index eff43e35c8e..2fcd78a69f4 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DataProducts/DataProductsSelectList/DataProductsSelectList.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataProducts/DataProductsSelectList/DataProductsSelectList.tsx @@ -128,7 +128,10 @@ const DataProductsSelectList = ({ <> {menu} {hasContentLoading ? : null} - +