Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,6 @@ test.describe('Activity Stream on Entity Pages', () => {
await activityFeedTab.click();
await waitForPageLoaded(page);

await page.waitForTimeout(2000);

const messageContainers = page.locator('[data-testid="message-container"]');
const count = await messageContainers.count();

Expand Down Expand Up @@ -188,11 +186,12 @@ test.describe('Activity Stream on Entity Pages', () => {
await activityFeedTab.click();
await waitForPageLoaded(page);

await page.waitForTimeout(2000);

const allTabInLeftPanel = page.locator(
'[data-testid="global-setting-left-panel"]'
);
await allTabInLeftPanel
.waitFor({ state: 'visible', timeout: 2000 })
.catch(() => undefined);

if (await allTabInLeftPanel.isVisible()) {
await expect(allTabInLeftPanel).toBeVisible();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import {
pressKeyXTimes,
validateImportStatus,
} from '../../utils/importUtils';
import { waitForSearchIndexed } from '../../utils/polling';
import { visitServiceDetailsPage } from '../../utils/service';

interface GlossaryDetails {
Expand Down Expand Up @@ -671,6 +672,18 @@ test.describe('Bulk Edit Entity', () => {
await glossary.create(apiContext);
await glossaryTerm.create(apiContext);

// Wait for the glossary term to be indexed in ES before bulk-edit reads
// the glossary's term list. Otherwise the bulk-edit table comes back
// empty, the test fills row 1 with the term's name, and the system
// creates a new term instead of recognizing the existing one — the
// subsequent status assertion gets "Entity created" instead of
// "Entity updated".
await waitForSearchIndexed(
apiContext,
glossaryTerm.responseData.fullyQualifiedName,
'glossary_term_search_index'
);

await test.step('create custom properties for extension edit', async () => {
customPropertyRecord = await createCustomPropertiesForEntity(
page,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { GlossaryTerm } from '../../support/glossary/GlossaryTerm';
import { createNewPage, redirectToHomePage } from '../../utils/common';
import { waitForAllLoadersToDisappear } from '../../utils/entity';
import { fillTextInputDetails, pressKeyXTimes } from '../../utils/importUtils';
import { waitForSearchIndexed } from '../../utils/polling';
import { visitServiceDetailsPage } from '../../utils/service';

test.use({ storageState: 'playwright/.auth/admin.json' });
Expand All @@ -39,6 +40,22 @@ test.describe('BulkEditEntity — OperationBadges and Search (all entity types)'
await opGlossary.create(apiContext);
await opGlossaryTerm.create(apiContext);
await opTable.create(apiContext);

// Wait for ES indexing of both the term and the table before any test
// opens the bulk-edit view; the bulk-edit table reads from search and
// otherwise comes back empty under load, racing the test's row count
// assertions.
await waitForSearchIndexed(
apiContext,
opGlossaryTerm.responseData.fullyQualifiedName,
'glossary_term_search_index'
);
await waitForSearchIndexed(
apiContext,
opTable.entityResponseData.fullyQualifiedName,
'table_search_index'
);

await afterAction();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import {
startCsvPreviewAndWaitForGrid,
validateImportStatus,
} from '../../utils/importUtils';
import { waitForSearchIndexed } from '../../utils/polling';

// use the admin user to login
test.use({
Expand Down Expand Up @@ -105,6 +106,15 @@ const expectImportRowStatusesToContain = async (
page: Page,
rowStatus: string[]
) => {
// The result grid populates cells asynchronously after Next-click. Without
// first waiting for the row count to match, the toContainText assertion
// can run mid-render against 0 or partial cells, fail under retry too,
// and never recover. Wait for the expected number of detail cells before
// checking text.
await expect(page.locator('.rdg-cell-details')).toHaveCount(
rowStatus.length,
{ timeout: 60_000 }
);
await expect(page.locator('.rdg-cell-details')).toContainText(rowStatus);
};

Expand Down Expand Up @@ -161,6 +171,14 @@ test.describe('Bulk Import Export', () => {
const { apiContext, afterAction } = await getApiContext(page);
await dbService.create(apiContext);

// Bulk-import reads the service's children list from ES; wait for the
// service to be indexed before the test fetches its export/edit grid.
await waitForSearchIndexed(
apiContext,
dbService.entityResponseData.fullyQualifiedName,
'database_service_search_index'
);

await test.step('create custom properties for extension edit', async () => {
customPropertyRecord = await createCustomPropertiesForEntity(
page,
Expand Down Expand Up @@ -613,6 +631,14 @@ test.describe('Bulk Import Export', () => {
const { apiContext, afterAction } = await getApiContext(page);
await dbSchemaEntity.create(apiContext);

// Bulk-import reads the schema's children list from ES; wait for the
// schema to be indexed before the test fetches its export/edit grid.
await waitForSearchIndexed(
apiContext,
dbSchemaEntity.entityResponseData.fullyQualifiedName,
'database_schema_search_index'
);

await test.step('create custom properties for extension edit', async () => {
customPropertyRecord = await createCustomPropertiesForEntity(
page,
Expand Down Expand Up @@ -775,6 +801,14 @@ test.describe('Bulk Import Export', () => {
const { apiContext, afterAction } = await getApiContext(page);
await tableEntity.create(apiContext);

// Bulk-import reads the table's columns from ES; wait for the table
// to be indexed before the test fetches its export/edit grid.
await waitForSearchIndexed(
apiContext,
tableEntity.entityResponseData.fullyQualifiedName,
'table_search_index'
);

await test.step('should export data table details', async () => {
await tableEntity.visitEntityPage(page);
await performBulkDownload(page, tableEntity.entity.name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { TableClass } from '../../../support/entity/TableClass';
import { UserClass } from '../../../support/user/UserClass';
import { performAdminLogin } from '../../../utils/admin';
import { redirectToHomePage, uuid } from '../../../utils/common';
import { waitForSearchIndexed } from '../../../utils/polling';
import {
cleanupDownloadedCSV,
performE2EExportImportFlow,
Expand Down Expand Up @@ -67,6 +68,18 @@ test.describe(
const { apiContext, afterAction } = await performAdminLogin(browser);
await table.create(apiContext);
await table.createTestCase(apiContext);

// The export step inside performE2EExportImportFlow reads the table's
// test cases via search. Without waiting for ES indexing here, the
// just-created test case is missing from the exported CSV, so the
// import sees only the 4 added rows (not 5 = 1 existing + 4 added) and
// `processed-row` reports "4" instead of the expected "5".
await waitForSearchIndexed(
apiContext,
table.testCasesResponseData[0]?.fullyQualifiedName,
'test_case_search_index'
);

await afterAction();
});

Expand Down Expand Up @@ -128,6 +141,16 @@ test.describe(

await table.create(apiContext);
await table.createTestCase(apiContext);

// See the matching note in the Admin describe — without waiting for
// ES indexing the export misses the just-created test case and
// processed-row reports "4" instead of "5".
await waitForSearchIndexed(
apiContext,
table.testCasesResponseData[0]?.fullyQualifiedName,
'test_case_search_index'
);

await afterAction();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,17 +116,24 @@ test.describe('Search index - deeply nested oversized columns', () => {

// Indexing: the table indexed despite the >32 KB nested leaf, so it is found by name.
await searchInput.click();
const byNameResponse = page.waitForResponse('/api/v1/search/query?*');

await searchInput.fill(table.entity.name);
await byNameResponse;

await page
.getByTestId(table.service.name + '-' + table.entity.name)
.waitFor({ timeout: 15000 });

await expect(suggestions).toBeVisible();
await expect(suggestions).toContainText(table.entity.name);

// Searching: the 25-level-deep column name surfaces the table via columnNamesFuzzy - the
// mechanism that replaced the dropped flattened columns.children.name search field.
await searchInput.clear();
const byColumnResponse = page.waitForResponse('/api/v1/search/query?*');
const byColumnResponse = page.waitForResponse(
(r) =>
r.url().includes('/api/v1/search/query') &&
r.url().includes(encodeURIComponent(leafColumnName))
);
await searchInput.fill(leafColumnName);
await byColumnResponse;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,29 @@ test.describe('Table pagination sorting search scenarios ', () => {
await page.click('[data-testid="test-cases"]');
await waitForAllLoadersToDisappear(page);

// Capture the paginated list responses so we wait for the *new* data
// before counting rows. Without this, the loader can finish for the
// current page while the page-2 fetch is still in flight, and the
// row count assertion runs against an empty table mid-transition.
const sortedResponse = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?*'
);
await page.getByText('Name', { exact: true }).click();
await sortedResponse;

const nextPageResponse = page.waitForResponse(
'/api/v1/dataQuality/testCases/search/list?*'
);
await page.getByTestId('next').click();
await nextPageResponse;

await waitForAllLoadersToDisappear(page);

expect(
await page
.locator('[data-testid="test-case-table"] tbody tr[data-key]')
.count()
).toBe(15);
// Use toHaveCount instead of .count() === 15 so Playwright auto-retries
// the assertion until the table re-renders with the page-2 rows.
await expect(
page.locator('[data-testid="test-case-table"] tbody tr[data-key]')
).toHaveCount(15);
});

test('Table search with sorting should work', async ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,6 @@ test.describe('Activity Feed - Filters', () => {
await subFilterDropdown.click();
await page.getByRole('menuitem', { name: menuLabel }).click();
await expect(subFilterDropdown).toContainText(new RegExp(menuLabel, 'i'));
await page.waitForTimeout(300);
};

await subFilterDropdown.click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,10 @@ test.describe('Task Comments - @Mention', () => {
'.mention-dropdown, .ql-mention-list-container, [data-testid="mention-suggestions"]'
);

// Dropdown should appear (may or may not be visible depending on UI implementation)
await page.waitForTimeout(1000);
await mentionDropdown
.first()
.waitFor({ state: 'visible', timeout: 2000 })
.catch(() => undefined);
}
}
}
Expand Down Expand Up @@ -339,12 +341,15 @@ test.describe('Task Comments - @Mention', () => {

// Type @ and part of username
await page.keyboard.type(`@${mentionedUser.responseData.name}`);
await page.waitForTimeout(500);

// Select from dropdown if visible
const mentionItem = page.locator(
`.mention-item, .ql-mention-list-item:has-text("${mentionedUser.responseData.displayName}")`
);
await mentionItem
.first()
.waitFor({ state: 'visible', timeout: 2000 })
.catch(() => undefined);

if (await mentionItem.isVisible()) {
await mentionItem.click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
selectDomain,
} from '../../utils/domain';
import { waitForAllLoadersToDisappear } from '../../utils/entity';
import { waitForSearchIndexed } from '../../utils/polling';
import { sidebarClick } from '../../utils/sidebar';

test.use({ storageState: 'playwright/.auth/admin.json' });
Expand Down Expand Up @@ -271,8 +272,12 @@ test.describe('Data Product Comprehensive Tests', () => {
}

if (retry < maxRetries - 1) {
// eslint-disable-next-line playwright/no-wait-for-timeout -- wait for ES indexing before retry
await page.waitForTimeout(2000);
await waitForSearchIndexed(
apiContext,
user.getUserName(),
'user_search_index',
{ timeout: 3000 }
).catch(() => undefined);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
selectDomain,
} from '../../utils/domain';
import { waitForAllLoadersToDisappear } from '../../utils/entity';
import { waitForSearchIndexed } from '../../utils/polling';
import { sidebarClick } from '../../utils/sidebar';

const test = base.extend<{
Expand Down Expand Up @@ -93,8 +94,12 @@ test.describe('Domain Owner Management', () => {
}

if (retry < maxRetries - 1) {
// eslint-disable-next-line playwright/no-wait-for-timeout -- wait for ES indexing before retry
await page.waitForTimeout(2000);
await waitForSearchIndexed(
apiContext,
user.getUserName(),
'user_search_index',
{ timeout: 3000 }
).catch(() => undefined);
}
}

Expand Down Expand Up @@ -244,8 +249,12 @@ test.describe('Domain Expert Management', () => {

// Wait before retry (ES indexing delay)
if (retry < maxRetries - 1) {
// eslint-disable-next-line playwright/no-wait-for-timeout -- wait for ES indexing before retry
await page.waitForTimeout(2000);
await waitForSearchIndexed(
apiContext,
user.getUserName(),
'user_search_index',
{ timeout: 3000 }
).catch(() => undefined);
}
}

Expand Down Expand Up @@ -431,8 +440,12 @@ test.describe('Data Product UI Operations', () => {
}

if (retry < maxRetries - 1) {
// eslint-disable-next-line playwright/no-wait-for-timeout -- wait for ES indexing before retry
await page.waitForTimeout(2000);
await waitForSearchIndexed(
apiContext,
user.getUserName(),
'user_search_index',
{ timeout: 3000 }
).catch(() => undefined);
}
}

Expand Down
Loading
Loading