Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
*/
import { expect, test } from '@playwright/test';
import { PLAYWRIGHT_BASIC_TEST_TAG_OBJ } from '../../constant/config';
import { GlobalSettingOptions } from '../../constant/settings';
import {
createNewPage,
redirectToHomePage,
toastNotification,
uuid,
Expand All @@ -23,9 +23,11 @@ import {
dragAndDropElement,
openDragDropDropdown,
} from '../../utils/dragDrop';
import { waitForAllLoadersToDisappear } from '../../utils/entity';
import { settingClick } from '../../utils/sidebar';
import { addTeamHierarchy } from '../../utils/team';
import {
addTeamHierarchy,
hardDeleteTeamByName,
visitTeamsPage,
} from '../../utils/team';

// use the admin user to login
test.use({ storageState: 'playwright/.auth/admin.json' });
Expand Down Expand Up @@ -89,28 +91,32 @@ test.describe(
'Teams drag and drop should work properly',
PLAYWRIGHT_BASIC_TEST_TAG_OBJ,
() => {
// Every test re-enters Settings > Teams, and that landing waits on the
// hierarchy table's asset-count aggregation, which grows with the catalog.
// On a long-lived deployment the hook alone can outlast the 60s default.
test.slow(true);
Comment thread
harsh-vador marked this conversation as resolved.
Outdated

test.beforeEach(async ({ page }) => {
await redirectToHomePage(page);
await visitTeamsPage(page);
});
Comment on lines 94 to +97

@gitar-bot gitar-bot Bot Aug 24, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Bug: Per-test test.slow() leaves slow beforeEach on default 60s budget

This commit removes test.slow() from beforeEach and instead calls test.slow(true) inside individual test bodies. Two problems reintroduce the very flake this PR targets: (1) the three 'Should fail...' tests (lines 125, 135, 149) get no test.slow() at all, so they run the slow visitTeamsPage hook under the default 60s timeout; (2) even for tests that do call test.slow(true), the call runs only after beforeEach completes — if the hierarchy-table aggregation makes visitTeamsPage exceed 60s (the exact failure in the RCA), the hook times out before the body runs and the tripling never applies. The deleted comment made precisely this point. Restore test.slow() at the start of beforeEach so the tripled budget covers hook time for every test, and drop the redundant per-test calls.

Move test.slow() back into beforeEach so it covers hook time for all tests; remove the per-test test.slow(true) calls.:

test.beforeEach(async ({ page }) => {
  // Hook time counts against the test timeout, and visitTeamsPage waits on
  // the hierarchy table's asset-count aggregation, which grows with the
  // catalog. Mark slow here so the tripled budget covers the hook for every
  // test (a per-test-body test.slow() runs too late if the hook overruns).
  test.slow();

  await redirectToHomePage(page);
  await visitTeamsPage(page);
});

Was this helpful? React with 👍 / 👎


const getOrganizationResponse = page.waitForResponse(
(response) =>
response.url().includes('/api/v1/teams/name/') &&
response.status() === 200
);
const permissionResponse = page.waitForResponse(
(response) =>
response.url().includes('/api/v1/permissions/team/name/') &&
response.status() === 200
);
test.afterAll(async ({ browser }) => {
const { apiContext, afterAction } = await createNewPage(browser);

for (const teamName of [
teamNameBusiness,
teamNameDivision,
teamNameDepartment,
teamNameGroup,
]) {
await hardDeleteTeamByName(apiContext, teamName);
Comment thread
greptile-apps[bot] marked this conversation as resolved.
Outdated
}

await settingClick(page, GlobalSettingOptions.TEAMS);
await permissionResponse;
await getOrganizationResponse;
await waitForAllLoadersToDisappear(page);
await afterAction();
});

test('Add teams in hierarchy', async ({ page }) => {
test.slow();
for (const teamDetails of DRAG_AND_DROP_TEAM_DETAILS) {
await addTeamHierarchy(page, teamDetails);

Expand Down Expand Up @@ -158,7 +164,6 @@ test.describe(
test(`Should drag and drop on ${TEAM_TYPE_BY_NAME[droppableTeamName]} team type`, async ({
page,
}) => {
test.slow();
// Nested team will be shown once anything is moved under it
if (index !== 0) {
await openDragDropDropdown(page, teams[index - 1]);
Expand All @@ -182,7 +187,6 @@ test.describe(
}

test(`Should drag and drop team on table level`, async ({ page }) => {
test.slow();
// Open department team dropdown as it is moved under it from last test
await openDragDropDropdown(page, teamNameDepartment);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
addTeamHierarchy,
getNewTeamDetails,
searchTeam,
visitTeamsPage,
} from '../../utils/team';

// use the admin user to login
Expand All @@ -45,17 +46,7 @@ test.describe(

test.beforeEach(async ({ page }) => {
await redirectToHomePage(page);

const getOrganizationResponse = page.waitForResponse(
'/api/v1/teams/name/*'
);
const permissionResponse = page.waitForResponse(
'/api/v1/permissions/team/name/*'
);

await settingClick(page, GlobalSettingOptions.TEAMS);
await permissionResponse;
await getOrganizationResponse;
await visitTeamsPage(page);
});

test('Add teams in hierarchy', async ({ page }) => {
Expand Down Expand Up @@ -110,8 +101,6 @@ test.describe(
});

test('Delete Parent Team', async ({ page }) => {
await settingClick(page, GlobalSettingOptions.TEAMS);

await page.getByRole('link', { name: businessTeamName }).click();

await page.click('[data-testid="manage-button"]');
Expand Down
49 changes: 49 additions & 0 deletions openmetadata-ui/src/main/resources/ui/playwright/utils/team.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,55 @@ export const openAddTeamModal = async (
return addTeamModal;
};

/**
* Land on Settings > Teams with the hierarchy table settled.
*
* The table spins on its own child-teams fetch plus the per-team asset-count
* aggregation, so navigation alone is not enough — a caller that acts right
* after the click drags rows that are still being repainted. Wait on the two
* calls that gate the first paint, then on the table itself.
*/
export const visitTeamsPage = async (page: Page) => {
const organizationResponse = page.waitForResponse(
(response) =>
response.url().includes('/api/v1/teams/name/') && response.ok()
);
const permissionResponse = page.waitForResponse(
(response) =>
response.url().includes('/api/v1/permissions/team/name/') && response.ok()
);

await settingClick(page, GlobalSettingOptions.TEAMS);
await Promise.all([permissionResponse, organizationResponse]);

await expect(page.getByTestId('team-hierarchy-table')).toBeVisible();
await waitForAllLoadersToDisappear(page);
};

/**
* Hard-delete a team created through the UI, children included.
*
* Specs that build teams through the UI have no entity handle to call
* `TeamClass.delete` on, so resolve the id by name first. A missing team is not
* an error — the spec may have deleted it as part of what it asserts.
*/
export const hardDeleteTeamByName = async (
apiContext: APIRequestContext,
teamName: string
) => {
const teamResponse = await apiContext.get(
`/api/v1/teams/name/${encodeURIComponent(teamName)}`
);

if (teamResponse.ok()) {
const { id } = await teamResponse.json();

await apiContext.delete(
`/api/v1/teams/${id}?hardDelete=true&recursive=true`
);
Comment thread
greptile-apps[bot] marked this conversation as resolved.
Outdated
}
Comment thread
gitar-bot[bot] marked this conversation as resolved.
Outdated
};

interface SearchTeamOptions {
expectEmptyResults?: boolean;
expectNotFound?: boolean;
Expand Down
Loading