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}
-
+