Fix: Show smsReminderNumber on booking success page (#8596)
This commit is contained in:
@@ -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 || "");
|
||||
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
|
||||
@@ -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")'),
|
||||
]);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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/")),
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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"]'),
|
||||
]);
|
||||
|
||||
@@ -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-"]')
|
||||
|
||||
@@ -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";
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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/);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user