fix: flaky e2e patterns (#16696)
Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
This commit is contained in:
1 parent
c1c4b1278b
commit
f52497f181
29 files changed
+262
-193
No files matched your search
@@ -1,4 +1,3 @@
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
import { sdkActionManager } from "@calcom/embed-core/embed-iframe";
|
||||
@@ -7,6 +6,8 @@ import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calco
|
||||
import type { RecurringEvent } from "@calcom/types/Calendar";
|
||||
import { Button, Icon, TextArea } from "@calcom/ui";
|
||||
|
||||
import { useRefreshData } from "@lib/hooks/useRefreshData";
|
||||
|
||||
type Props = {
|
||||
booking: {
|
||||
title?: string;
|
||||
@@ -38,7 +39,7 @@ type Props = {
|
||||
export default function CancelBooking(props: Props) {
|
||||
const [cancellationReason, setCancellationReason] = useState<string>("");
|
||||
const { t } = useLocale();
|
||||
const router = useRouter();
|
||||
const refreshData = useRefreshData();
|
||||
const { booking, allRemainingBookings, seatReferenceUid, bookingCancelledEventProps, currentUserEmail } =
|
||||
props;
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -120,7 +121,7 @@ export default function CancelBooking(props: Props) {
|
||||
...bookingCancelledEventProps,
|
||||
booking: bookingWithCancellationReason,
|
||||
});
|
||||
router.refresh();
|
||||
refreshData();
|
||||
} else {
|
||||
setLoading(false);
|
||||
setError(
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import { usePathname, useSearchParams } from "next/navigation";
|
||||
import { useMemo } from "react";
|
||||
|
||||
export function useAsPath() {
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
const asPath = useMemo(
|
||||
() => `${pathname}${searchParams ? `?${searchParams.toString()}` : ""}`,
|
||||
[pathname, searchParams]
|
||||
);
|
||||
return asPath;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
import { useAsPath } from "./useAsPath";
|
||||
|
||||
/** @see https://www.joshwcomeau.com/nextjs/refreshing-server-side-props/ */
|
||||
export function useRefreshData() {
|
||||
const router = useRouter();
|
||||
const asPath = useAsPath();
|
||||
const refreshData = () => {
|
||||
router.replace(asPath);
|
||||
};
|
||||
return refreshData;
|
||||
}
|
||||
@@ -33,9 +33,9 @@ test.describe("Availablity", () => {
|
||||
await page.getByTestId("add-override-submit-btn").click();
|
||||
await page.getByTestId("dialog-rejection").click();
|
||||
await expect(page.locator('[data-testid="date-overrides-list"] > li')).toHaveCount(1);
|
||||
await page.locator('[form="availability-form"][type="submit"]').click();
|
||||
const response = await page.waitForResponse("**/api/trpc/availability/schedule.update?batch=1");
|
||||
const json = await response.json();
|
||||
await submitAndWaitForResponse(page, "/api/trpc/availability/schedule.update?batch=1", {
|
||||
action: () => page.locator('[form="availability-form"][type="submit"]').click(),
|
||||
});
|
||||
const nextMonth = dayjs().add(1, "month").startOf("month");
|
||||
const troubleshooterURL = `/availability/troubleshoot?date=${nextMonth.format("YYYY-MM-DD")}`;
|
||||
await page.goto(troubleshooterURL);
|
||||
|
||||
@@ -13,7 +13,7 @@ import { entries } from "@calcom/prisma/zod-utils";
|
||||
import type { IntervalLimit } from "@calcom/types/Calendar";
|
||||
|
||||
import { test } from "./lib/fixtures";
|
||||
import { bookTimeSlot, createUserWithLimits } from "./lib/testUtils";
|
||||
import { bookTimeSlot, confirmReschedule, createUserWithLimits } from "./lib/testUtils";
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
test.afterEach(async ({ users }) => {
|
||||
@@ -163,7 +163,7 @@ test.describe("Booking limits", () => {
|
||||
await expect(page.locator('[name="name"]')).toBeDisabled();
|
||||
await expect(page.locator('[name="email"]')).toBeDisabled();
|
||||
|
||||
await page.locator('[data-testid="confirm-reschedule-button"]').click();
|
||||
await confirmReschedule(page);
|
||||
|
||||
await expect(page.locator("[data-testid=success-page]")).toBeVisible();
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
bookFirstEvent,
|
||||
bookOptinEvent,
|
||||
bookTimeSlot,
|
||||
confirmReschedule,
|
||||
selectFirstAvailableTimeSlotNextMonth,
|
||||
testEmail,
|
||||
testName,
|
||||
@@ -128,7 +129,7 @@ testBothFutureAndLegacyRoutes.describe("pro user", () => {
|
||||
});
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
|
||||
await page.locator('[data-testid="confirm-reschedule-button"]').click();
|
||||
await confirmReschedule(page);
|
||||
await page.waitForURL((url) => {
|
||||
return url.pathname.startsWith("/booking");
|
||||
});
|
||||
|
||||
@@ -7,9 +7,11 @@ import { BookingStatus } from "@calcom/prisma/enums";
|
||||
|
||||
import { test } from "./lib/fixtures";
|
||||
import {
|
||||
confirmReschedule,
|
||||
createNewSeatedEventType,
|
||||
selectFirstAvailableTimeSlotNextMonth,
|
||||
createUserWithSeatedEventAndAttendees,
|
||||
selectFirstAvailableTimeSlotNextMonth,
|
||||
submitAndWaitForResponse,
|
||||
} from "./lib/testUtils";
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
@@ -160,9 +162,9 @@ test.describe("Reschedule for booking with seats", () => {
|
||||
`/booking/${references[0].referenceUid}?cancel=true&seatReferenceUid=${references[0].referenceUid}`
|
||||
);
|
||||
|
||||
await page.locator('[data-testid="confirm_cancel"]').click();
|
||||
|
||||
await page.waitForResponse((res) => res.url().includes("api/cancel") && res.status() === 200);
|
||||
await submitAndWaitForResponse(page, "/api/cancel", {
|
||||
action: () => page.locator('[data-testid="confirm_cancel"]').click(),
|
||||
});
|
||||
|
||||
const oldBooking = await prisma.booking.findFirst({
|
||||
where: { uid: booking.uid },
|
||||
@@ -396,7 +398,7 @@ test.describe("Reschedule for booking with seats", () => {
|
||||
await expect(reasonElement).toBeVisible();
|
||||
|
||||
// expect to be redirected to reschedule page
|
||||
await page.locator('[data-testid="confirm-reschedule-button"]').click();
|
||||
await confirmReschedule(page);
|
||||
|
||||
// should wait for URL but that path starts with booking/
|
||||
await page.waitForURL(/\/booking\/.*/);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { expect } from "@playwright/test";
|
||||
|
||||
import { test } from "./lib/fixtures";
|
||||
import { submitAndWaitForResponse } from "./lib/testUtils";
|
||||
|
||||
test.afterEach(({ users }) => users.deleteAll());
|
||||
|
||||
@@ -18,11 +19,8 @@ test.describe("Change Password Test", () => {
|
||||
|
||||
const $newPasswordField = page.locator('[name="newPassword"]');
|
||||
$newPasswordField.fill(`${pro.username}Aa1111`);
|
||||
|
||||
await page.locator("text=Update").click();
|
||||
|
||||
const toast = await page.waitForSelector('[data-testid="toast-success"]');
|
||||
|
||||
expect(toast).toBeTruthy();
|
||||
await submitAndWaitForResponse(page, "/api/trpc/auth/changePassword?batch=1", {
|
||||
action: () => page.locator("text=Update").click(),
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -7,7 +7,7 @@ import { MembershipRole } from "@calcom/prisma/enums";
|
||||
import { moveUserToOrg } from "@lib/orgMigration";
|
||||
|
||||
import { test } from "./lib/fixtures";
|
||||
import { IS_STRIPE_ENABLED } from "./lib/testUtils";
|
||||
import { IS_STRIPE_ENABLED, submitAndWaitForResponse } from "./lib/testUtils";
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
|
||||
@@ -15,59 +15,45 @@ const IS_SELF_HOSTED = !(
|
||||
new URL(WEBAPP_URL).hostname.endsWith(".cal.dev") || !!new URL(WEBAPP_URL).hostname.endsWith(".cal.com")
|
||||
);
|
||||
|
||||
const TESTING_USERNAMES = [
|
||||
{
|
||||
username: "demousernamex",
|
||||
description: "",
|
||||
},
|
||||
{
|
||||
username: "demo.username",
|
||||
description: " to include periods(or dots)",
|
||||
},
|
||||
];
|
||||
|
||||
test.describe("Change username on settings", () => {
|
||||
test.afterEach(async ({ users }) => {
|
||||
await users.deleteAll();
|
||||
});
|
||||
|
||||
test("User can change username", async ({ page, users, prisma }) => {
|
||||
const user = await users.create();
|
||||
TESTING_USERNAMES.forEach((item) => {
|
||||
test(`User can change username${item.description}`, async ({ page, users, prisma }) => {
|
||||
const user = await users.create();
|
||||
await user.apiLogin();
|
||||
// Try to go homepage
|
||||
await page.goto("/settings/my-account/profile");
|
||||
// Change username from normal to normal
|
||||
const usernameInput = page.locator("[data-testid=username-input]");
|
||||
|
||||
await user.apiLogin();
|
||||
// Try to go homepage
|
||||
await page.goto("/settings/my-account/profile");
|
||||
// Change username from normal to normal
|
||||
const usernameInput = page.locator("[data-testid=username-input]");
|
||||
await usernameInput.fill(item.username);
|
||||
await page.click("[data-testid=update-username-btn]");
|
||||
await submitAndWaitForResponse(page, "/api/trpc/viewer/updateProfile?batch=1", {
|
||||
action: () => page.click("[data-testid=save-username]"),
|
||||
});
|
||||
|
||||
await usernameInput.fill("demousernamex");
|
||||
await page.click("[data-testid=update-username-btn]");
|
||||
await Promise.all([
|
||||
page.click("[data-testid=save-username]"),
|
||||
page.getByTestId("toast-success").waitFor(),
|
||||
]);
|
||||
const newUpdatedUser = await prisma.user.findUniqueOrThrow({
|
||||
where: {
|
||||
id: user.id,
|
||||
},
|
||||
});
|
||||
|
||||
const newUpdatedUser = await prisma.user.findUniqueOrThrow({
|
||||
where: {
|
||||
id: user.id,
|
||||
},
|
||||
expect(newUpdatedUser.username).toBe(item.username);
|
||||
});
|
||||
|
||||
expect(newUpdatedUser.username).toBe("demousernamex");
|
||||
});
|
||||
|
||||
test("User can change username to include periods(or dots)", async ({ page, users, prisma }) => {
|
||||
const user = await users.create();
|
||||
|
||||
await user.apiLogin();
|
||||
// Try to go homepage
|
||||
await page.goto("/settings/my-account/profile");
|
||||
// Change username from normal to normal
|
||||
const usernameInput = page.locator("[data-testid=username-input]");
|
||||
// User can change username to include dots(or periods)
|
||||
await usernameInput.fill("demo.username");
|
||||
await page.click("[data-testid=update-username-btn]");
|
||||
await Promise.all([
|
||||
page.click("[data-testid=save-username]"),
|
||||
page.getByTestId("toast-success").waitFor(),
|
||||
]);
|
||||
|
||||
const updatedUser = await prisma.user.findUniqueOrThrow({
|
||||
where: {
|
||||
id: user.id,
|
||||
},
|
||||
});
|
||||
|
||||
expect(updatedUser.username).toBe("demo.username");
|
||||
});
|
||||
|
||||
test("User can update to PREMIUM username", async ({ page, users }, testInfo) => {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { MembershipRole } from "@calcom/prisma/client";
|
||||
import { test } from "./lib/fixtures";
|
||||
import {
|
||||
bookTimeSlot,
|
||||
confirmReschedule,
|
||||
doOnOrgDomain,
|
||||
selectFirstAvailableTimeSlotNextMonth,
|
||||
selectSecondAvailableTimeSlotNextMonth,
|
||||
@@ -42,7 +43,7 @@ test("dynamic booking", async ({ page, users }) => {
|
||||
await selectSecondAvailableTimeSlotNextMonth(page);
|
||||
|
||||
// No need to fill fields since they should be already filled
|
||||
await page.locator('[data-testid="confirm-reschedule-button"]').click();
|
||||
await confirmReschedule(page);
|
||||
await page.waitForURL((url) => {
|
||||
return url.pathname.startsWith("/booking");
|
||||
});
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
gotoFirstEventType,
|
||||
saveEventType,
|
||||
selectFirstAvailableTimeSlotNextMonth,
|
||||
submitAndWaitForResponse,
|
||||
} from "./lib/testUtils";
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
@@ -130,9 +131,9 @@ testBothFutureAndLegacyRoutes.describe("Event Types tests", () => {
|
||||
await page.waitForURL((url) => {
|
||||
return !!url.pathname.match(/\/event-types\/.+/);
|
||||
});
|
||||
await page.locator("[data-testid=update-eventtype]").click();
|
||||
const toast = await page.waitForSelector('[data-testid="toast-success"]');
|
||||
expect(toast).toBeTruthy();
|
||||
await submitAndWaitForResponse(page, "/api/trpc/eventTypes/update?batch=1", {
|
||||
action: () => page.locator("[data-testid=update-eventtype]").click(),
|
||||
});
|
||||
});
|
||||
|
||||
test("can add multiple organizer address", async ({ page }) => {
|
||||
@@ -153,7 +154,9 @@ testBothFutureAndLegacyRoutes.describe("Event Types tests", () => {
|
||||
await page.locator("[data-testid=add-location]").click();
|
||||
await fillLocation(page, locationData[2], 2);
|
||||
|
||||
await page.locator("[data-testid=update-eventtype]").click();
|
||||
await submitAndWaitForResponse(page, "/api/trpc/eventTypes/update?batch=1", {
|
||||
action: () => page.locator("[data-testid=update-eventtype]").click(),
|
||||
});
|
||||
|
||||
await page.goto("/event-types");
|
||||
|
||||
@@ -224,7 +227,6 @@ testBothFutureAndLegacyRoutes.describe("Event Types tests", () => {
|
||||
await page.locator(`text="Cal Video (Global)"`).click();
|
||||
|
||||
await saveEventType(page);
|
||||
await page.getByTestId("toast-success").waitFor();
|
||||
await gotoBookingPage(page);
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
|
||||
@@ -246,7 +248,6 @@ testBothFutureAndLegacyRoutes.describe("Event Types tests", () => {
|
||||
await page.locator(`input[name="${locationInputName}"]`).fill(testUrl);
|
||||
|
||||
await saveEventType(page);
|
||||
await page.getByTestId("toast-success").waitFor();
|
||||
await gotoBookingPage(page);
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
|
||||
@@ -298,7 +299,9 @@ testBothFutureAndLegacyRoutes.describe("Event Types tests", () => {
|
||||
const locationAddress = "New Delhi";
|
||||
|
||||
await fillLocation(page, locationAddress, 0, false);
|
||||
await page.locator("[data-testid=update-eventtype]").click();
|
||||
await submitAndWaitForResponse(page, "/api/trpc/eventTypes/update?batch=1", {
|
||||
action: () => page.locator("[data-testid=update-eventtype]").click(),
|
||||
});
|
||||
|
||||
await page.goto("/event-types");
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Page } from "@playwright/test";
|
||||
import type { Page, WorkerInfo } from "@playwright/test";
|
||||
import type { Booking, Prisma } from "@prisma/client";
|
||||
import short from "short-uuid";
|
||||
import { v5 as uuidv5 } from "uuid";
|
||||
@@ -14,7 +14,7 @@ type BookingFixture = ReturnType<typeof createBookingFixture>;
|
||||
const dayjs = (...args: Parameters<typeof _dayjs>) => _dayjs(...args).tz("Europe/London");
|
||||
|
||||
// creates a user fixture instance and stores the collection
|
||||
export const createBookingsFixture = (page: Page) => {
|
||||
export const createBookingsFixture = (page: Page, workerInfo: WorkerInfo) => {
|
||||
const store = { bookings: [], page } as { bookings: BookingFixture[]; page: typeof page };
|
||||
return {
|
||||
create: async (
|
||||
@@ -40,7 +40,9 @@ export const createBookingsFixture = (page: Page) => {
|
||||
endDateParam?: Date
|
||||
) => {
|
||||
const startDate = startDateParam || dayjs().add(1, "day").toDate();
|
||||
const seed = `${username}:${dayjs(startDate).utc().format()}:${new Date().getTime()}`;
|
||||
const seed = `${username}:${dayjs(startDate).utc().format()}:${new Date().getTime()}:${
|
||||
workerInfo.workerIndex
|
||||
}`;
|
||||
const uid = translator.fromUUID(uuidv5(seed, uuidv5.URL));
|
||||
const booking = await prisma.booking.create({
|
||||
data: {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { expect, type Page } from "@playwright/test";
|
||||
|
||||
import type { MembershipRole } from "@calcom/prisma/enums";
|
||||
|
||||
import { localize } from "../lib/testUtils";
|
||||
import { localize, submitAndWaitForResponse } from "../lib/testUtils";
|
||||
import type { createUsersFixture } from "./users";
|
||||
|
||||
export const scheduleSuccessfullyText = "This meeting is scheduled";
|
||||
@@ -40,9 +40,9 @@ export function createBookingPageFixture(page: Page) {
|
||||
await page.goto("/event-types");
|
||||
},
|
||||
updateEventType: async () => {
|
||||
await page.getByTestId("update-eventtype").click();
|
||||
const toast = await page.waitForSelector('[data-testid="toast-success"]');
|
||||
expect(toast).toBeTruthy();
|
||||
await submitAndWaitForResponse(page, "/api/trpc/eventTypes/update?batch=1", {
|
||||
action: () => page.locator("[data-testid=update-eventtype]").click(),
|
||||
});
|
||||
},
|
||||
previewEventType: async () => {
|
||||
const eventtypePromise = page.waitForEvent("popup");
|
||||
|
||||
@@ -1014,10 +1014,11 @@ export async function login(
|
||||
await emailLocator.fill(user.email ?? `${user.username}@example.com`);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
await passwordLocator.fill(user.password ?? user.username!);
|
||||
await signInLocator.click();
|
||||
|
||||
// waiting for specific login request to resolve
|
||||
await page.waitForResponse(/\/api\/auth\/callback\/credentials/);
|
||||
const responsePromise = page.waitForResponse(/\/api\/auth\/callback\/credentials/);
|
||||
await signInLocator.click();
|
||||
await responsePromise;
|
||||
}
|
||||
|
||||
export async function apiLogin(
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { expect } from "@playwright/test";
|
||||
|
||||
import { test } from "./lib/fixtures";
|
||||
import { bookTimeSlot, selectFirstAvailableTimeSlotNextMonth } from "./lib/testUtils";
|
||||
import {
|
||||
bookTimeSlot,
|
||||
selectFirstAvailableTimeSlotNextMonth,
|
||||
submitAndWaitForResponse,
|
||||
} from "./lib/testUtils";
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
|
||||
@@ -55,10 +59,9 @@ test.describe("hash my url", () => {
|
||||
await page.getByTestId("vertical-tab-event_setup_tab_title").click();
|
||||
await page.locator("[data-testid=event-title]").first().fill("somethingrandom");
|
||||
await page.locator("[data-testid=event-slug]").first().fill("somethingrandom");
|
||||
const submitPromise = page.waitForResponse("/api/trpc/eventTypes/update?batch=1");
|
||||
await page.locator("[data-testid=update-eventtype]").click();
|
||||
const response = await submitPromise;
|
||||
expect(response.status()).toBe(200);
|
||||
await submitAndWaitForResponse(page, "/api/trpc/eventTypes/update?batch=1", {
|
||||
action: () => page.locator("[data-testid=update-eventtype]").click(),
|
||||
});
|
||||
await page.locator(".primary-navigation >> text=Advanced").click();
|
||||
const $url2 = await page.locator('//*[@data-testid="generated-hash-url"]').inputValue();
|
||||
expect($url2.includes("somethingrandom")).toBeTruthy();
|
||||
|
||||
@@ -7,7 +7,7 @@ import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
import { test, todo } from "./lib/fixtures";
|
||||
import type { Fixtures } from "./lib/fixtures";
|
||||
import { IS_STRIPE_ENABLED, selectFirstAvailableTimeSlotNextMonth } from "./lib/testUtils";
|
||||
import { confirmReschedule, IS_STRIPE_ENABLED, selectFirstAvailableTimeSlotNextMonth } from "./lib/testUtils";
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
test.afterEach(({ users }) => users.deleteAll());
|
||||
@@ -438,7 +438,7 @@ test.describe("Stripe integration with the new app install flow skip false", ()
|
||||
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
|
||||
await page.click('[data-testid="confirm-reschedule-button"]');
|
||||
await confirmReschedule(page);
|
||||
|
||||
await expect(page.getByText("This meeting is scheduled")).toBeVisible();
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ import { v4 as uuidv4 } from "uuid";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
|
||||
import { test, todo } from "./lib/fixtures";
|
||||
import { submitAndWaitForResponse } from "./lib/testUtils";
|
||||
|
||||
declare let global: {
|
||||
E2E_EMAILS?: ({ text: string } | Record<string, unknown>)[];
|
||||
@@ -130,8 +131,10 @@ async function bookEvent(page: Page, calLink: string) {
|
||||
// --- fill form
|
||||
await page.fill('[name="name"]', "Integration User");
|
||||
await page.fill('[name="email"]', "integration-user@example.com");
|
||||
await page.press('[name="email"]', "Enter");
|
||||
const response = await page.waitForResponse("**/api/book/event");
|
||||
|
||||
const response = await submitAndWaitForResponse(page, "**/api/book/event", {
|
||||
action: () => page.press('[name="email"]', "Enter"),
|
||||
});
|
||||
const responseObj = await response.json();
|
||||
const bookingId = responseObj.uid;
|
||||
await page.waitForSelector("[data-testid=success-page]");
|
||||
|
||||
@@ -68,8 +68,8 @@ export const test = base.extend<Fixtures>({
|
||||
const usersFixture = createUsersFixture(page, emails, workerInfo);
|
||||
await use(usersFixture);
|
||||
},
|
||||
bookings: async ({ page }, use) => {
|
||||
const bookingsFixture = createBookingsFixture(page);
|
||||
bookings: async ({ page }, use, workerInfo) => {
|
||||
const bookingsFixture = createBookingsFixture(page, workerInfo);
|
||||
await use(bookingsFixture);
|
||||
},
|
||||
payments: async ({ page }, use) => {
|
||||
|
||||
@@ -218,9 +218,9 @@ export async function installAppleCalendar(page: Page) {
|
||||
}
|
||||
|
||||
export async function getInviteLink(page: Page) {
|
||||
const response = await page.waitForResponse("/api/trpc/teams/createInvite?batch=1");
|
||||
expect(response.status()).toBe(200);
|
||||
const json = await response.json();
|
||||
const json = await submitAndWaitForResponse(page, "/api/trpc/teams/createInvite?batch=1", {
|
||||
action: () => page.locator(`[data-testid="copy-invite-link-button"]`).click(),
|
||||
});
|
||||
return json[0].result.data.json.inviteLink as string;
|
||||
}
|
||||
|
||||
@@ -428,10 +428,15 @@ export async function gotoBookingPage(page: Page) {
|
||||
}
|
||||
|
||||
export async function saveEventType(page: Page) {
|
||||
await page.locator("[data-testid=update-eventtype]").click();
|
||||
await submitAndWaitForResponse(page, "/api/trpc/eventTypes/update?batch=1", {
|
||||
action: () => page.locator("[data-testid=update-eventtype]").click(),
|
||||
});
|
||||
}
|
||||
|
||||
/** Fastest way so far to test for saving changes and form submissions */
|
||||
/**
|
||||
* Fastest way so far to test for saving changes and form submissions
|
||||
* @see https://playwright.dev/docs/api/class-page#page-wait-for-response
|
||||
*/
|
||||
export async function submitAndWaitForResponse(
|
||||
page: Page,
|
||||
url: string,
|
||||
@@ -441,4 +446,11 @@ export async function submitAndWaitForResponse(
|
||||
await action();
|
||||
const response = await submitPromise;
|
||||
expect(response.status()).toBe(expectedStatusCode);
|
||||
return response.json();
|
||||
}
|
||||
|
||||
export async function confirmReschedule(page: Page, url = "/api/book/event") {
|
||||
await submitAndWaitForResponse(page, url, {
|
||||
action: () => page.locator('[data-testid="confirm-reschedule-button"]').click(),
|
||||
});
|
||||
}
|
||||
@@ -10,8 +10,12 @@ import { WebhookTriggerEvents } from "@calcom/prisma/enums";
|
||||
import type { CalendarEvent } from "@calcom/types/Calendar";
|
||||
|
||||
import { test } from "./lib/fixtures";
|
||||
import { createNewEventType } from "./lib/testUtils";
|
||||
import { createHttpServer, selectFirstAvailableTimeSlotNextMonth } from "./lib/testUtils";
|
||||
import {
|
||||
createHttpServer,
|
||||
createNewEventType,
|
||||
selectFirstAvailableTimeSlotNextMonth,
|
||||
submitAndWaitForResponse,
|
||||
} from "./lib/testUtils";
|
||||
|
||||
function getLabelLocator(field: Locator) {
|
||||
// There are 2 labels right now. Will be one in future. The second one is hidden
|
||||
@@ -655,7 +659,7 @@ async function rescheduleFromTheLinkOnPage({ page }: { page: Page }) {
|
||||
await page.locator('[data-testid="reschedule-link"]').click();
|
||||
await page.waitForLoadState();
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
await page.click('[data-testid="confirm-reschedule-button"]');
|
||||
await page.locator('[data-testid="confirm-reschedule-button"]').click();
|
||||
}
|
||||
|
||||
async function openBookingFormInPreviewTab(context: PlaywrightTestArgs["context"], page: Page) {
|
||||
@@ -668,7 +672,9 @@ async function openBookingFormInPreviewTab(context: PlaywrightTestArgs["context"
|
||||
}
|
||||
|
||||
async function saveEventType(page: Page) {
|
||||
await page.locator("[data-testid=update-eventtype]").click();
|
||||
await submitAndWaitForResponse(page, "/api/trpc/eventTypes/update?batch=1", {
|
||||
action: () => page.locator("[data-testid=update-eventtype]").click(),
|
||||
});
|
||||
}
|
||||
|
||||
async function addWebhook(
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
bookTimeSlot,
|
||||
doOnOrgDomain,
|
||||
selectFirstAvailableTimeSlotNextMonth,
|
||||
submitAndWaitForResponse,
|
||||
testName,
|
||||
} from "../lib/testUtils";
|
||||
import { expectExistingUserToBeInvitedToOrganization } from "../team/expects";
|
||||
@@ -660,11 +661,9 @@ const markPhoneNumberAsRequiredAndEmailAsOptional = async (page: Page, eventId:
|
||||
const emailRequiredFiled = await page.locator('[data-testid="field-required"]');
|
||||
await emailRequiredFiled.locator("> :nth-child(2)").click();
|
||||
await page.getByTestId("field-add-save").click();
|
||||
|
||||
const submitPromise = page.waitForResponse("/api/trpc/eventTypes/update?batch=1");
|
||||
await page.locator("[data-testid=update-eventtype]").click();
|
||||
const response = await submitPromise;
|
||||
expect(response.status()).toBe(200);
|
||||
await submitAndWaitForResponse(page, "/api/trpc/eventTypes/update?batch=1", {
|
||||
action: () => page.locator("[data-testid=update-eventtype]").click(),
|
||||
});
|
||||
};
|
||||
|
||||
const markPhoneNumberAsRequiredField = async (page: Page, eventId: number) => {
|
||||
@@ -675,9 +674,7 @@ const markPhoneNumberAsRequiredField = async (page: Page, eventId: number) => {
|
||||
const phoneRequiredFiled = await page.locator('[data-testid="field-required"]');
|
||||
await phoneRequiredFiled.locator("> :nth-child(1)").click();
|
||||
await page.getByTestId("field-add-save").click();
|
||||
|
||||
const submitPromise = page.waitForResponse("/api/trpc/eventTypes/update?batch=1");
|
||||
await page.locator("[data-testid=update-eventtype]").click();
|
||||
const response = await submitPromise;
|
||||
expect(response.status()).toBe(200);
|
||||
await submitAndWaitForResponse(page, "/api/trpc/eventTypes/update?batch=1", {
|
||||
action: () => page.locator("[data-testid=update-eventtype]").click(),
|
||||
});
|
||||
};
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { Page } from "@playwright/test";
|
||||
import type { createUsersFixture } from "playwright/fixtures/users";
|
||||
|
||||
import { submitAndWaitForResponse } from "../../lib/testUtils";
|
||||
|
||||
export const inviteUserToOrganization = async ({
|
||||
page,
|
||||
organizationId,
|
||||
@@ -35,19 +37,21 @@ export const inviteExistingUserToOrganization = async ({
|
||||
usersFixture: ReturnType<typeof createUsersFixture>;
|
||||
}) => {
|
||||
await page.goto("/settings/organizations/members");
|
||||
|
||||
await inviteAnEmail(page, user.email);
|
||||
await page.waitForSelector('[data-testid="toast-success"]');
|
||||
return { invitedUserEmail: user.email };
|
||||
};
|
||||
|
||||
export async function acceptTeamOrOrgInvite(page: Page) {
|
||||
await page.goto("/settings/teams");
|
||||
await page.click('[data-testid^="accept-invitation"]');
|
||||
await submitAndWaitForResponse(page, "/api/trpc/teams/acceptOrLeave?batch=1", {
|
||||
action: () => page.click('[data-testid^="accept-invitation"]'),
|
||||
});
|
||||
}
|
||||
|
||||
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 submitAndWaitForResponse(page, "/api/trpc/teams/inviteMember?batch=1", {
|
||||
action: () => page.locator('button:text("Send invite")').click(),
|
||||
});
|
||||
}
|
||||
@@ -558,7 +558,6 @@ function assertInviteLink(inviteLink: string | null | undefined): asserts invite
|
||||
|
||||
async function copyInviteLink(page: Page) {
|
||||
await page.locator('button:text("Add")').click();
|
||||
await page.locator(`[data-testid="copy-invite-link-button"]`).click();
|
||||
const inviteLink = await getInviteLink(page);
|
||||
return inviteLink;
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import type { PrismaClient } from "@calcom/prisma";
|
||||
|
||||
import type { createEmailsFixture } from "./fixtures/emails";
|
||||
import { test } from "./lib/fixtures";
|
||||
import { getEmailsReceivedByUser } from "./lib/testUtils";
|
||||
import { getEmailsReceivedByUser, submitAndWaitForResponse } from "./lib/testUtils";
|
||||
import { expectInvitationEmailToBeReceived } from "./team/expects";
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
@@ -62,13 +62,9 @@ test.describe("Update Profile", () => {
|
||||
|
||||
await page.getByTestId("password").fill(user?.username ?? "Nameless User");
|
||||
|
||||
await page.getByTestId("profile-update-email-submit-button").click();
|
||||
|
||||
const toastLocator = await page.getByTestId("toast-success");
|
||||
|
||||
const textContent = await toastLocator.textContent();
|
||||
|
||||
expect(textContent).toContain(email);
|
||||
await submitAndWaitForResponse(page, "/api/trpc/viewer/updateProfile?batch=1", {
|
||||
action: () => page.getByTestId("profile-update-email-submit-button").click(),
|
||||
});
|
||||
|
||||
// Instead of dealing with emails in e2e lets just get the token and navigate to it
|
||||
const verificationToken = await prisma.verificationToken.findFirst({
|
||||
|
||||
@@ -6,13 +6,16 @@ import { MembershipRole } from "@calcom/prisma/client";
|
||||
import { BookingStatus } from "@calcom/prisma/enums";
|
||||
import { bookingMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
import { apiLogin } from "./fixtures/users";
|
||||
import { test } from "./lib/fixtures";
|
||||
import {
|
||||
selectFirstAvailableTimeSlotNextMonth,
|
||||
bookTimeSlot,
|
||||
confirmReschedule,
|
||||
doOnOrgDomain,
|
||||
goToUrlWithErrorHandling,
|
||||
IS_STRIPE_ENABLED,
|
||||
selectFirstAvailableTimeSlotNextMonth,
|
||||
submitAndWaitForResponse,
|
||||
} from "./lib/testUtils";
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
@@ -93,9 +96,7 @@ test.describe("Reschedule Tests", async () => {
|
||||
|
||||
await expect(page.locator('[name="name"]')).toBeDisabled();
|
||||
await expect(page.locator('[name="email"]')).toBeDisabled();
|
||||
|
||||
await page.locator('[data-testid="confirm-reschedule-button"]').click();
|
||||
|
||||
await confirmReschedule(page);
|
||||
await expect(page.locator("[data-testid=success-page]")).toBeVisible();
|
||||
|
||||
const newBooking = await prisma.booking.findFirstOrThrow({ where: { fromReschedule: booking.uid } });
|
||||
@@ -147,7 +148,7 @@ test.describe("Reschedule Tests", async () => {
|
||||
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
|
||||
await page.locator('[data-testid="confirm-reschedule-button"]').click();
|
||||
await confirmReschedule(page);
|
||||
|
||||
await page.waitForURL((url) => {
|
||||
return url.pathname.indexOf("/payment") > -1;
|
||||
@@ -177,7 +178,7 @@ test.describe("Reschedule Tests", async () => {
|
||||
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
|
||||
await page.locator('[data-testid="confirm-reschedule-button"]').click();
|
||||
await confirmReschedule(page);
|
||||
|
||||
await expect(page).toHaveURL(/.*booking/);
|
||||
});
|
||||
@@ -194,13 +195,13 @@ test.describe("Reschedule Tests", async () => {
|
||||
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
|
||||
await page.locator('[data-testid="confirm-reschedule-button"]').click();
|
||||
await confirmReschedule(page);
|
||||
|
||||
await expect(page).toHaveURL(/.*booking/);
|
||||
|
||||
const newBooking = await prisma.booking.findFirst({ where: { fromReschedule: booking?.uid } });
|
||||
const newBooking = await prisma.booking.findFirstOrThrow({ where: { fromReschedule: booking?.uid } });
|
||||
expect(newBooking).not.toBeNull();
|
||||
expect(newBooking?.status).toBe(BookingStatus.PENDING);
|
||||
expect(newBooking.status).toBe(BookingStatus.PENDING);
|
||||
});
|
||||
|
||||
test("Opt in event should be ACCEPTED when rescheduled by OWNER", async ({ page, users, bookings }) => {
|
||||
@@ -216,13 +217,13 @@ test.describe("Reschedule Tests", async () => {
|
||||
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
|
||||
await page.locator('[data-testid="confirm-reschedule-button"]').click();
|
||||
await confirmReschedule(page);
|
||||
|
||||
await expect(page).toHaveURL(/.*booking/);
|
||||
|
||||
const newBooking = await prisma.booking.findFirst({ where: { fromReschedule: booking?.uid } });
|
||||
const newBooking = await prisma.booking.findFirstOrThrow({ where: { fromReschedule: booking?.uid } });
|
||||
expect(newBooking).not.toBeNull();
|
||||
expect(newBooking?.status).toBe(BookingStatus.ACCEPTED);
|
||||
expect(newBooking.status).toBe(BookingStatus.ACCEPTED);
|
||||
});
|
||||
|
||||
test("Attendee should be able to reschedule a booking", async ({ page, users, bookings }) => {
|
||||
@@ -235,13 +236,13 @@ test.describe("Reschedule Tests", async () => {
|
||||
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
|
||||
await page.locator('[data-testid="confirm-reschedule-button"]').click();
|
||||
await confirmReschedule(page);
|
||||
|
||||
await expect(page).toHaveURL(/.*booking/);
|
||||
|
||||
const newBooking = await prisma.booking.findFirst({ where: { fromReschedule: booking?.uid } });
|
||||
const newBooking = await prisma.booking.findFirstOrThrow({ where: { fromReschedule: booking?.uid } });
|
||||
expect(newBooking).not.toBeNull();
|
||||
expect(newBooking?.status).toBe(BookingStatus.ACCEPTED);
|
||||
expect(newBooking.status).toBe(BookingStatus.ACCEPTED);
|
||||
});
|
||||
|
||||
test("Should be able to book slot that overlaps with original rescheduled booking", async ({
|
||||
@@ -270,26 +271,31 @@ test.describe("Reschedule Tests", async () => {
|
||||
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
|
||||
await page.locator('[data-testid="confirm-reschedule-button"]').click();
|
||||
await confirmReschedule(page);
|
||||
await expect(page).toHaveURL(/.*booking/);
|
||||
});
|
||||
|
||||
test("Should load Valid Cal video url after rescheduling Opt in events", async ({
|
||||
page,
|
||||
users,
|
||||
bookings,
|
||||
browser,
|
||||
}) => {
|
||||
// eslint-disable-next-line playwright/no-skipped-test
|
||||
test.skip(!process.env.DAILY_API_KEY, "DAILY_API_KEY is needed for this test");
|
||||
const user = await users.create();
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const eventType = user.eventTypes.find((e) => e.slug === "opt-in")!;
|
||||
|
||||
const confirmBooking = async (bookingId: number) => {
|
||||
await user.apiLogin();
|
||||
await page.goto("/bookings/upcoming");
|
||||
const elem = await page.locator(`[data-bookingid="${bookingId}"][data-testid="confirm"]`);
|
||||
await elem.click();
|
||||
await page.getByTestId("toast-success").waitFor();
|
||||
await user.logout();
|
||||
const authedContext = await browser.newContext();
|
||||
const authedPage = await authedContext.newPage();
|
||||
const userSnapshot = await user.self();
|
||||
await apiLogin({ ...userSnapshot, password: userSnapshot.username }, authedPage);
|
||||
await authedPage.goto("/bookings/upcoming");
|
||||
await submitAndWaitForResponse(authedPage, "/api/trpc/bookings/confirm?batch=1", {
|
||||
action: () => authedPage.locator(`[data-bookingid="${bookingId}"][data-testid="confirm"]`).click(),
|
||||
});
|
||||
await authedContext.close();
|
||||
};
|
||||
|
||||
await page.goto(`/${user.username}/${eventType.slug}`);
|
||||
@@ -301,38 +307,34 @@ test.describe("Reschedule Tests", async () => {
|
||||
const pathSegments = pageUrl.pathname.split("/");
|
||||
const bookingUID = pathSegments[pathSegments.length - 1];
|
||||
|
||||
const currentBooking = await prisma.booking.findFirst({ where: { uid: bookingUID } });
|
||||
const currentBooking = await prisma.booking.findFirstOrThrow({ where: { uid: bookingUID } });
|
||||
expect(currentBooking).not.toBeUndefined();
|
||||
await confirmBooking(currentBooking.id);
|
||||
|
||||
await page.goto(`/reschedule/${currentBooking.uid}`);
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
|
||||
await confirmReschedule(page);
|
||||
await expect(page).toHaveURL(/.*booking/);
|
||||
|
||||
const newBooking = await prisma.booking.findFirstOrThrow({
|
||||
where: { fromReschedule: currentBooking.uid },
|
||||
});
|
||||
expect(newBooking).not.toBeUndefined();
|
||||
expect(newBooking.status).toBe(BookingStatus.PENDING);
|
||||
await confirmBooking(newBooking.id);
|
||||
|
||||
const booking = await prisma.booking.findFirstOrThrow({ where: { id: newBooking.id } });
|
||||
expect(booking).not.toBeUndefined();
|
||||
expect(booking.status).toBe(BookingStatus.ACCEPTED);
|
||||
|
||||
const locationVideoCallUrl = bookingMetadataSchema.parse(booking.metadata || {})?.videoCallUrl;
|
||||
// FIXME: This should be consistent or skip the whole test
|
||||
// eslint-disable-next-line playwright/no-conditional-in-test
|
||||
if (currentBooking) {
|
||||
await confirmBooking(currentBooking.id);
|
||||
|
||||
await page.goto(`/reschedule/${currentBooking.uid}`);
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
|
||||
await page.locator('[data-testid="confirm-reschedule-button"]').click();
|
||||
await expect(page).toHaveURL(/.*booking/);
|
||||
|
||||
const newBooking = await prisma.booking.findFirst({ where: { fromReschedule: currentBooking.uid } });
|
||||
expect(newBooking).not.toBeUndefined();
|
||||
expect(newBooking?.status).toBe(BookingStatus.PENDING);
|
||||
// eslint-disable-next-line playwright/no-conditional-in-test
|
||||
if (newBooking) {
|
||||
await confirmBooking(newBooking?.id);
|
||||
|
||||
const booking = await prisma.booking.findFirst({ where: { id: newBooking.id } });
|
||||
expect(booking).not.toBeUndefined();
|
||||
expect(booking?.status).toBe(BookingStatus.ACCEPTED);
|
||||
const locationVideoCallUrl = bookingMetadataSchema.parse(booking?.metadata || {})?.videoCallUrl;
|
||||
expect(locationVideoCallUrl).not.toBeUndefined();
|
||||
|
||||
// eslint-disable-next-line playwright/no-conditional-in-test
|
||||
if (booking && locationVideoCallUrl) {
|
||||
await page.goto(locationVideoCallUrl);
|
||||
await expect(page.frameLocator("iFrame").locator('text="Continue"')).toBeVisible();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!locationVideoCallUrl) return;
|
||||
expect(locationVideoCallUrl).not.toBeUndefined();
|
||||
await page.goto(locationVideoCallUrl);
|
||||
await expect(page.frameLocator("iFrame").locator('text="Continue"')).toBeVisible();
|
||||
});
|
||||
|
||||
test("Should be able to a dynamic group booking", async () => {
|
||||
@@ -409,7 +411,10 @@ test.describe("Reschedule Tests", async () => {
|
||||
|
||||
async function expectSuccessfulReschedule() {
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
await page.locator("[data-testid=confirm-reschedule-button]").click();
|
||||
const { protocol, host } = new URL(page.url());
|
||||
// Needed since we we're expecting a non-org URL, causing timeouts.
|
||||
const url = getNonOrgUrlFromOrgUrl(`${protocol}//${host}/api/book/event`);
|
||||
await confirmReschedule(page, url);
|
||||
await expect(page.locator("[data-testid=success-page]")).toBeVisible();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@ import { expect } from "@playwright/test";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
|
||||
import { test } from "../lib/fixtures";
|
||||
import { localize, getInviteLink } from "../lib/testUtils";
|
||||
import { getInviteLink, localize } from "../lib/testUtils";
|
||||
import { expectInvitationEmailToBeReceived } from "./expects";
|
||||
|
||||
test.describe.configure({ mode: "parallel" });
|
||||
@@ -75,7 +75,6 @@ test.describe("Team", () => {
|
||||
password: "P4ssw0rd!",
|
||||
});
|
||||
await page.locator(`button:text("${t("add")}")`).click();
|
||||
await page.locator(`[data-testid="copy-invite-link-button"]`).click();
|
||||
const inviteLink = await getInviteLink(page);
|
||||
|
||||
const context = await browser.newContext();
|
||||
|
||||
@@ -8,6 +8,7 @@ import { test, todo } from "./lib/fixtures";
|
||||
import { testBothFutureAndLegacyRoutes } from "./lib/future-legacy-routes";
|
||||
import {
|
||||
bookTimeSlot,
|
||||
confirmReschedule,
|
||||
fillStripeTestCheckout,
|
||||
selectFirstAvailableTimeSlotNextMonth,
|
||||
testName,
|
||||
@@ -300,7 +301,7 @@ testBothFutureAndLegacyRoutes.describe("Teams - NonOrg", (routeVariant) => {
|
||||
const booking = await bookings.create(owner.id, owner.username, eventType.id);
|
||||
await page.goto(`/reschedule/${booking.uid}`);
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
await page.locator("[data-testid=confirm-reschedule-button]").click();
|
||||
await confirmReschedule(page);
|
||||
await expect(page.locator("[data-testid=success-page]")).toBeVisible();
|
||||
});
|
||||
todo("Reschedule a Round Robin EventType booking");
|
||||
|
||||
@@ -9,9 +9,11 @@ import { test } from "./lib/fixtures";
|
||||
import {
|
||||
bookOptinEvent,
|
||||
bookTimeSlot,
|
||||
confirmReschedule,
|
||||
createUserWithSeatedEventAndAttendees,
|
||||
gotoRoutingLink,
|
||||
selectFirstAvailableTimeSlotNextMonth,
|
||||
submitAndWaitForResponse,
|
||||
} from "./lib/testUtils";
|
||||
|
||||
// remove dynamic properties that differs depending on where you run the tests
|
||||
@@ -145,8 +147,10 @@ test.describe("BOOKING_REJECTED", async () => {
|
||||
const webhookReceiver = await webhooks.createReceiver();
|
||||
await page.goto("/bookings/unconfirmed");
|
||||
await page.click('[data-testid="reject"]');
|
||||
await page.click('[data-testid="rejection-confirm"]');
|
||||
await page.waitForResponse((response) => response.url().includes("/api/trpc/bookings/confirm"));
|
||||
|
||||
await submitAndWaitForResponse(page, "/api/trpc/bookings/confirm?batch=1", {
|
||||
action: () => page.click('[data-testid="rejection-confirm"]'),
|
||||
});
|
||||
|
||||
await webhookReceiver.waitForRequestCount(1);
|
||||
|
||||
@@ -358,7 +362,7 @@ test.describe("BOOKING_RESCHEDULED", async () => {
|
||||
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
|
||||
await page.locator('[data-testid="confirm-reschedule-button"]').click();
|
||||
await confirmReschedule(page);
|
||||
|
||||
await expect(page.getByTestId("success-page")).toBeVisible();
|
||||
|
||||
@@ -426,7 +430,7 @@ test.describe("BOOKING_RESCHEDULED", async () => {
|
||||
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
|
||||
await page.locator('[data-testid="confirm-reschedule-button"]').click();
|
||||
await confirmReschedule(page);
|
||||
|
||||
await expect(page.getByTestId("success-page")).toBeVisible();
|
||||
|
||||
@@ -459,7 +463,7 @@ test.describe("BOOKING_RESCHEDULED", async () => {
|
||||
|
||||
await selectFirstAvailableTimeSlotNextMonth(page);
|
||||
|
||||
await page.locator('[data-testid="confirm-reschedule-button"]').click();
|
||||
await confirmReschedule(page);
|
||||
|
||||
await expect(page).toHaveURL(/.*booking/);
|
||||
|
||||
@@ -577,10 +581,28 @@ test.describe("MEETING_ENDED, MEETING_STARTED", async () => {
|
||||
expect(newMeetingEndedTriggers.length).toBe(0);
|
||||
|
||||
// disable webhook
|
||||
const submitPromise = page.waitForResponse("/api/trpc/webhook/edit?batch=1");
|
||||
await page.getByTestId("webhook-switch").click();
|
||||
const response = await submitPromise;
|
||||
expect(response.status()).toBe(200);
|
||||
await submitAndWaitForResponse(page, "/api/trpc/webhook/edit?batch=1", {
|
||||
action: () => page.getByTestId("webhook-switch").click(),
|
||||
});
|
||||
|
||||
const scheduledTriggersAfterDisabling = await prisma.webhookScheduledTriggers.findMany({
|
||||
where: {
|
||||
webhook: {
|
||||
userId: user.id,
|
||||
},
|
||||
},
|
||||
select: {
|
||||
payload: true,
|
||||
webhook: {
|
||||
select: {
|
||||
userId: true,
|
||||
},
|
||||
},
|
||||
startAfter: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(scheduledTriggersAfterDisabling.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -102,8 +102,9 @@ export async function bookFirstEvent(username: string, frame: Frame, page: Page)
|
||||
// --- fill form
|
||||
await frame.fill('[name="name"]', "Embed User");
|
||||
await frame.fill('[name="email"]', "embed-user@example.com");
|
||||
const responsePromise = page.waitForResponse("**/api/book/event");
|
||||
await frame.press('[name="email"]', "Enter");
|
||||
const response = await page.waitForResponse("**/api/book/event");
|
||||
const response = await responsePromise;
|
||||
const booking = (await response.json()) as { uid: string; eventSlug: string };
|
||||
expect(response.status()).toBe(200);
|
||||
booking.eventSlug = eventSlug;
|
||||
@@ -114,8 +115,9 @@ export async function rescheduleEvent(username: string, frame: Frame, page: Page
|
||||
await selectFirstAvailableTimeSlotNextMonth(frame, page);
|
||||
// --- fill form
|
||||
await frame.press('[name="email"]', "Enter");
|
||||
const responsePromise = page.waitForResponse("**/api/book/event");
|
||||
await frame.click("[data-testid=confirm-reschedule-button]");
|
||||
const response = await page.waitForResponse("**/api/book/event");
|
||||
const response = await responsePromise;
|
||||
expect(response.status()).toBe(200);
|
||||
const responseObj = await response.json();
|
||||
const booking = responseObj.uid;
|
||||
|
||||
Reference in new issue
Block a user