diff --git a/apps/web/playwright/auth/auth-index.e2e.ts b/apps/web/playwright/auth/auth-index.e2e.ts index 7b6a2276ba..21846a3c04 100644 --- a/apps/web/playwright/auth/auth-index.e2e.ts +++ b/apps/web/playwright/auth/auth-index.e2e.ts @@ -1,22 +1,27 @@ +import { expect } from "@playwright/test"; + import { test } from "../lib/fixtures"; +import { submitAndWaitForResponse } from "../lib/testUtils"; test.describe("Can signup from a team invite", async () => { test.beforeEach(async ({ users }) => { const proUser = await users.create(); await proUser.apiLogin(); }); - test.afterEach(async ({ users }) => users.deleteAll()); + test.afterEach(async ({ users }) => { + await users.deleteAll(); + }); test("Team invites validations work and can accept invite", async ({ browser, page, users, prisma }) => { const [proUser] = users.get(); const teamName = `${proUser.username}'s Team`; const testUser = { username: `${proUser.username}-member`, - password: `${proUser.username}-member`, + // At least one number, lower and uppercase letters + password: `${proUser.username}-MEMBER`, email: `${proUser.username}-member@example.com`, }; await page.goto("/settings/teams/new"); - await page.waitForLoadState("networkidle"); // Create a new team await page.locator('input[name="name"]').fill(teamName); @@ -26,72 +31,65 @@ test.describe("Can signup from a team invite", async () => { // Add new member to team await page.click('[data-testid="new-member-button"]'); await page.fill('input[id="inviteUser"]', testUser.email); - await page.click('[data-testid="invite-new-member-button"]'); + const submitPromise = page.waitForResponse("/api/trpc/teams/inviteMember?batch=1"); + await page.getByTestId("invite-new-member-button").click(); + const response = await submitPromise; + expect(response.status()).toBe(200); // TODO: Adapt to new flow + const tokenObj = await prisma.verificationToken.findFirstOrThrow({ + where: { identifier: testUser.email }, + select: { token: true }, + }); - // Wait for the invite to be sent - /*await page.waitForSelector(`[data-testid="member-email"][data-email="${testUser.email}"]`); + if (!proUser.username) throw Error("Test username is null, can't continue"); - const tokenObj = await prisma.verificationToken.findFirstOrThrow({ - where: { identifier: testUser.email }, - select: { token: true }, - }); + // Open a new user window to accept the invite + const context = await browser.newContext(); + const newPage = await context.newPage(); + await newPage.goto(`/auth/signup?token=${tokenObj.token}&callbackUrl=/settings/teams`); + // We wait on locales so we prevent password lost on re-render + await newPage.locator('text="Create your account"').waitFor(); - if (!proUser.username) throw Error("Test username is null, can't continue"); + // Fill in form + await newPage.fill('input[name="username"]', proUser.username); // Invalid username + await newPage.fill('input[name="password"]', testUser.password); + await submitAndWaitForResponse(newPage, "/api/auth/signup", { expectedStatusCode: 409 }); + await expect(newPage.locator('text="Username or email is already taken"')).toBeVisible(); - // Open a new user window to accept the invite - const newPage = await browser.newPage(); - await newPage.goto(`/auth/signup?token=${tokenObj.token}&callbackUrl=${WEBAPP_URL}/settings/teams`); + // Successful signup + // TODO: Form errors don't disappear when corrected and resubmitted, so we need to refresh + await newPage.reload(); + await newPage.fill('input[name="username"]', testUser.username); + await newPage.fill('input[name="password"]', testUser.password); + await submitAndWaitForResponse(newPage, "/api/auth/signup", { expectedStatusCode: 201 }); + // Since it's a new user, it shoud be redirected to the onboarding + await newPage.locator('text="Welcome to Cal.com!"').waitFor(); + await expect(newPage.locator('text="Welcome to Cal.com!"')).toBeVisible(); + // We don't need the new browser anymore + await newPage.close(); - // Fill in form - await newPage.fill('input[name="username"]', proUser.username); // Invalid username - await newPage.fill('input[name="email"]', testUser.email); - await newPage.fill('input[name="password"]', testUser.password); - await newPage.fill('input[name="passwordcheck"]', testUser.password); - await newPage.press('input[name="passwordcheck"]', "Enter"); // Press Enter to submit + const createdUser = await prisma.user.findUniqueOrThrow({ + where: { email: testUser.email }, + include: { + teams: { include: { team: true } }, + password: { + select: { hash: true }, + }, + }, + }); - await expect(newPage.locator('text="Username already taken"')).toBeVisible(); + console.log("createdUser", createdUser); - // Email address is already registered - // TODO: Form errors don't disappear when corrected and resubmitted, so we need to refresh - await newPage.reload(); - await newPage.fill('input[name="username"]', testUser.username); - await newPage.fill('input[name="email"]', `${proUser.username}@example.com`); // Taken email - await newPage.fill('input[name="password"]', testUser.password); - await newPage.fill('input[name="passwordcheck"]', testUser.password); - await newPage.press('input[name="passwordcheck"]', "Enter"); // Press Enter to submit - await expect(newPage.locator('text="Email address is already registered"')).toBeVisible(); - - // Successful signup - // TODO: Form errors don't disappear when corrected and resubmitted, so we need to refresh - await newPage.reload(); - await newPage.fill('input[name="username"]', testUser.username); - await newPage.fill('input[name="email"]', testUser.email); - await newPage.fill('input[name="password"]', testUser.password); - await newPage.fill('input[name="passwordcheck"]', testUser.password); - await newPage.press('input[name="passwordcheck"]', "Enter"); // Press Enter to submit - await expect(newPage.locator(`[data-testid="login-form"]`)).toBeVisible(); - - // We don't need the new browser anymore - await newPage.close(); - - const createdUser = await prisma.user.findUniqueOrThrow({ - where: { email: testUser.email }, - include: { teams: { include: { team: true } } }, - }); - - console.log("createdUser", createdUser); - - // Check that the user was created - expect(createdUser).not.toBeNull(); - expect(createdUser.username).toBe(testUser.username); - expect(createdUser.password).not.toBeNull(); - expect(createdUser.emailVerified).not.toBeNull(); - // Check that the user accepted the team invite - expect(createdUser.teams).toHaveLength(1); - expect(createdUser.teams[0].team.name).toBe(teamName); - expect(createdUser.teams[0].role).toBe("MEMBER"); - expect(createdUser.teams[0].accepted).toBe(true);*/ + // Check that the user was created + expect(createdUser).not.toBeNull(); + expect(createdUser.username).toBe(testUser.username); + expect(createdUser.password?.hash).not.toBeNull(); + expect(createdUser.emailVerified).not.toBeNull(); + // Check that the user accepted the team invite + expect(createdUser.teams).toHaveLength(1); + expect(createdUser.teams[0].team.name).toBe(teamName); + expect(createdUser.teams[0].role).toBe("MEMBER"); + expect(createdUser.teams[0].accepted).toBe(true); }); }); diff --git a/apps/web/playwright/availability.e2e.ts b/apps/web/playwright/availability.e2e.ts index 352e777e54..479b496c80 100644 --- a/apps/web/playwright/availability.e2e.ts +++ b/apps/web/playwright/availability.e2e.ts @@ -3,7 +3,7 @@ import { expect } from "@playwright/test"; import dayjs from "@calcom/dayjs"; import { test } from "./lib/fixtures"; -import { localize } from "./lib/testUtils"; +import { localize, submitAndWaitForResponse } from "./lib/testUtils"; test.describe.configure({ mode: "parallel" }); @@ -39,7 +39,7 @@ test.describe("Availablity", () => { const nextMonth = dayjs().add(1, "month").startOf("month"); const troubleshooterURL = `/availability/troubleshoot?date=${nextMonth.format("YYYY-MM-DD")}`; await page.goto(troubleshooterURL); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await expect(page.locator('[data-testid="troubleshooter-busy-time"]')).toHaveCount(1); }); @@ -121,18 +121,17 @@ test.describe("Availablity", () => { await test.step("Can delete a schedule", async () => { await page.getByTestId("go-back-button").click(); await page.locator('[data-testid="schedules"] > li').nth(1).getByTestId("schedule-more").click(); - await page.locator('[data-testid="delete-schedule"]').click(); - const toast = await page.waitForSelector('[data-testid="toast-success"]'); - expect(toast).toBeTruthy(); - + await submitAndWaitForResponse(page, "/api/trpc/availability/schedule.delete?batch=1", { + action: () => page.locator('[data-testid="delete-schedule"]').click(), + }); await expect(page.locator('[data-testid="schedules"] > li').nth(1)).toHaveCount(0); }); await test.step("Cannot delete the last schedule", async () => { await page.locator('[data-testid="schedules"] > li').nth(0).getByTestId("schedule-more").click(); await page.locator('[data-testid="delete-schedule"]').click(); + // FIXME: Check on toast to be present causes flakiness, cannot check for response since it's client side validated as well const toast = await page.waitForSelector('[data-testid="toast-error"]'); expect(toast).toBeTruthy(); - await expect(page.locator('[data-testid="schedules"] > li').nth(0)).toHaveCount(1); }); }); @@ -183,8 +182,7 @@ test.describe("Availablity", () => { await page.locator("[id=timeZone-lg-viewport]").fill("bras"); await page.getByTestId("select-option-America/Sao_Paulo").click(); - await page.getByRole("button", { name: save }).click(); - await expect(page.getByTestId("toast-success").last()).toBeVisible(); + await submitAndWaitForResponse(page, "/api/trpc/availability/schedule.update?batch=1"); await page.getByTestId("add-override").click(); await page.getByTestId("incrementMonth").click(); await page.getByRole("button", { name: "20" }).click(); @@ -192,7 +190,6 @@ test.describe("Availablity", () => { await page.getByTestId("add-override-submit-btn").click(); await page.getByTestId("dialog-rejection").click(); await page.getByTestId("date-overrides-list").getByRole("button").nth(1).click(); - await page.getByRole("button", { name: save }).click(); - await expect(page.getByTestId("toast-success").last()).toBeVisible(); + await submitAndWaitForResponse(page, "/api/trpc/availability/schedule.update?batch=1"); }); }); diff --git a/apps/web/playwright/booking-limits.e2e.ts b/apps/web/playwright/booking-limits.e2e.ts index 3ec1489b01..f5a49ea324 100644 --- a/apps/web/playwright/booking-limits.e2e.ts +++ b/apps/web/playwright/booking-limits.e2e.ts @@ -59,13 +59,12 @@ const getLastEventUrlWithMonth = (user: Awaited { +test.describe("Booking limits", () => { entries(BOOKING_LIMITS_SINGLE).forEach(([limitKey, bookingLimit]) => { const limitUnit = intervalLimitKeyToUnit(limitKey); // test one limit at a time - test(limitUnit, async ({ page, users }) => { + test.fixme(`Per ${limitUnit}`, async ({ page, users }) => { const slug = `booking-limit-${limitUnit}`; const singleLimit = { [limitKey]: bookingLimit }; @@ -166,7 +165,7 @@ test.skip("Booking limits", () => { await page.locator('[data-testid="confirm-reschedule-button"]').click(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await expect(page.locator("[data-testid=success-page]")).toBeVisible(); const newBooking = await prisma.booking.findFirstOrThrow({ where: { fromReschedule: bookingId } }); diff --git a/apps/web/playwright/booking-pages.e2e.ts b/apps/web/playwright/booking-pages.e2e.ts index 88fa60a369..388933e3e3 100644 --- a/apps/web/playwright/booking-pages.e2e.ts +++ b/apps/web/playwright/booking-pages.e2e.ts @@ -300,10 +300,10 @@ testBothFutureAndLegacyRoutes.describe("pro user", () => { await eventTypeLink.waitFor(); await eventTypeLink.click(); - await pageTwo.waitForLoadState("networkidle"); + // await pageTwo.waitForLoadState("networkidle"); await pageTwo.locator('[data-testid="incrementMonth"]').waitFor(); await pageTwo.click('[data-testid="incrementMonth"]'); - await pageTwo.waitForLoadState("networkidle"); + // await pageTwo.waitForLoadState("networkidle"); await pageTwo.locator('[data-testid="day"][data-disabled="false"]').nth(0).waitFor(); await pageTwo.locator('[data-testid="day"][data-disabled="false"]').nth(0).click(); @@ -337,10 +337,10 @@ testBothFutureAndLegacyRoutes.describe("pro user", () => { await page.locator('[data-testid="back"]').waitFor(); await page.click('[data-testid="back"]'); - await pageTwo.waitForLoadState("networkidle"); + // await pageTwo.waitForLoadState("networkidle"); await pageTwo.locator('[data-testid="incrementMonth"]').waitFor(); await pageTwo.click('[data-testid="incrementMonth"]'); - await pageTwo.waitForLoadState("networkidle"); + // await pageTwo.waitForLoadState("networkidle"); await pageTwo.locator('[data-testid="day"][data-disabled="false"]').nth(0).waitFor(); await pageTwo.locator('[data-testid="day"][data-disabled="false"]').nth(0).click(); @@ -509,7 +509,7 @@ testBothFutureAndLegacyRoutes.describe("Booking round robin event", () => { // books 9AM slots for 120 minutes (test-user is not available at this time, availability starts at 10) await page.locator('[data-testid="time"]').nth(0).click(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await page.locator('[name="name"]').fill("Test name"); await page.locator('[name="email"]').fill(`${randomString(4)}@example.com`); @@ -541,7 +541,7 @@ testBothFutureAndLegacyRoutes.describe("Booking round robin event", () => { // Again book a 9AM slot for 120 minutes where test-user is not available await page.locator('[data-testid="time"]').nth(0).click(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await page.locator('[name="name"]').fill("Test name"); await page.locator('[name="email"]').fill(`${randomString(4)}@example.com`); diff --git a/apps/web/playwright/booking-seats.e2e.ts b/apps/web/playwright/booking-seats.e2e.ts index 6c892a43de..33b20677b5 100644 --- a/apps/web/playwright/booking-seats.e2e.ts +++ b/apps/web/playwright/booking-seats.e2e.ts @@ -104,7 +104,9 @@ test.describe("Booking with Seats", () => { // confirm cancellation await page.locator('[data-testid="confirm_cancel"]').click(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); + + await expect(page.locator("text=This event is canceled")).toBeVisible(); const updatedBooking = await prisma.booking.findFirst({ where: { id: booking.id }, @@ -227,9 +229,9 @@ test.describe("Reschedule for booking with seats", () => { await page.locator('[data-testid="confirm_cancel"]').click(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); - await expect(page).toHaveURL(/\/booking\/.*/); + await expect(page.locator("text=You are no longer attending this event")).toBeVisible(); await page.goto( `/booking/${booking.uid}?cancel=true&allRemainingBookings=false&seatReferenceUid=${bookingSeats[1].referenceUid}` @@ -238,9 +240,9 @@ test.describe("Reschedule for booking with seats", () => { // Page should not be 404 await page.locator('[data-testid="confirm_cancel"]').click(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); - await expect(page).toHaveURL(/\/booking\/.*/); + await expect(page.locator("text=You are no longer attending this event")).toBeVisible(); }); test("Should book with seats and hide attendees info from showAttendees true", async ({ @@ -406,7 +408,7 @@ test.describe("Reschedule for booking with seats", () => { await expect(page).toHaveURL(/\/booking\/.*/); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const updatedBooking = await prisma.booking.findFirst({ where: { id: booking.id }, diff --git a/apps/web/playwright/change-password.e2e.ts b/apps/web/playwright/change-password.e2e.ts index e8eeaba41d..541af5bf23 100644 --- a/apps/web/playwright/change-password.e2e.ts +++ b/apps/web/playwright/change-password.e2e.ts @@ -13,7 +13,7 @@ test.describe("Change Password Test", () => { expect(pro.username).toBeTruthy(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); // Fill form await page.locator('[name="oldPassword"]').fill(String(pro.username)); diff --git a/apps/web/playwright/change-theme.e2e.ts b/apps/web/playwright/change-theme.e2e.ts index f2051f9eda..e7d2159644 100644 --- a/apps/web/playwright/change-theme.e2e.ts +++ b/apps/web/playwright/change-theme.e2e.ts @@ -9,7 +9,7 @@ test.describe("Change Theme Test", () => { await page.goto("/settings/my-account/appearance"); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); //Click the "Dark" theme label await page.click('[data-testid="theme-dark"]'); //Click the update button @@ -29,7 +29,7 @@ test.describe("Change Theme Test", () => { await page.goto("/settings/my-account/appearance"); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); //Click the "Light" theme label await page.click('[data-testid="theme-light"]'); //Click the update theme button diff --git a/apps/web/playwright/change-username.e2e.ts b/apps/web/playwright/change-username.e2e.ts index 56809bd55c..3892c72cbc 100644 --- a/apps/web/playwright/change-username.e2e.ts +++ b/apps/web/playwright/change-username.e2e.ts @@ -60,7 +60,7 @@ test.describe("Change username on settings", () => { page.click("[data-testid=save-username]"), page.getByTestId("toast-success").waitFor(), ]); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const updatedUser = await prisma.user.findUniqueOrThrow({ where: { @@ -149,7 +149,7 @@ test.describe("Change username on settings", () => { const usernameInput = page.locator("[data-testid=username-input]"); await usernameInput.fill(previousUsername); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await expect(page.locator("[data-testid=update-username-btn]").nth(0)).toBeHidden(); await expect(page.locator("[data-testid=update-username-btn]").nth(1)).toBeHidden(); }); diff --git a/apps/web/playwright/dynamic-booking-pages.e2e.ts b/apps/web/playwright/dynamic-booking-pages.e2e.ts index d17cd711f0..dfc969220a 100644 --- a/apps/web/playwright/dynamic-booking-pages.e2e.ts +++ b/apps/web/playwright/dynamic-booking-pages.e2e.ts @@ -70,7 +70,7 @@ test("dynamic booking info prefilled by query params", async ({ page, users }) = const free = await users.create({ username: "free.example" }); await page.goto(`/${pro.username}+${free.username}?duration=${duration}`); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const listItemByDurationTestId = (duration: number) => `multiple-choice-${duration}mins`; diff --git a/apps/web/playwright/event-types.e2e.ts b/apps/web/playwright/event-types.e2e.ts index 6dd3065975..778970ea63 100644 --- a/apps/web/playwright/event-types.e2e.ts +++ b/apps/web/playwright/event-types.e2e.ts @@ -64,7 +64,7 @@ testBothFutureAndLegacyRoutes.describe("Event Types tests", () => { const nonce = randomString(3); const eventTitle = `my recurring event ${nonce}`; await createNewEventType(page, { eventTitle }); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await page.click("[data-testid=vertical-tab-recurring]"); await expect(page.locator("[data-testid=recurring-event-collapsible]")).toBeHidden(); @@ -270,14 +270,14 @@ testBothFutureAndLegacyRoutes.describe("Event Types tests", () => { await addAnotherLocation(page, "Cal Video (Global)"); await saveEventType(page); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); // Remove Attendee Phone Number Location const removeButtomId = "delete-locations.0.type"; await page.getByTestId(removeButtomId).click(); await saveEventType(page); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await gotoBookingPage(page); await selectFirstAvailableTimeSlotNextMonth(page); diff --git a/apps/web/playwright/fixtures/apps.ts b/apps/web/playwright/fixtures/apps.ts index 2fa3499416..60f60dad4d 100644 --- a/apps/web/playwright/fixtures/apps.ts +++ b/apps/web/playwright/fixtures/apps.ts @@ -62,11 +62,11 @@ export function createAppsFixture(page: Page) { } await page.locator("[data-testid=display-location]").last().check(); await saveEventType(page); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await gotoBookingPage(page); await selectFirstAvailableTimeSlotNextMonth(page); await bookTimeSlot(page); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await expect(page.locator("[data-testid=success-page]")).toBeVisible(); await expect(page.locator("[data-testid=where] ")).toContainText(app.label); @@ -94,11 +94,11 @@ export function createAppsFixture(page: Page) { verifyConferencingAppNew: async (app: TApp, eventTypeIds: number[]) => { for (const id of eventTypeIds) { await page.goto(`/event-types/${id}`); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await gotoBookingPage(page); await selectFirstAvailableTimeSlotNextMonth(page); await bookTimeSlot(page, { name: `Test Testson`, email: `test@example.com` }); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await expect(page.locator("[data-testid=success-page]")).toBeVisible(); await expect(page.locator("[data-testid=where] ")).toContainText(app.label); } diff --git a/apps/web/playwright/hash-my-url.e2e.ts b/apps/web/playwright/hash-my-url.e2e.ts index 23cc51a3dd..d84e439522 100644 --- a/apps/web/playwright/hash-my-url.e2e.ts +++ b/apps/web/playwright/hash-my-url.e2e.ts @@ -32,7 +32,7 @@ test.describe("hash my url", () => { // click update await page.locator('[data-testid="update-eventtype"]').press("Enter"); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); // book using generated url hash await page.goto($url); @@ -61,7 +61,7 @@ test.describe("hash my url", () => { await page.locator("[data-testid=update-eventtype]").click(); const response = await submitPromise; expect(response.status()).toBe(200); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await page.locator(".primary-navigation >> text=Advanced").click(); const $url2 = await page.locator('//*[@data-testid="generated-hash-url"]').inputValue(); expect($url2.includes("somethingrandom")).toBeTruthy(); diff --git a/apps/web/playwright/impersonation.e2e.ts b/apps/web/playwright/impersonation.e2e.ts index 15c74fe9de..9e917d2a75 100644 --- a/apps/web/playwright/impersonation.e2e.ts +++ b/apps/web/playwright/impersonation.e2e.ts @@ -41,6 +41,7 @@ test.describe("Users can impersonate", async () => { await stopImpersonatingButton.click(); await expect(stopImpersonatingButton).toBeHidden(); + // await page.waitForLoadState("networkidle"); // Return to user const ogUser = await impersonatedUsernameInput.inputValue(); diff --git a/apps/web/playwright/insights.e2e.ts b/apps/web/playwright/insights.e2e.ts index 3537e66166..8ec67f4176 100644 --- a/apps/web/playwright/insights.e2e.ts +++ b/apps/web/playwright/insights.e2e.ts @@ -75,11 +75,10 @@ test.describe("Insights", async () => { // go to insights page await page.goto("/insights"); - await page.waitForLoadState("networkidle"); + await page.waitForURL(/.*\/insights\?teamId=[^&]*&isAll=false.*/); // expect url to have isAll and TeamId in query params - expect(page.url()).toContain("isAll=false"); - expect(page.url()).toContain("teamId="); + await expect(page).toHaveURL(/.*\/insights\?teamId=[^&]*&isAll=false.*/); }); test("should be able to go to insights as members", async ({ page, users }) => { @@ -92,12 +91,10 @@ test.describe("Insights", async () => { // go to insights page await page.goto("/insights"); - await page.waitForLoadState("networkidle"); + await page.waitForURL(/.*\/insights\?userId=[^&]*&isAll=false.*/); // expect url to have isAll and TeamId in query params - - expect(page.url()).toContain("isAll=false"); - expect(page.url()).not.toContain("teamId="); + await expect(page).toHaveURL(/.*\/insights\?userId=[^&]*&isAll=false.*/); }); test("team select filter should have 2 teams and your account option only as member", async ({ @@ -113,7 +110,7 @@ test.describe("Insights", async () => { // go to insights page await page.goto("/insights"); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); // get div from team select filter with this class flex flex-col gap-0.5 [&>*:first-child]:mt-1 [&>*:last-child]:mb-1 await page.getByTestId("dashboard-shell").getByText("Team: test-insights").click(); @@ -137,7 +134,7 @@ test.describe("Insights", async () => { await owner.apiLogin(); await page.goto("/insights"); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await page.getByTestId("dashboard-shell").getByText("All").nth(1).click(); @@ -223,7 +220,7 @@ test.describe("Insights", async () => { ) .nth(0) .click(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await page .locator( @@ -231,7 +228,7 @@ test.describe("Insights", async () => { ) .nth(1) .click(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); // press escape button to close the filter await page.keyboard.press("Escape"); @@ -250,7 +247,7 @@ test.describe("Insights", async () => { await owner.apiLogin(); await page.goto("/insights"); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const downloadPromise = page.waitForEvent("download"); diff --git a/apps/web/playwright/lib/testUtils.ts b/apps/web/playwright/lib/testUtils.ts index 2cdfb451cf..f474b4584d 100644 --- a/apps/web/playwright/lib/testUtils.ts +++ b/apps/web/playwright/lib/testUtils.ts @@ -430,3 +430,15 @@ export async function gotoBookingPage(page: Page) { export async function saveEventType(page: Page) { await page.locator("[data-testid=update-eventtype]").click(); } + +/** Fastest way so far to test for saving changes and form submissions */ +export async function submitAndWaitForResponse( + page: Page, + url: string, + { action = () => page.locator('[type="submit"]').click(), expectedStatusCode = 200 } = {} +) { + const submitPromise = page.waitForResponse(url); + await action(); + const response = await submitPromise; + expect(response.status()).toBe(expectedStatusCode); +} diff --git a/apps/web/playwright/managed-event-types.e2e.ts b/apps/web/playwright/managed-event-types.e2e.ts index 90eae36af2..3951594d2b 100644 --- a/apps/web/playwright/managed-event-types.e2e.ts +++ b/apps/web/playwright/managed-event-types.e2e.ts @@ -5,7 +5,12 @@ import { apiLogin } from "playwright/fixtures/users"; import { SchedulingType } from "@calcom/prisma/enums"; import { test, type Fixtures } from "./lib/fixtures"; -import { bookTimeSlot, localize, selectFirstAvailableTimeSlotNextMonth } from "./lib/testUtils"; +import { + bookTimeSlot, + localize, + submitAndWaitForResponse, + selectFirstAvailableTimeSlotNextMonth, +} from "./lib/testUtils"; test.afterEach(async ({ users }) => { await users.deleteAll(); @@ -98,7 +103,7 @@ test.describe("Managed Event Types", () => { const optionText = await getByKey(page, "organizer_default_conferencing_app"); await expect(optionText).toBeVisible(); await optionText.click(); - await submitAndWaitForResponse(page); + await saveAndWaitForResponse(page); await page.getByTestId("vertical-tab-assignment").click(); await gotoBookingPage(page); @@ -177,7 +182,7 @@ test.describe("Managed Event Types", () => { await memberPage.waitForURL("event-types/**"); await expect(memberPage.locator('input[name="title"]')).toBeEditable(); await memberPage.locator('input[name="title"]').fill(`Managed Event Title`); - await submitAndWaitForResponse(memberPage); + await saveAndWaitForResponse(memberPage); // We edit the managed event as original owner const adminContext = await browser.newContext(); @@ -188,7 +193,7 @@ test.describe("Managed Event Types", () => { await adminPage.getByTestId("event-types").locator(`a[title="${teamEventTitle}"]`).click(); await adminPage.waitForURL("event-types/**"); await adminPage.locator('input[name="length"]').fill(`45`); - await submitAndWaitForResponse(adminPage); + await saveAndWaitForResponse(adminPage); await adminContext.close(); await memberPage.goto("/event-types"); @@ -200,7 +205,7 @@ test.describe("Managed Event Types", () => { expect(await memberPage.locator(`input[name="title"]`).getAttribute("value")).toBe(`Managed Event Title`); await memberPage.locator('input[name="title"]').fill(`managed`); // Save changes - await submitAndWaitForResponse(memberPage); + await saveAndWaitForResponse(memberPage); }); const MANAGED_EVENT_TABS: { slug: string; locator: (page: Page) => Locator | Promise }[] = [ @@ -252,9 +257,6 @@ async function gotoBookingPage(page: Page) { await page.goto(previewLink ?? ""); } -async function submitAndWaitForResponse(page: Page) { - const submitPromise = page.waitForResponse("/api/trpc/eventTypes/update?batch=1"); - await page.locator('[type="submit"]').click(); - const response = await submitPromise; - expect(response.status()).toBe(200); +async function saveAndWaitForResponse(page: Page) { + await submitAndWaitForResponse(page, "/api/trpc/eventTypes/update?batch=1"); } diff --git a/apps/web/playwright/oauth-provider.e2e.ts b/apps/web/playwright/oauth-provider.e2e.ts index fae75e5cb7..3b4626518a 100644 --- a/apps/web/playwright/oauth-provider.e2e.ts +++ b/apps/web/playwright/oauth-provider.e2e.ts @@ -32,7 +32,7 @@ test.describe("OAuth Provider", () => { `auth/oauth2/authorize?client_id=${client.clientId}&redirect_uri=${client.redirectUri}&response_type=code&scope=READ_PROFILE&state=1234` ); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await page.getByTestId("allow-button").click(); await page.waitForFunction(() => { @@ -112,7 +112,7 @@ test.describe("OAuth Provider", () => { `auth/oauth2/authorize?client_id=${client.clientId}&redirect_uri=${client.redirectUri}&response_type=code&scope=READ_PROFILE&state=1234` ); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await page.locator("#account-select").click(); diff --git a/apps/web/playwright/organization/across-org/across-org.e2e.ts b/apps/web/playwright/organization/across-org/across-org.e2e.ts index 0bcc9e9a21..77ad84dbc6 100644 --- a/apps/web/playwright/organization/across-org/across-org.e2e.ts +++ b/apps/web/playwright/organization/across-org/across-org.e2e.ts @@ -47,14 +47,13 @@ test.describe("user1NotMemberOfOrg1 is part of team1MemberOfOrg1", () => { await user1NotMemberOfOrg1.apiLogin(); await page.goto("/event-types"); - await page.waitForLoadState("networkidle"); - - const userEventLinksLocators = await page - .locator(`[data-testid=slug-${user1NotMemberOfOrg1.username}] [data-testid="preview-link-button"]`) - .all(); + // await page.waitForLoadState("networkidle"); + const userEventLinksSelector = `[data-testid=slug-${user1NotMemberOfOrg1.username}] [data-testid="preview-link-button"]`; + await page.waitForSelector(userEventLinksSelector); + // Get all the event links + const userEventLinksLocators = await page.locator(userEventLinksSelector).all(); expect(userEventLinksLocators.length).toBeGreaterThan(0); - for (const userEventLinkLocator of userEventLinksLocators) { const href = await userEventLinkLocator.getAttribute("href"); expect(href).toContain(WEBAPP_URL); diff --git a/apps/web/playwright/organization/lib/inviteUser.ts b/apps/web/playwright/organization/lib/inviteUser.ts index 214862ed7f..bd18615a2f 100644 --- a/apps/web/playwright/organization/lib/inviteUser.ts +++ b/apps/web/playwright/organization/lib/inviteUser.ts @@ -13,7 +13,7 @@ export const inviteUserToOrganization = async ({ usersFixture: ReturnType; }) => { await page.goto("/settings/organizations/members"); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const invitedUserEmail = usersFixture.trackEmail({ username: email.split("@")[0], domain: email.split("@")[1], @@ -36,7 +36,7 @@ export const inviteExistingUserToOrganization = async ({ usersFixture: ReturnType; }) => { await page.goto("/settings/organizations/members"); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await inviteAnEmail(page, user.email); await page.waitForSelector('[data-testid="toast-success"]'); @@ -46,12 +46,12 @@ export const inviteExistingUserToOrganization = async ({ export async function acceptTeamOrOrgInvite(page: Page) { await page.goto("/settings/teams"); await page.click('[data-testid^="accept-invitation"]'); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); } async function inviteAnEmail(page: Page, invitedUserEmail: string) { await page.locator('button:text("Add")').click(); await page.locator('input[name="inviteUser"]').fill(invitedUserEmail); await page.locator('button:text("Send invite")').click(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); } diff --git a/apps/web/playwright/organization/organization-creation.e2e.ts b/apps/web/playwright/organization/organization-creation.e2e.ts index 77519c1b7b..5665ec90fc 100644 --- a/apps/web/playwright/organization/organization-creation.e2e.ts +++ b/apps/web/playwright/organization/organization-creation.e2e.ts @@ -131,7 +131,7 @@ test.describe("Organization", () => { const orgName = capitalize(`${orgOwnerUser.username}`); const orgSlug = `myOrg-${uuid()}`.toLowerCase(); await page.goto("/settings/organizations/new"); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await test.step("Basic info", async () => { // Check required fields @@ -192,7 +192,7 @@ test.describe("Organization", () => { await expect(page.getByTestId("pending-member-item")).toHaveCount(2); const lastRemoveMemberButton = page.getByTestId("remove-member-button").last(); await lastRemoveMemberButton.click(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await expect(page.getByTestId("pending-member-item")).toHaveCount(1); await page.getByTestId("publish-button").click(); // Waiting to be in next step URL @@ -232,7 +232,7 @@ test.describe("Organization", () => { expect(url).toContain(expectedUrl); await fillStripeTestCheckout(page); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const upgradeButtonHidden = await page.getByTestId("upgrade_org_banner_button"); @@ -268,7 +268,7 @@ test.describe("Organization", () => { }); await page.goto("/settings/organizations/new"); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await test.step("Basic info", async () => { // Check required fields @@ -309,7 +309,7 @@ test.describe("Organization", () => { await orgOwnerUser.apiLogin(); const orgName = capitalize(`${orgOwnerUsername}`); await page.goto("/settings/organizations/new"); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await test.step("Basic info", async () => { // These values are infered due to an existing user being signed @@ -320,7 +320,7 @@ test.describe("Organization", () => { await page.locator("input[name=slug]").fill(orgOwnerUsername); await page.locator("button[type=submit]").click(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); }); await test.step("About the organization", async () => { @@ -364,7 +364,7 @@ test.describe("Organization", () => { await expect(page.getByTestId("pending-member-item")).toHaveCount(2); const lastRemoveMemberButton = page.getByTestId("remove-member-button").last(); await lastRemoveMemberButton.click(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await expect(page.getByTestId("pending-member-item")).toHaveCount(1); await page.getByTestId("publish-button").click(); // Waiting to be in next step URL @@ -402,7 +402,7 @@ test.describe("Organization", () => { expect(url).toContain(expectedUrl); await fillStripeTestCheckout(page); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const upgradeButtonHidden = await page.getByTestId("upgrade_org_banner_button"); @@ -455,7 +455,7 @@ test.describe("Organization", () => { await slugLocator.fill(`example-${stringUUID}`); await page.locator("button[type=submit]").click(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); }); await test.step("About the organization", async () => { @@ -499,7 +499,7 @@ test.describe("Organization", () => { await expect(page.getByTestId("pending-member-item")).toHaveCount(2); const lastRemoveMemberButton = page.getByTestId("remove-member-button").last(); await lastRemoveMemberButton.click(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await expect(page.getByTestId("pending-member-item")).toHaveCount(1); await page.getByTestId("publish-button").click(); // Waiting to be in next step URL @@ -547,7 +547,7 @@ test.describe("Organization", () => { expect(url).toContain(expectedUrl); await fillStripeTestCheckout(page); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const upgradeButtonHidden = await page.getByTestId("upgrade_org_banner_button"); @@ -557,7 +557,7 @@ test.describe("Organization", () => { await test.step("Ensure correctnumberOfTeams are migrated", async () => { // eslint-disable-next-line playwright/no-skipped-test await page.goto("/teams"); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const teamListItems = await page.getByTestId("team-list-item-link").all(); // Number of teams migrated + the two created in the create teams step diff --git a/apps/web/playwright/organization/organization-invitation.e2e.ts b/apps/web/playwright/organization/organization-invitation.e2e.ts index 858fba51f9..0558c40a6a 100644 --- a/apps/web/playwright/organization/organization-invitation.e2e.ts +++ b/apps/web/playwright/organization/organization-invitation.e2e.ts @@ -24,7 +24,7 @@ test.describe("Organization", () => { const { team: org } = await orgOwner.getOrgMembership(); await orgOwner.apiLogin(); await page.goto("/settings/organizations/members"); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await test.step("By email", async () => { const invitedUserEmail = users.trackEmail({ username: "rick", domain: "domain.com" }); @@ -104,7 +104,7 @@ test.describe("Organization", () => { await test.step("By email", async () => { await page.goto(`/settings/teams/${team.id}/members`); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const invitedUserEmail = users.trackEmail({ username: "rick", domain: "domain.com" }); // '-domain' because the email doesn't match orgAutoAcceptEmail const usernameDerivedFromEmail = `${invitedUserEmail.split("@")[0]}-domain`; @@ -126,7 +126,7 @@ test.describe("Organization", () => { email: invitedUserEmail, }); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const inviteLink = await expectInvitationEmailToBeReceived( page, emails, @@ -206,7 +206,7 @@ test.describe("Organization", () => { const { team: org } = await orgOwner.getOrgMembership(); await orgOwner.apiLogin(); await page.goto("/settings/organizations/members"); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await test.step("By email", async () => { const invitedUserEmail = users.trackEmail({ username: "rick", domain: "example.com" }); @@ -309,6 +309,7 @@ test.describe("Organization", () => { .locator('input[name="email"]') .fill(`${existingUser.username}-differnet-email@example.com`); await page.locator('input[name="password"]').fill("Password99!"); + // await page.waitForLoadState("networkidle"); await expect(page.locator('button[type="submit"]')).toBeDisabled(); }); }); @@ -333,7 +334,7 @@ test.describe("Organization", () => { await test.step("By email", async () => { await page.goto(`/settings/teams/${team.id}/members`); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const invitedUserEmail = users.trackEmail({ username: "rick", domain: "example.com" }); const usernameDerivedFromEmail = invitedUserEmail.split("@")[0]; await inviteAnEmail(page, invitedUserEmail); @@ -488,7 +489,7 @@ export async function signupFromEmailInviteLink({ async function inviteAnEmail(page: Page, invitedUserEmail: string) { await page.locator('button:text("Add")').click(); await page.locator('input[name="inviteUser"]').fill(invitedUserEmail); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const submitPromise = page.waitForResponse("/api/trpc/teams/inviteMember?batch=1"); await page.locator('button:text("Send invite")').click(); const response = await submitPromise; diff --git a/apps/web/playwright/organization/team-management.e2e.ts b/apps/web/playwright/organization/team-management.e2e.ts index 72827b9e7d..fb9c24fc6e 100644 --- a/apps/web/playwright/organization/team-management.e2e.ts +++ b/apps/web/playwright/organization/team-management.e2e.ts @@ -57,7 +57,7 @@ test.describe("Teams", () => { await expect(page.getByTestId("pending-member-item")).toHaveCount(2); const lastRemoveMemberButton = page.getByTestId("remove-member-button").last(); await lastRemoveMemberButton.click(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await expect(page.getByTestId("pending-member-item")).toHaveCount(1); // Cleanup here since this user is created without our fixtures. diff --git a/apps/web/playwright/out-of-office.e2e.ts b/apps/web/playwright/out-of-office.e2e.ts index 71dfadc777..e805ebf164 100644 --- a/apps/web/playwright/out-of-office.e2e.ts +++ b/apps/web/playwright/out-of-office.e2e.ts @@ -1,5 +1,5 @@ -import { expect } from "@playwright/test"; import type { Page } from "@playwright/test"; +import { expect } from "@playwright/test"; import { v4 as uuidv4 } from "uuid"; import dayjs from "@calcom/dayjs"; @@ -7,6 +7,7 @@ import { randomString } from "@calcom/lib/random"; import prisma from "@calcom/prisma"; import { test } from "./lib/fixtures"; +import { submitAndWaitForResponse } from "./lib/testUtils"; test.describe.configure({ mode: "parallel" }); test.afterEach(async ({ users }) => { @@ -20,10 +21,8 @@ test.describe("Out of office", () => { await user.apiLogin(); await page.goto("/settings/my-account/out-of-office"); - await page.waitForLoadState("networkidle"); await page.getByTestId("add_entry_ooo").click(); - await page.waitForLoadState("networkidle"); await page.getByTestId("reason_select").click(); await page.getByTestId("select-option-4").click(); @@ -32,7 +31,9 @@ test.describe("Out of office", () => { await page.getByTestId("notes_input").fill("Demo notes"); // send request - await submitAndWaitForResponse(page); + await saveAndWaitForResponse(page); + + await expect(page.locator(`data-testid=table-redirect-n-a`)).toBeVisible(); }); test("User can configure booking redirect", async ({ page, users }) => { @@ -67,10 +68,8 @@ test.describe("Out of office", () => { await user.apiLogin(); await page.goto(`/settings/my-account/out-of-office`); - await page.waitForLoadState("networkidle"); await page.getByTestId("add_entry_ooo").click(); - await page.waitForLoadState("networkidle"); await page.getByTestId("reason_select").click(); await page.getByTestId("select-option-4").click(); @@ -86,7 +85,10 @@ test.describe("Out of office", () => { await page.locator("#react-select-3-input").press("Enter"); // send request - await submitAndWaitForResponse(page); + await saveAndWaitForResponse(page); + + // expect table-redirect-toUserId to be visible + await expect(page.locator(`data-testid=table-redirect-${userTo.username}`)).toBeVisible(); }); test("User can edit out of office entry", async ({ page, users }) => { @@ -146,7 +148,6 @@ test.describe("Out of office", () => { await user.apiLogin(); await page.goto(`/settings/my-account/out-of-office`); - await page.waitForLoadState("networkidle"); // expect table-redirect-toUserId to be visible await expect(page.locator(`data-testid=table-redirect-${userTo.username}`)).toBeVisible(); @@ -163,7 +164,16 @@ test.describe("Out of office", () => { await page.locator("#react-select-3-input").press("Enter"); // send request - await submitAndWaitForResponse(page); + await saveAndWaitForResponse(page); + + // expect entry with new username exist. + await expect(page.locator(`data-testid=table-redirect-${userToSecond.username}`)).toBeVisible(); + + // expect new note to be present. + await expect(page.locator(`data-testid=ooo-entry-note-${userToSecond.username}`)).toBeVisible(); + await expect(page.locator(`data-testid=ooo-entry-note-${userToSecond.username}`)).toContainText( + "Changed notes" + ); }); test("Profile redirection", async ({ page, users }) => { @@ -187,7 +197,6 @@ test.describe("Out of office", () => { }); await page.goto(`/${user.username}`); - await page.waitForLoadState("networkidle"); const eventTypeLink = page.locator('[data-testid="event-type-link"]').first(); await eventTypeLink.click(); @@ -195,9 +204,9 @@ test.describe("Out of office", () => { await expect(page.getByTestId("away-emoji")).toBeTruthy(); }); }); -async function submitAndWaitForResponse(page: Page) { - const submitPromise = page.waitForResponse("/api/trpc/viewer/outOfOfficeCreateOrUpdate?batch=1"); - await page.getByTestId("create-or-edit-entry-ooo-redirect").click(); - const response = await submitPromise; - expect(response.status()).toBe(200); + +async function saveAndWaitForResponse(page: Page) { + await submitAndWaitForResponse(page, "/api/trpc/viewer/outOfOfficeCreateOrUpdate?batch=1", { + action: () => page.getByTestId("create-or-edit-entry-ooo-redirect").click(), + }); } diff --git a/apps/web/playwright/overlay-calendar.e2e.ts b/apps/web/playwright/overlay-calendar.e2e.ts index d6ed744917..3494ffc4f0 100644 --- a/apps/web/playwright/overlay-calendar.e2e.ts +++ b/apps/web/playwright/overlay-calendar.e2e.ts @@ -31,7 +31,7 @@ export {}; // await test.step("Settings should so no calendars connected", async () => { // const settingsCog = page.locator(`[data-testid=overlay-calendar-settings-button]`); // await settingsCog.click(); -// await page.waitForLoadState("networkidle"); +// // await page.waitForLoadState("networkidle"); // const emptyScreenLocator = page.locator(`[data-testid=empty-screen]`); // await expect(emptyScreenLocator).toBeVisible(); // }); diff --git a/apps/web/playwright/payment.e2e.ts b/apps/web/playwright/payment.e2e.ts index 8d4a29fc1a..bd1a98b830 100644 --- a/apps/web/playwright/payment.e2e.ts +++ b/apps/web/playwright/payment.e2e.ts @@ -43,7 +43,7 @@ testBothFutureAndLegacyRoutes.describe("Payment", (routeVariant) => { await page.goto(`${user.username}/30-min`); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await selectFirstAvailableTimeSlotNextMonth(page); await bookTimeSlot(page); diff --git a/apps/web/playwright/profile.e2e.ts b/apps/web/playwright/profile.e2e.ts index 04fbdf1a4e..17289291d7 100644 --- a/apps/web/playwright/profile.e2e.ts +++ b/apps/web/playwright/profile.e2e.ts @@ -198,7 +198,7 @@ test.describe("Update Profile", () => { secondaryEmail: string; }) => { await test.step("the user receives the correct invitation link", async () => { - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const verificationToken = await prisma.verificationToken.findFirst({ where: { identifier: secondaryEmail, @@ -248,7 +248,7 @@ test.describe("Update Profile", () => { expect(await secondaryEmailConfirmDialog.isVisible()).toBe(false); await test.step("the user receives the correct invitation link", async () => { - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const verificationToken = await prisma.verificationToken.findFirst({ where: { identifier: secondaryEmail, diff --git a/apps/web/playwright/reschedule.e2e.ts b/apps/web/playwright/reschedule.e2e.ts index 85f3cb906a..394cc9786c 100644 --- a/apps/web/playwright/reschedule.e2e.ts +++ b/apps/web/playwright/reschedule.e2e.ts @@ -96,7 +96,7 @@ test.describe("Reschedule Tests", async () => { await page.locator('[data-testid="confirm-reschedule-button"]').click(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await expect(page.locator("[data-testid=success-page]")).toBeVisible(); diff --git a/apps/web/playwright/signup.e2e.ts b/apps/web/playwright/signup.e2e.ts index da171cf19b..4dee6a59c7 100644 --- a/apps/web/playwright/signup.e2e.ts +++ b/apps/web/playwright/signup.e2e.ts @@ -25,7 +25,7 @@ test.describe("Signup Flow Test", async () => { }); await page.goto("/signup"); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const alertMessage = "Username or email is already taken"; @@ -52,7 +52,7 @@ test.describe("Signup Flow Test", async () => { }); await page.goto("/signup"); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const alertMessage = "Username or email is already taken"; @@ -83,7 +83,7 @@ test.describe("Signup Flow Test", async () => { // Signup with premium username name await page.goto("/signup"); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); // Fill form await page.locator('input[name="username"]').fill("rock"); @@ -111,7 +111,7 @@ test.describe("Signup Flow Test", async () => { }); await page.goto("/signup"); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); // Fill form await page.locator('input[name="username"]').fill(userToCreate.username); @@ -179,7 +179,7 @@ test.describe("Signup Flow Test", async () => { const signupUrlWithToken = `/signup?token=${token}`; await page.goto(signupUrlWithToken); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const usernameField = page.locator('input[name="username"]'); const emailField = page.locator('input[name="email"]'); @@ -250,7 +250,7 @@ test.describe("Signup Flow Test", async () => { const { team } = await teamOwner.getFirstTeamMembership(); await teamOwner.apiLogin(); await page.goto(`/settings/teams/${team.id}/members`); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await test.step("Invite User to team", async () => { // TODO: This invite logic should live in a fixture - its used in team and orgs invites (Duplicated from team/org invites) @@ -258,7 +258,7 @@ test.describe("Signup Flow Test", async () => { await page.locator(`button:text("${t("add")}")`).click(); await page.locator('input[name="inviteUser"]').fill(invitedUserEmail); await page.locator(`button:text("${t("send_invite")}")`).click(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const inviteLink = await expectInvitationEmailToBeReceived( page, emails, diff --git a/apps/web/playwright/team/team-invitation.e2e.ts b/apps/web/playwright/team/team-invitation.e2e.ts index d5c5c77a3d..0417a0d2e7 100644 --- a/apps/web/playwright/team/team-invitation.e2e.ts +++ b/apps/web/playwright/team/team-invitation.e2e.ts @@ -19,7 +19,7 @@ test.describe("Team", () => { const { team } = await teamOwner.getFirstTeamMembership(); await teamOwner.apiLogin(); await page.goto(`/settings/teams/${team.id}/members`); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await test.step("To the team by email (external user)", async () => { const invitedUserEmail = users.trackEmail({ @@ -29,7 +29,7 @@ test.describe("Team", () => { await page.locator(`button:text("${t("add")}")`).click(); await page.locator('input[name="inviteUser"]').fill(invitedUserEmail); await page.locator(`button:text("${t("send_invite")}")`).click(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const inviteLink = await expectInvitationEmailToBeReceived( page, emails, @@ -66,7 +66,7 @@ test.describe("Team", () => { // Check newly invited member is not pending anymore await page.bringToFront(); await page.goto(`/settings/teams/${team.id}/members`); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await expect( page.locator(`[data-testid="email-${invitedUserEmail.replace("@", "")}-pending"]`) ).toHaveCount(0); @@ -103,7 +103,7 @@ test.describe("Team", () => { const { team } = await teamOwner.getFirstTeamMembership(); await teamOwner.apiLogin(); await page.goto(`/settings/teams/${team.id}/members`); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await test.step("To the organization by email (internal user)", async () => { const invitedUserEmail = users.trackEmail({ @@ -113,7 +113,7 @@ test.describe("Team", () => { await page.locator(`button:text("${t("add")}")`).click(); await page.locator('input[name="inviteUser"]').fill(invitedUserEmail); await page.locator(`button:text("${t("send_invite")}")`).click(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await expectInvitationEmailToBeReceived( page, emails, diff --git a/apps/web/playwright/teams.e2e.ts b/apps/web/playwright/teams.e2e.ts index 8f190d791a..ddf0f81587 100644 --- a/apps/web/playwright/teams.e2e.ts +++ b/apps/web/playwright/teams.e2e.ts @@ -44,7 +44,7 @@ testBothFutureAndLegacyRoutes.describe("Teams - NonOrg", (routeVariant) => { await user.apiLogin(); page.goto(`/settings/teams/${team.id}/onboard-members`); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await test.step("Can add members", async () => { // Click [data-testid="new-member-button"] diff --git a/apps/web/playwright/unpublished.e2e.ts b/apps/web/playwright/unpublished.e2e.ts index 6ba782515c..4b81668f0a 100644 --- a/apps/web/playwright/unpublished.e2e.ts +++ b/apps/web/playwright/unpublished.e2e.ts @@ -47,7 +47,7 @@ test.describe("Unpublished", () => { const { team: org } = await owner.getOrgMembership(); const { requestedSlug } = org.metadata as { requestedSlug: string }; await page.goto(`/org/${requestedSlug}`); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await expect(page.locator('[data-testid="empty-screen"]')).toHaveCount(1); await expect(page.locator(`h2:has-text("${title(org.name)}")`)).toHaveCount(1); await expect(page.locator(`div:text("${description("organization")}")`)).toHaveCount(1); @@ -65,7 +65,7 @@ test.describe("Unpublished", () => { const { requestedSlug } = org.metadata as { requestedSlug: string }; const [{ slug: subteamSlug }] = org.children as { slug: string }[]; await page.goto(`/org/${requestedSlug}/team/${subteamSlug}`); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await expect(page.locator('[data-testid="empty-screen"]')).toHaveCount(1); await expect(page.locator(`h2:has-text("${title(org.name)}")`)).toHaveCount(1); await expect(page.locator(`div:text("${description("organization")}")`)).toHaveCount(1); @@ -84,7 +84,7 @@ test.describe("Unpublished", () => { const [{ slug: subteamSlug, id: subteamId }] = org.children as { slug: string; id: number }[]; const { slug: subteamEventSlug } = await owner.getFirstTeamEvent(subteamId); await page.goto(`/org/${requestedSlug}/team/${subteamSlug}/${subteamEventSlug}`); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await expect(page.locator('[data-testid="empty-screen"]')).toHaveCount(1); await expect(page.locator(`h2:has-text("${title(org.name)}")`)).toHaveCount(1); @@ -97,7 +97,7 @@ test.describe("Unpublished", () => { const { team: org } = await owner.getOrgMembership(); const { requestedSlug } = org.metadata as { requestedSlug: string }; await page.goto(`/org/${requestedSlug}/${owner.username}`); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await expect(page.locator('[data-testid="empty-screen"]')).toHaveCount(1); await expect(page.locator(`h2:has-text("${title(org.name)}")`)).toHaveCount(1); await expect(page.locator(`div:text("${description("organization")}")`)).toHaveCount(1); @@ -110,7 +110,7 @@ test.describe("Unpublished", () => { const { requestedSlug } = org.metadata as { requestedSlug: string }; const [{ slug: ownerEventType }] = owner.eventTypes; await page.goto(`/org/${requestedSlug}/${owner.username}/${ownerEventType}`); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await expect(page.locator('[data-testid="empty-screen"]')).toHaveCount(1); await expect(page.locator(`h2:has-text("${title(org.name)}")`)).toHaveCount(1); await expect(page.locator(`div:text("${description("organization")}")`)).toHaveCount(1); diff --git a/apps/web/playwright/webhook.e2e.ts b/apps/web/playwright/webhook.e2e.ts index 1895f65027..8df73e283b 100644 --- a/apps/web/playwright/webhook.e2e.ts +++ b/apps/web/playwright/webhook.e2e.ts @@ -577,9 +577,11 @@ test.describe("MEETING_ENDED, MEETING_STARTED", async () => { expect(newMeetingEndedTriggers.length).toBe(0); // disable webhook + await page.click('[data-testid="webhook-switch"]'); await page.getByTestId("webhook-switch").click(); const response = await page.waitForResponse("/api/trpc/webhook/edit?batch=1"); expect(response.status()).toBe(200); + // await page.waitForLoadState("networkidle"); const scheduledTriggersAfterDisabling = await prisma.webhookScheduledTriggers.findMany({ where: { @@ -608,7 +610,7 @@ test.describe("FORM_SUBMITTED", async () => { await user.apiLogin(); const webhookReceiver = await webhooks.createReceiver(); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); const form = await routingForms.create({ name: "Test Form", @@ -624,7 +626,7 @@ test.describe("FORM_SUBMITTED", async () => { ], }); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await gotoRoutingLink({ page, formId: form.id }); const fieldName = "name"; @@ -693,7 +695,7 @@ test.describe("FORM_SUBMITTED", async () => { ], }); - await page.waitForLoadState("networkidle"); + // await page.waitForLoadState("networkidle"); await gotoRoutingLink({ page, formId: form.id }); const textFieldIdentifier = "name"; diff --git a/packages/app-store/routing-forms/playwright/tests/basic.e2e.ts b/packages/app-store/routing-forms/playwright/tests/basic.e2e.ts index a5808a8736..9a9f95fcca 100644 --- a/packages/app-store/routing-forms/playwright/tests/basic.e2e.ts +++ b/packages/app-store/routing-forms/playwright/tests/basic.e2e.ts @@ -365,6 +365,7 @@ test.describe("Routing Forms", () => { const routingForm = user.routingForms[0]; await page.goto(`apps/routing-forms/form-edit/${routingForm.id}`); await page.click('[data-testid="test-preview"]'); + // await page.waitForLoadState("networkidle"); //event redirect await page.fill('[data-testid="form-field-Test field"]', "event-routing"); diff --git a/playwright.config.ts b/playwright.config.ts index 1f069d9a33..27f202ac71 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -57,12 +57,14 @@ if (IS_EMBED_REACT_TEST) { }); } -const DEFAULT_CHROMIUM = { +const DEFAULT_CHROMIUM: NonNullable[number]["use"] = { ...devices["Desktop Chrome"], timezoneId: "Europe/London", storageState: { cookies: [ { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore TS definitions for USE are wrong. url: WEBAPP_URL, name: "calcom-timezone-dialog", expires: -1, @@ -73,6 +75,10 @@ const DEFAULT_CHROMIUM = { locale: "en-US", /** If navigation takes more than this, then something's wrong, let's fail fast. */ navigationTimeout: DEFAULT_NAVIGATION_TIMEOUT, + // chromium-specific permissions - Chromium seems to be the only browser type that requires perms + contextOptions: { + permissions: ["clipboard-read", "clipboard-write"], + }, }; const config: PlaywrightTestConfig = { @@ -96,10 +102,6 @@ const config: PlaywrightTestConfig = { locale: "en-US", trace: "retain-on-failure", headless, - // chromium-specific permissions - Chromium seems to be the only browser type that requires perms - contextOptions: { - permissions: ["clipboard-read", "clipboard-write"], - }, }, projects: [ {