Skip to content

Commit bdc9c9c

Browse files
harsh-vadorclaude
authored andcommitted
test(teams): stop the add-team click from landing in a toast (#31734)
* test(teams): stop the add-team click from landing in a toast addTeamHierarchy clicked the add button with `force: true`, which skips the hit-target check. The backend fans delete/job notifications out to every socket of the logged-in admin, so a parallel worker's success toast can sit over that button — and with force the click was dispatched into the toast. The click "succeeded", the modal never opened, and the failure surfaced 15s later on the modal assertion. Success toasts carry no close button and self-dismiss after 3.5s, so clicking without force is the fix: the hit-target check waits the toast out. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(teams): retry the add-team open when a toast eats the click Dropping `force` was not enough. Playwright checks the hit target and then dispatches, so a socket-fanned success toast landing in that window still swallows the click — the trace shows the click "succeeding" in 16ms with a delete toast on screen and the modal never opening. Route every add-team trigger through openAddTeamModal: let a pending toast expire, click, and retry until the modal is up. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit af609a6)
1 parent 6db2ba9 commit bdc9c9c

2 files changed

Lines changed: 49 additions & 16 deletions

File tree

openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Teams.spec.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import {
5858
executionOnOwnerTeam,
5959
getNewTeamDetails,
6060
hardDeleteTeam,
61+
openAddTeamModal,
6162
searchTeam,
6263
softDeleteTeam,
6364
verifyAssetsInTeamsPage,
@@ -192,9 +193,7 @@ test.describe('Teams Page', () => {
192193
await test.step('Create a new team', async () => {
193194
await checkTeamTabCount(page);
194195

195-
await page.getByTestId('add-team').waitFor();
196-
197-
await page.getByTestId('add-team').click();
196+
await openAddTeamModal(page);
198197

199198
const newTeamData = await createTeam(page, true);
200199

@@ -427,9 +426,7 @@ test.describe('Teams Page', () => {
427426
test('Create a new public team', async ({ page }) => {
428427
await settingClick(page, GlobalSettingOptions.TEAMS);
429428

430-
await page.getByTestId('add-team').waitFor();
431-
432-
await page.getByTestId('add-team').click();
429+
await openAddTeamModal(page);
433430
const { apiContext, afterAction } = await getApiContext(page);
434431

435432
try {

openmetadata-ui/src/main/resources/ui/playwright/utils/team.ts

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,47 @@ import { settingClick } from './sidebar';
3333

3434
const TEAM_TYPES = ['Department', 'Division', 'Group'];
3535

36+
const ADD_TEAM_MODAL = '[role="dialog"].ant-modal';
37+
// A success toast self-dismisses after 3.5s; give it a beat past that.
38+
const TOAST_DISMISS_TIMEOUT = 6_000;
39+
const MODAL_OPEN_TIMEOUT = 10_000;
40+
const MODAL_RETRY_TIMEOUT = 60_000;
41+
42+
type AddTeamTrigger = 'add-team' | 'add-placeholder-button';
43+
44+
/**
45+
* Click an add-team trigger and return the modal it opens.
46+
*
47+
* The backend fans async-delete/job notifications out to every socket of the
48+
* logged-in user, so a parallel worker's toast can drop over the button in the
49+
* window between Playwright's hit-target check and the dispatched click — the
50+
* toast swallows the click and the modal never opens. Success toasts carry no
51+
* close button, so let them expire and click again; clicking with `force` only
52+
* dispatches INTO the toast.
53+
*/
54+
export const openAddTeamModal = async (
55+
page: Page,
56+
trigger: AddTeamTrigger = 'add-team'
57+
) => {
58+
const addButton = page.getByTestId(trigger);
59+
const addTeamModal = page.locator(ADD_TEAM_MODAL).last();
60+
61+
await expect(async () => {
62+
await page
63+
.getByTestId('alert-bar')
64+
.first()
65+
.waitFor({ state: 'detached', timeout: TOAST_DISMISS_TIMEOUT })
66+
.catch(() => undefined);
67+
68+
await expect(addButton).toBeEnabled();
69+
await addButton.click();
70+
71+
await expect(addTeamModal).toBeVisible({ timeout: MODAL_OPEN_TIMEOUT });
72+
}).toPass({ timeout: MODAL_RETRY_TIMEOUT, intervals: [1_000] });
73+
74+
return addTeamModal;
75+
};
76+
3677
interface SearchTeamOptions {
3778
expectEmptyResults?: boolean;
3879
expectNotFound?: boolean;
@@ -252,16 +293,11 @@ export const addTeamHierarchy = async (
252293
index?: number,
253294
isHierarchy = false
254295
) => {
255-
const addTeamModal = page.locator('[role="dialog"].ant-modal').last();
256-
257-
// Fetching the add button and clicking on it
258-
if (index && index > 0) {
259-
await page.click('[data-testid="add-placeholder-button"]', { force: true });
260-
} else {
261-
await page.click('[data-testid="add-team"]', { force: true });
262-
}
296+
const addTeamModal = await openAddTeamModal(
297+
page,
298+
index && index > 0 ? 'add-placeholder-button' : 'add-team'
299+
);
263300

264-
await expect(addTeamModal).toBeVisible();
265301
await expect(page.locator('[data-testid="name"]')).toBeVisible();
266302

267303
// Entering team details
@@ -621,7 +657,7 @@ export const executionOnOwnerTeam = async (
621657

622658
await addEmailTeam(page, data.email);
623659

624-
await page.getByTestId('add-placeholder-button').click();
660+
await openAddTeamModal(page, 'add-placeholder-button');
625661

626662
const newTeamData = await createTeam(page);
627663

0 commit comments

Comments
 (0)