diff --git a/apps/web/pages/booking/[uid].tsx b/apps/web/pages/booking/[uid].tsx index c1b27528c8..3ef82da92b 100644 --- a/apps/web/pages/booking/[uid].tsx +++ b/apps/web/pages/booking/[uid].tsx @@ -27,6 +27,7 @@ import { getBookingWithResponses } from "@calcom/features/bookings/lib/get-booki import { SystemField, getBookingFieldsWithSystemFields, + SMS_REMINDER_NUMBER_FIELD, } from "@calcom/features/bookings/lib/getBookingFields"; import { parseRecurringEvent } from "@calcom/lib"; import { APP_NAME } from "@calcom/lib/constants"; @@ -487,7 +488,8 @@ export default function Success(props: SuccessProps) { // We show rescheduleReason at the top if (!field) return null; const isSystemField = SystemField.safeParse(field.name); - if (isSystemField.success) return null; + // SMS_REMINDER_NUMBER_FIELD is a system field but doesn't have a dedicated place in the UI. So, it would be shown through the following responses list + if (isSystemField.success && field.name !== SMS_REMINDER_NUMBER_FIELD) return null; const label = field.label || t(field.defaultLabel || ""); diff --git a/apps/web/playwright/auth/delete-account.e2e.ts b/apps/web/playwright/auth/delete-account.e2e.ts index 61c976b932..73df266ac7 100644 --- a/apps/web/playwright/auth/delete-account.e2e.ts +++ b/apps/web/playwright/auth/delete-account.e2e.ts @@ -19,7 +19,10 @@ test("Can delete user account", async ({ page, users }) => { const $passwordField = page.locator("[data-testid=password]"); await $passwordField.fill(user.username); - await Promise.all([page.waitForNavigation({ url: "/auth/logout" }), page.click("text=Delete my account")]); + await Promise.all([ + page.waitForURL((url) => url.pathname === "/auth/logout"), + page.click("text=Delete my account"), + ]); await expect(page.locator(`[id="modal-title"]`)).toHaveText("You've been logged out"); }); diff --git a/apps/web/playwright/auth/forgot-password.e2e.ts b/apps/web/playwright/auth/forgot-password.e2e.ts index ac82c2a7d4..ead9e4e9da 100644 --- a/apps/web/playwright/auth/forgot-password.e2e.ts +++ b/apps/web/playwright/auth/forgot-password.e2e.ts @@ -17,9 +17,7 @@ test("Can reset forgotten password", async ({ page, users }) => { // Press Enter await Promise.all([ - page.waitForNavigation({ - url: (u) => u.pathname.startsWith("/auth/forgot-password/"), - }), + page.waitForURL((u) => u.pathname.startsWith("/auth/forgot-password/")), page.press('input[name="email"]', "Enter"), ]); @@ -38,7 +36,7 @@ test("Can reset forgotten password", async ({ page, users }) => { await expect(page.locator(`text=Password updated`)).toBeVisible(); // Click button:has-text("Login") await Promise.all([ - page.waitForNavigation({ url: (u) => u.pathname.startsWith("/auth/login") }), + page.waitForURL((u) => u.pathname.startsWith("/auth/login")), page.click('a:has-text("Login")'), ]); diff --git a/apps/web/playwright/booking-pages.e2e.ts b/apps/web/playwright/booking-pages.e2e.ts index 985125be5a..b54728c4ce 100644 --- a/apps/web/playwright/booking-pages.e2e.ts +++ b/apps/web/playwright/booking-pages.e2e.ts @@ -31,10 +31,8 @@ testBothBookers.describe("free user", (bookerVariant) => { // eslint-disable-next-line playwright/no-conditional-in-test if (bookerVariant !== "new-booker") { // Navigate to book page - await page.waitForNavigation({ - url(url) { - return url.pathname.endsWith("/book"); - }, + await page.waitForURL((url) => { + return url.pathname.endsWith("/book"); }); } @@ -84,19 +82,15 @@ testBothBookers.describe("pro user", () => { await page.waitForSelector('[data-testid="bookings"]'); await page.locator('[data-testid="edit_booking"]').nth(0).click(); await page.locator('[data-testid="reschedule"]').click(); - await page.waitForNavigation({ - url: (url) => { - const bookingId = url.searchParams.get("rescheduleUid"); - return !!bookingId; - }, + await page.waitForURL((url) => { + const bookingId = url.searchParams.get("rescheduleUid"); + return !!bookingId; }); await selectSecondAvailableTimeSlotNextMonth(page); // --- fill form await page.locator('[data-testid="confirm-reschedule-button"]').click(); - await page.waitForNavigation({ - url(url) { - return url.pathname.startsWith("/booking"); - }, + await page.waitForURL((url) => { + return url.pathname.startsWith("/booking"); }); }); @@ -108,10 +102,8 @@ testBothBookers.describe("pro user", () => { await page.goto("/bookings/upcoming"); await page.locator('[data-testid="cancel"]').first().click(); - await page.waitForNavigation({ - url: (url) => { - return url.pathname.startsWith("/booking"); - }, + await page.waitForURL((url) => { + return url.pathname.startsWith("/booking"); }); await page.locator('[data-testid="cancel"]').click(); diff --git a/apps/web/playwright/booking-seats.e2e.ts b/apps/web/playwright/booking-seats.e2e.ts index 74e5214119..f4fd821a6d 100644 --- a/apps/web/playwright/booking-seats.e2e.ts +++ b/apps/web/playwright/booking-seats.e2e.ts @@ -71,10 +71,8 @@ testBothBookers.describe("Booking with Seats", (bookerVariant) => { // to change the test as little as possible. // eslint-disable-next-line playwright/no-conditional-in-test if (bookerVariant === "old-booker") { - await page.waitForNavigation({ - url(url) { - return url.pathname.endsWith("/book"); - }, + await page.waitForURL((url) => { + return url.pathname.endsWith("/book"); }); } @@ -192,7 +190,7 @@ testBothBookers.describe("Booking with Seats", (bookerVariant) => { await page.locator('[data-testid="confirm-reschedule-button"]').click(); - await page.waitForNavigation({ url: /.*booking/ }); + await page.waitForURL(/.*booking/); await page.goto(`/reschedule/${references[1].referenceUid}`); @@ -200,6 +198,7 @@ testBothBookers.describe("Booking with Seats", (bookerVariant) => { await page.locator('[data-testid="confirm-reschedule-button"]').click(); + // Using waitForUrl here fails the assertion `expect(oldBooking?.status).toBe(BookingStatus.CANCELLED);` probably because waitForUrl is considered complete before waitForNavigation and till that time the booking is not cancelled await page.waitForNavigation({ url: /.*booking/ }); // Should expect old booking to be cancelled diff --git a/apps/web/playwright/dynamic-booking-pages.e2e.ts b/apps/web/playwright/dynamic-booking-pages.e2e.ts index 21d6917cea..9f101760fa 100644 --- a/apps/web/playwright/dynamic-booking-pages.e2e.ts +++ b/apps/web/playwright/dynamic-booking-pages.e2e.ts @@ -31,19 +31,15 @@ test.skip("dynamic booking", async ({ page, users }) => { await page.goto("/bookings/upcoming"); await page.locator('[data-testid="edit_booking"]').nth(0).click(); await page.locator('[data-testid="reschedule"]').click(); - await page.waitForNavigation({ - url: (url) => { - const bookingId = url.searchParams.get("rescheduleUid"); - return !!bookingId; - }, + await page.waitForURL((url) => { + const bookingId = url.searchParams.get("rescheduleUid"); + return !!bookingId; }); await selectSecondAvailableTimeSlotNextMonth(page); // --- fill form await page.locator('[data-testid="confirm-reschedule-button"]').click(); - await page.waitForNavigation({ - url(url) { - return url.pathname.startsWith("/booking"); - }, + await page.waitForURL((url) => { + return url.pathname.startsWith("/booking"); }); await expect(page.locator("[data-testid=success-page]")).toBeVisible(); }); @@ -51,10 +47,8 @@ test.skip("dynamic booking", async ({ page, users }) => { await test.step("Can cancel the recently created booking", async () => { await page.goto("/bookings/upcoming"); await page.locator('[data-testid="cancel"]').first().click(); - await page.waitForNavigation({ - url: (url) => { - return url.pathname.startsWith("/booking"); - }, + await page.waitForURL((url) => { + return url.pathname.startsWith("/booking"); }); await page.locator('[data-testid="cancel"]').click(); diff --git a/apps/web/playwright/embed-code-generator.e2e.ts b/apps/web/playwright/embed-code-generator.e2e.ts index 45cc1986a1..ab1a195bc7 100644 --- a/apps/web/playwright/embed-code-generator.e2e.ts +++ b/apps/web/playwright/embed-code-generator.e2e.ts @@ -36,14 +36,12 @@ async function expectToBeNavigatingToEmbedTypesDialog( if (!embedUrl) { throw new Error("Couldn't find embedUrl"); } - await page.waitForNavigation({ - url: (url) => { - return ( - url.pathname === basePage && - url.searchParams.get("dialog") === "embed" && - url.searchParams.get("embedUrl") === embedUrl - ); - }, + await page.waitForURL((url) => { + return ( + url.pathname === basePage && + url.searchParams.get("dialog") === "embed" && + url.searchParams.get("embedUrl") === embedUrl + ); }); } @@ -54,16 +52,14 @@ async function expectToBeNavigatingToEmbedCodeAndPreviewDialog( if (!embedUrl) { throw new Error("Couldn't find embedUrl"); } - await page.waitForNavigation({ - url: (url) => { - return ( - url.pathname === basePage && - url.searchParams.get("dialog") === "embed" && - url.searchParams.get("embedUrl") === embedUrl && - url.searchParams.get("embedType") === embedType && - url.searchParams.get("embedTabName") === "embed-code" - ); - }, + await page.waitForURL((url) => { + return ( + url.pathname === basePage && + url.searchParams.get("dialog") === "embed" && + url.searchParams.get("embedUrl") === embedUrl && + url.searchParams.get("embedType") === embedType && + url.searchParams.get("embedTabName") === "embed-code" + ); }); } @@ -183,9 +179,7 @@ test.describe("Embed Code Generator Tests", () => { await page.goto(`/event-types`); await Promise.all([ page.locator('[href*="/event-types/"]').first().click(), - page.waitForNavigation({ - url: (url) => url.pathname.startsWith("/event-types/"), - }), + page.waitForURL((url) => url.pathname.startsWith("/event-types/")), ]); }); diff --git a/apps/web/playwright/event-types.e2e.ts b/apps/web/playwright/event-types.e2e.ts index d3a12f1622..e2e5b1abca 100644 --- a/apps/web/playwright/event-types.e2e.ts +++ b/apps/web/playwright/event-types.e2e.ts @@ -94,10 +94,8 @@ test.describe("Event Types tests", () => { const $eventTypes = page.locator("[data-testid=event-types] > li a"); const firstEventTypeElement = $eventTypes.first(); await firstEventTypeElement.click(); - await page.waitForNavigation({ - url: (url) => { - return !!url.pathname.match(/\/event-types\/.+/); - }, + await page.waitForURL((url) => { + return !!url.pathname.match(/\/event-types\/.+/); }); await page.locator("[data-testid=update-eventtype]").click(); const toast = await page.waitForSelector("div[class*='data-testid-toast-success']"); @@ -108,10 +106,8 @@ test.describe("Event Types tests", () => { const $eventTypes = page.locator("[data-testid=event-types] > li a"); const firstEventTypeElement = $eventTypes.first(); await firstEventTypeElement.click(); - await page.waitForNavigation({ - url: (url) => { - return !!url.pathname.match(/\/event-types\/.+/); - }, + await page.waitForURL((url) => { + return !!url.pathname.match(/\/event-types\/.+/); }); const locationData = ["location 1", "location 2", "location 3"]; @@ -153,10 +149,8 @@ test.describe("Event Types tests", () => { // to change the test as little as possible. // eslint-disable-next-line playwright/no-conditional-in-test if (bookerVariant === "old-booker") { - await page.waitForNavigation({ - url(url) { - return url.pathname.endsWith("/book"); - }, + await page.waitForURL((url) => { + return url.pathname.endsWith("/book"); }); } diff --git a/apps/web/playwright/fixtures/users.ts b/apps/web/playwright/fixtures/users.ts index 7f14200ae6..1b04e4fd96 100644 --- a/apps/web/playwright/fixtures/users.ts +++ b/apps/web/playwright/fixtures/users.ts @@ -346,12 +346,12 @@ export async function getPaymentCredential(page: Page) { /** We start the Stripe flow */ await Promise.all([ - page.waitForNavigation({ url: "https://connect.stripe.com/oauth/v2/authorize?*" }), + page.waitForURL("https://connect.stripe.com/oauth/v2/authorize?*"), page.click('[data-testid="install-app-button"]'), ]); await Promise.all([ - page.waitForNavigation({ url: "/apps/installed/payment?hl=stripe" }), + page.waitForURL("/apps/installed/payment?hl=stripe"), /** We skip filling Stripe forms (testing mode only) */ page.click('[id="skip-account-app"]'), ]); diff --git a/apps/web/playwright/integrations-stripe.e2e.ts b/apps/web/playwright/integrations-stripe.e2e.ts index 389ebc477e..cc81109d86 100644 --- a/apps/web/playwright/integrations-stripe.e2e.ts +++ b/apps/web/playwright/integrations-stripe.e2e.ts @@ -49,7 +49,7 @@ test.describe("Stripe integration", () => { await page.fill('[name="name"]', "Stripe Stripeson"); await page.fill('[name="email"]', "test@example.com"); - await Promise.all([page.waitForNavigation({ url: "/payment/*" }), page.press('[name="email"]', "Enter")]); + await Promise.all([page.waitForURL("/payment/*"), page.press('[name="email"]', "Enter")]); const stripeFrame = page .frameLocator('iframe[src^="https://js.stripe.com/v3/elements-inner-card-"]') diff --git a/apps/web/playwright/lib/testUtils.ts b/apps/web/playwright/lib/testUtils.ts index 64005dd0f7..d4fc2cc3ce 100644 --- a/apps/web/playwright/lib/testUtils.ts +++ b/apps/web/playwright/lib/testUtils.ts @@ -114,10 +114,8 @@ async function bookEventOnThisPage(page: Page) { await bookTimeSlot(page); // Make sure we're navigated to the success page - await page.waitForNavigation({ - url(url) { - return url.pathname.startsWith("/booking"); - }, + await page.waitForURL((url) => { + return url.pathname.startsWith("/booking"); }); await expect(page.locator("[data-testid=success-page]")).toBeVisible(); } @@ -156,10 +154,8 @@ export const createNewEventType = async (page: Page, args: { eventTitle: string await page.fill("[name=length]", "10"); await page.click("[type=submit]"); - await page.waitForNavigation({ - url(url) { - return url.pathname !== "/event-types"; - }, + await page.waitForURL((url) => { + return url.pathname !== "/event-types"; }); }; diff --git a/apps/web/playwright/manage-booking-questions.e2e.ts b/apps/web/playwright/manage-booking-questions.e2e.ts index 203b1e4be4..fb5ebde5ad 100644 --- a/apps/web/playwright/manage-booking-questions.e2e.ts +++ b/apps/web/playwright/manage-booking-questions.e2e.ts @@ -362,8 +362,8 @@ async function rescheduleFromTheLinkOnPage({ await page.waitForLoadState(); await selectFirstAvailableTimeSlotNextMonth(page); if (bookerVariant === "old-booker") { - await page.waitForNavigation({ - url: (url) => url.pathname.endsWith("/book"), + await page.waitForURL((url) => { + return url.pathname.endsWith("/book"); }); } await page.click('[data-testid="confirm-reschedule-button"]'); @@ -380,8 +380,8 @@ async function openBookingFormInPreviewTab( await previewTabPage.waitForLoadState(); await selectFirstAvailableTimeSlotNextMonth(previewTabPage); if (bookerVariant === "old-booker") { - await previewTabPage.waitForNavigation({ - url: (url) => url.pathname.endsWith("/book"), + await previewTabPage.waitForURL((url) => { + return url.pathname.endsWith("/book"); }); } return previewTabPage; diff --git a/apps/web/playwright/reschedule.e2e.ts b/apps/web/playwright/reschedule.e2e.ts index de7c37d9f1..ee2d9bb840 100644 --- a/apps/web/playwright/reschedule.e2e.ts +++ b/apps/web/playwright/reschedule.e2e.ts @@ -149,10 +149,8 @@ testBothBookers.describe("Reschedule Tests", async () => { await page.locator('[data-testid="confirm-reschedule-button"]').click(); - await page.waitForNavigation({ - url(url) { - return url.pathname.indexOf("/payment") > -1; - }, + await page.waitForURL((url) => { + return url.pathname.indexOf("/payment") > -1; }); await expect(page).toHaveURL(/.*payment/); diff --git a/apps/web/playwright/webhook.e2e.ts b/apps/web/playwright/webhook.e2e.ts index 23ba60e2a1..533dc93418 100644 --- a/apps/web/playwright/webhook.e2e.ts +++ b/apps/web/playwright/webhook.e2e.ts @@ -24,9 +24,7 @@ test("add webhook & test that creating an event triggers a webhook call", async await Promise.all([ page.click("[type=submit]"), - page.waitForNavigation({ - url: (url) => url.pathname.endsWith("/settings/developer/webhooks"), - }), + page.waitForURL((url) => url.pathname.endsWith("/settings/developer/webhooks")), ]); // page contains the url 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 ee485e4206..3e47c36c98 100644 --- a/packages/app-store/routing-forms/playwright/tests/basic.e2e.ts +++ b/packages/app-store/routing-forms/playwright/tests/basic.e2e.ts @@ -130,9 +130,7 @@ test.describe("Routing Forms", () => { // Install app await page.goto(`/apps/routing-forms`); await page.click('[data-testid="install-app-button"]'); - await page.waitForNavigation({ - url: (url) => url.pathname === `/apps/routing-forms/forms`, - }); + await page.waitForURL((url) => url.pathname === `/apps/routing-forms/forms`); }); test.afterEach(async ({ users }) => { @@ -163,9 +161,7 @@ test.describe("Routing Forms", () => { // Install app await page.goto(`/apps/routing-forms`); await page.click('[data-testid="install-app-button"]'); - await page.waitForNavigation({ - url: (url) => url.pathname === `/apps/routing-forms/forms`, - }); + await page.waitForURL((url) => url.pathname === `/apps/routing-forms/forms`); return user; }; @@ -260,17 +256,13 @@ test.describe("Routing Forms", () => { // Router should be publicly accessible await users.logout(); page.goto(`/router?form=${routingForm.id}&Test field=event-routing`); - await page.waitForNavigation({ - url(url) { - return url.pathname.endsWith("/pro/30min"); - }, + await page.waitForURL((url) => { + return url.pathname.endsWith("/pro/30min"); }); page.goto(`/router?form=${routingForm.id}&Test field=external-redirect`); - await page.waitForNavigation({ - url(url) { - return url.hostname.includes("google.com"); - }, + await page.waitForURL((url) => { + return url.hostname.includes("google.com"); }); await page.goto(`/router?form=${routingForm.id}&Test field=custom-page`); @@ -352,19 +344,15 @@ async function fillSeededForm(page: Page, routingFormId: string) { await gotoRoutingLink(page, routingFormId); await page.fill('[data-testid="form-field"]', "event-routing"); page.click('button[type="submit"]'); - await page.waitForNavigation({ - url(url) { - return url.pathname.endsWith("/pro/30min"); - }, + await page.waitForURL((url) => { + return url.pathname.endsWith("/pro/30min"); }); await gotoRoutingLink(page, routingFormId); await page.fill('[data-testid="form-field"]', "external-redirect"); page.click('button[type="submit"]'); - await page.waitForNavigation({ - url(url) { - return url.hostname.includes("google.com"); - }, + await page.waitForURL((url) => { + return url.hostname.includes("google.com"); }); await gotoRoutingLink(page, routingFormId); diff --git a/packages/app-store/typeform/playwright/tests/basic.e2e.ts b/packages/app-store/typeform/playwright/tests/basic.e2e.ts index 8963529da0..7fb17c1fb0 100644 --- a/packages/app-store/typeform/playwright/tests/basic.e2e.ts +++ b/packages/app-store/typeform/playwright/tests/basic.e2e.ts @@ -19,14 +19,10 @@ const installApps = async (page: Page, users: Fixtures["users"]) => { await user.login(); await page.goto(`/apps/routing-forms`); await page.click('[data-testid="install-app-button"]'); - await page.waitForNavigation({ - url: (url) => url.pathname === `/apps/routing-forms/forms`, - }); + await page.waitForURL((url) => url.pathname === `/apps/routing-forms/forms`); await page.goto(`/apps/typeform`); await page.click('[data-testid="install-app-button"]'); - await page.waitForNavigation({ - url: (url) => url.pathname === `/apps/typeform/how-to-use`, - }); + await page.waitForURL((url) => url.pathname === `/apps/typeform/how-to-use`); }; test.describe("Typeform App", () => { diff --git a/packages/embeds/embed-core/playwright/lib/testUtils.ts b/packages/embeds/embed-core/playwright/lib/testUtils.ts index 9ac134a6ac..f3486ed1b4 100644 --- a/packages/embeds/embed-core/playwright/lib/testUtils.ts +++ b/packages/embeds/embed-core/playwright/lib/testUtils.ts @@ -93,10 +93,8 @@ async function selectFirstAvailableTimeSlotNextMonth(frame: Frame, page: Page) { export async function bookFirstEvent(username: string, frame: Frame, page: Page) { // Click first event type await frame.click('[data-testid="event-type-link"]'); - await frame.waitForNavigation({ - url(url) { - return !!url.pathname.match(new RegExp(`/${username}/.*$`)); - }, + await frame.waitForURL((url) => { + return !!url.pathname.match(new RegExp(`/${username}/.*$`)); }); // Let current month dates fully render. @@ -107,10 +105,8 @@ export async function bookFirstEvent(username: string, frame: Frame, page: Page) // expect(await page.screenshot()).toMatchSnapshot("availability-page-1.png"); const eventSlug = new URL(frame.url()).pathname; await selectFirstAvailableTimeSlotNextMonth(frame, page); - await frame.waitForNavigation({ - url(url) { - return url.pathname.includes(`/${username}/book`); - }, + await frame.waitForURL((url) => { + return url.pathname.includes(`/${username}/book`); }); // expect(await page.screenshot()).toMatchSnapshot("booking-page.png"); // --- fill form @@ -136,10 +132,8 @@ export async function bookFirstEvent(username: string, frame: Frame, page: Page) export async function rescheduleEvent(username, frame, page) { await selectFirstAvailableTimeSlotNextMonth(frame, page); - await frame.waitForNavigation({ - url(url) { - return url.pathname.includes(`/${username}/book`); - }, + await frame.waitForURL((url) => { + return url.pathname.includes(`/${username}/book`); }); // --- fill form await frame.press('[name="email"]', "Enter"); diff --git a/playwright.config.ts b/playwright.config.ts index efceb65d00..77f818ad84 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -12,7 +12,7 @@ const outputDir = path.join(__dirname, "test-results"); // So, if not in CI, keep the timers high, if the test is stuck somewhere and there is unnecessary wait developer can see in browser that it's stuck const DEFAULT_NAVIGATION_TIMEOUT = process.env.CI ? 15000 : 50000; -const DEFAULT_EXPECT_TIMEOUT = process.env.CI ? 10000 : 50000; +const DEFAULT_EXPECT_TIMEOUT = process.env.CI ? 15000 : 50000; // Test Timeout can hit due to slow expect, slow navigation. // So, it should me much higher than sum of expect and navigation timeouts as there can be many async expects and navigations in a single test