Files
calendar/apps/web/playwright/organization/team-management.e2e.ts
T
RomitGitHubromitgabani1Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
e073cbd5ea fix: resolve flaky team-management E2E test (#28575)
* fix: resolve flaky team-management E2E test

Fix two failure modes in the 'Can create teams via Wizard' test:

1. Strict mode violation: locator('[data-testid=new-team-btn]') resolves to
   2 elements during Next.js streaming/hydration. Fixed by using .first().

2. Race condition in disband assertion: raw .count() check doesn't wait for
   UI to update after team deletion. Replaced with Playwright's auto-retrying
   toBeHidden() assertion with a 10s timeout.

Co-Authored-By: romitgabani1 <romitgabani1.work@gmail.com>

* chore: remove explanatory comments per review feedback

Co-Authored-By: romitgabani1 <romitgabani1.work@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-03-25 14:19:35 +05:30

76 lines
2.9 KiB
TypeScript

import { expect } from "@playwright/test";
import { IS_TEAM_BILLING_ENABLED } from "@calcom/lib/constants";
import { prisma } from "@calcom/prisma";
import { MembershipRole } from "@calcom/prisma/enums";
import { test } from "../lib/fixtures";
import { fillStripeTestCheckout } from "../lib/testUtils";
test.describe("Teams", () => {
test.afterEach(({ orgs, users }) => {
orgs.deleteAll();
users.deleteAll();
});
test("Can create teams via Wizard", async ({ page, users, orgs }) => {
const org = await orgs.create({
name: "TestOrg",
});
const user = await users.create(
{
organizationId: org.id,
roleInOrganization: MembershipRole.ADMIN,
},
{ hasTeam: true }
);
const inviteeEmail = `${user.username}+invitee@example.com`;
await user.apiLogin();
await page.goto("/teams");
await test.step("Can create team", async () => {
await page.locator("[data-testid=new-team-btn]").first().click();
await page.waitForLoadState("networkidle");
// Fill team name input (new onboarding-v3 style flow)
await page.locator('[data-testid="team-name-input"]').fill(`${user.username}'s Team`);
// Click text=Continue
await page.click("[type=submit]");
// TODO: Figure out a way to make this more reliable
// eslint-disable-next-line playwright/no-conditional-in-test
if (IS_TEAM_BILLING_ENABLED) await fillStripeTestCheckout(page);
// Wait for the invite email page (new flow)
await expect(page).toHaveURL(/\/settings\/teams\/new\/invite\/email.*$/i);
await page.waitForLoadState("networkidle");
});
await test.step("Can add members via email invite", async () => {
// Add member via email invite form
await page.locator('input[type="email"]').first().fill(inviteeEmail);
await page.click("[type=submit]");
await page.waitForLoadState("networkidle");
// Wait for redirect to teams page
await expect(page).toHaveURL(/\/teams$/i);
});
await test.step("Can navigate to team settings", async () => {
// Click on the team to go to settings
await page.locator(`text=${user.username}'s Team`).click();
await page.waitForURL(/\/settings\/teams\/(\d+)\/profile$/i);
});
await test.step("Can disband team", async () => {
await page.getByTestId("disband-team-button").click();
await page.getByTestId("dialog-confirmation").click();
await page.waitForURL("/teams");
await expect(page.locator(`text=${user.username}'s Team`)).toBeHidden({ timeout: 10000 });
// Cleanup the invited user since they were created without our fixtures
const invitedUser = await prisma.user.findUnique({ where: { email: inviteeEmail } });
// eslint-disable-next-line playwright/no-conditional-in-test
if (invitedUser) {
await prisma.user.delete({ where: { email: inviteeEmail } });
}
});
});
});