966d4b5cc6
* fix: address flaky E2E tests
- booking-pages.e2e.ts: Use selectFirstAvailableTimeSlotNextMonth helper instead of brittle nth(1) selector to avoid race condition where time slots become unavailable
- fixtures/users.ts: Add retryOnNetworkError helper to handle transient ECONNRESET errors during apiLogin
- lib/testUtils.ts: Add waitForLoadState('networkidle') to goToUrlWithErrorHandling to ensure page is fully loaded before checking URL
- teams.e2e.ts: Add explicit wait for publish button visibility before clicking to avoid timeout
- unpublished.e2e.ts: Change from parallel to serial mode to avoid database deadlocks from concurrent writes
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix: consolidate unpublished.e2e.ts tests to reduce concurrent DB writes
Instead of using serial mode, consolidate related tests into single test
functions that share setup data. This reduces concurrent users.create()
and users.deleteAll() calls from 7 to 3, significantly reducing the
chance of database deadlocks while maintaining parallel execution.
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
* fix: only fail goToUrlWithErrorHandling on main navigation requests
The previous fix was incorrectly resolving the promise when any request
failed (like images, RSC requests, etc.), causing the URL check to fail.
Now we only consider it a navigation failure if:
- request.isNavigationRequest() is true
- request.frame() === page.mainFrame()
Also added a resolved flag to prevent multiple resolutions and removed
the networkidle wait which was causing issues.
Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
117 lines
4.3 KiB
TypeScript
117 lines
4.3 KiB
TypeScript
import { expect } from "@playwright/test";
|
|
|
|
import { SchedulingType } from "@calcom/prisma/enums";
|
|
|
|
import { test } from "./lib/fixtures";
|
|
|
|
// Keep parallel mode - each test creates its own isolated data
|
|
test.describe.configure({ mode: "parallel" });
|
|
|
|
const title = (name: string) => `${name} is unpublished`;
|
|
const description = (entity: string) =>
|
|
`This ${entity} link is currently not available. Please contact the ${entity} owner or ask them to publish it.`;
|
|
|
|
const assertChecks = async (page: any, entityName: string, entityType: string) => {
|
|
await expect(page.locator('[data-testid="empty-screen"]')).toHaveCount(1);
|
|
await expect(page.locator(`h2:has-text("${title(entityName)}")`)).toHaveCount(1);
|
|
await expect(page.locator(`div:text("${description(entityType)}")`)).toHaveCount(1);
|
|
await expect(page.locator(`img`)).toHaveAttribute("src", /.*/);
|
|
};
|
|
|
|
// Group 1: Regular team tests - share setup data
|
|
test.describe("Unpublished - Regular team", () => {
|
|
test.afterEach(async ({ users }) => {
|
|
await users.deleteAll();
|
|
});
|
|
|
|
test("Regular team profile", async ({ page, users }) => {
|
|
const owner = await users.create(undefined, {
|
|
hasTeam: true,
|
|
isUnpublished: true,
|
|
schedulingType: SchedulingType.COLLECTIVE,
|
|
});
|
|
const { team } = await owner.getFirstTeamMembership();
|
|
const { requestedSlug } = team.metadata as { requestedSlug: string };
|
|
const teamEventSlug = (await owner.getFirstTeamEvent(team.id)).slug;
|
|
const prefixes = ["", "/en"];
|
|
|
|
// Test team profile
|
|
for (const prefix of prefixes) {
|
|
await page.goto(`${prefix}/team/${requestedSlug}`);
|
|
await assertChecks(page, team.name, "team");
|
|
}
|
|
|
|
// Test team event type (reuse same data)
|
|
for (const prefix of prefixes) {
|
|
await page.goto(`${prefix}/team/${requestedSlug}/${teamEventSlug}`);
|
|
await assertChecks(page, team.name, "team");
|
|
}
|
|
});
|
|
});
|
|
|
|
// Group 2: Organization tests - share setup data
|
|
test.describe("Unpublished - Organization", () => {
|
|
test.afterEach(async ({ users }) => {
|
|
await users.deleteAll();
|
|
});
|
|
|
|
test("Organization profile and user", async ({ users, page }) => {
|
|
const owner = await users.create(undefined, { hasTeam: true, isUnpublished: true, isOrg: true });
|
|
const { team: org } = await owner.getOrgMembership();
|
|
const { requestedSlug } = org.metadata as { requestedSlug: string };
|
|
const [{ slug: ownerEventType }] = owner.eventTypes;
|
|
const prefixes = ["", "/en"];
|
|
|
|
// Test organization profile
|
|
for (const prefix of prefixes) {
|
|
await page.goto(`${prefix}/org/${requestedSlug}`);
|
|
await assertChecks(page, org.name, "organization");
|
|
}
|
|
|
|
// Test organization user
|
|
for (const prefix of prefixes) {
|
|
await page.goto(`${prefix}/org/${requestedSlug}/${owner.username}`);
|
|
await assertChecks(page, org.name, "organization");
|
|
}
|
|
|
|
// Test organization user event-type
|
|
for (const prefix of prefixes) {
|
|
await page.goto(`${prefix}/org/${requestedSlug}/${owner.username}/${ownerEventType}`);
|
|
await assertChecks(page, org.name, "organization");
|
|
}
|
|
});
|
|
});
|
|
|
|
// Group 3: Organization sub-team tests - share setup data
|
|
test.describe("Unpublished - Organization sub-team", () => {
|
|
test.afterEach(async ({ users }) => {
|
|
await users.deleteAll();
|
|
});
|
|
|
|
test("Organization sub-team and event-type", async ({ users, page }) => {
|
|
const owner = await users.create(undefined, {
|
|
hasTeam: true,
|
|
isUnpublished: true,
|
|
isOrg: true,
|
|
hasSubteam: true,
|
|
});
|
|
const { team: org } = await owner.getOrgMembership();
|
|
const { requestedSlug } = org.metadata as { requestedSlug: string };
|
|
const [{ slug: subteamSlug, id: subteamId }] = org.children as { slug: string; id: number }[];
|
|
const { slug: subteamEventSlug } = await owner.getFirstTeamEvent(subteamId);
|
|
const prefixes = ["", "/en"];
|
|
|
|
// Test organization sub-team
|
|
for (const prefix of prefixes) {
|
|
await page.goto(`${prefix}/org/${requestedSlug}/team/${subteamSlug}`);
|
|
await assertChecks(page, org.name, "organization");
|
|
}
|
|
|
|
// Test organization sub-team event-type
|
|
for (const prefix of prefixes) {
|
|
await page.goto(`${prefix}/org/${requestedSlug}/team/${subteamSlug}/${subteamEventSlug}`);
|
|
await assertChecks(page, org.name, "organization");
|
|
}
|
|
});
|
|
});
|