chore: [app dir bootstrapping 2] ensure tests do not have explicit timeouts (#11970)
parent
2a8f7412dd
commit
e91fe12219
|
@ -53,7 +53,7 @@ test.describe("free user", () => {
|
||||||
// book same time spot again
|
// book same time spot again
|
||||||
await bookTimeSlot(page);
|
await bookTimeSlot(page);
|
||||||
|
|
||||||
await expect(page.locator("[data-testid=booking-fail]")).toBeVisible({ timeout: 1000 });
|
await page.locator("[data-testid=booking-fail]").waitFor({ state: "visible" });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import type { Frame, Page } from "@playwright/test";
|
import type { Frame, Page } from "@playwright/test";
|
||||||
import { expect } from "@playwright/test";
|
import { expect } from "@playwright/test";
|
||||||
|
import EventEmitter from "events";
|
||||||
import type { IncomingMessage, ServerResponse } from "http";
|
import type { IncomingMessage, ServerResponse } from "http";
|
||||||
import { createServer } from "http";
|
import { createServer } from "http";
|
||||||
// eslint-disable-next-line no-restricted-imports
|
// eslint-disable-next-line no-restricted-imports
|
||||||
|
@ -35,7 +36,27 @@ export function createHttpServer(opts: { requestHandler?: RequestHandler } = {})
|
||||||
res.end();
|
res.end();
|
||||||
},
|
},
|
||||||
} = opts;
|
} = opts;
|
||||||
|
const eventEmitter = new EventEmitter();
|
||||||
const requestList: Request[] = [];
|
const requestList: Request[] = [];
|
||||||
|
|
||||||
|
const waitForRequestCount = (count: number) =>
|
||||||
|
new Promise<void>((resolve) => {
|
||||||
|
if (requestList.length === count) {
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pushHandler = () => {
|
||||||
|
if (requestList.length !== count) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
eventEmitter.off("push", pushHandler);
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
|
||||||
|
eventEmitter.on("push", pushHandler);
|
||||||
|
});
|
||||||
|
|
||||||
const server = createServer((req, res) => {
|
const server = createServer((req, res) => {
|
||||||
const buffer: unknown[] = [];
|
const buffer: unknown[] = [];
|
||||||
|
|
||||||
|
@ -49,6 +70,7 @@ export function createHttpServer(opts: { requestHandler?: RequestHandler } = {})
|
||||||
|
|
||||||
_req.body = json;
|
_req.body = json;
|
||||||
requestList.push(_req);
|
requestList.push(_req);
|
||||||
|
eventEmitter.emit("push");
|
||||||
requestHandler({ req: _req, res });
|
requestHandler({ req: _req, res });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -58,34 +80,16 @@ export function createHttpServer(opts: { requestHandler?: RequestHandler } = {})
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const port: number = (server.address() as any).port;
|
const port: number = (server.address() as any).port;
|
||||||
const url = `http://localhost:${port}`;
|
const url = `http://localhost:${port}`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
port,
|
port,
|
||||||
close: () => server.close(),
|
close: () => server.close(),
|
||||||
requestList,
|
requestList,
|
||||||
url,
|
url,
|
||||||
|
waitForRequestCount,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* When in need to wait for any period of time you can use waitFor, to wait for your expectations to pass.
|
|
||||||
*/
|
|
||||||
export async function waitFor(fn: () => Promise<unknown> | unknown, opts: { timeout?: number } = {}) {
|
|
||||||
let finished = false;
|
|
||||||
const timeout = opts.timeout ?? 5000; // 5s
|
|
||||||
const timeStart = Date.now();
|
|
||||||
while (!finished) {
|
|
||||||
try {
|
|
||||||
await fn();
|
|
||||||
finished = true;
|
|
||||||
} catch {
|
|
||||||
if (Date.now() - timeStart >= timeout) {
|
|
||||||
throw new Error("waitFor timed out");
|
|
||||||
}
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function selectFirstAvailableTimeSlotNextMonth(page: Page | Frame) {
|
export async function selectFirstAvailableTimeSlotNextMonth(page: Page | Frame) {
|
||||||
// Let current month dates fully render.
|
// Let current month dates fully render.
|
||||||
await page.click('[data-testid="incrementMonth"]');
|
await page.click('[data-testid="incrementMonth"]');
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { WebhookTriggerEvents } from "@calcom/prisma/enums";
|
||||||
import type { CalendarEvent } from "@calcom/types/Calendar";
|
import type { CalendarEvent } from "@calcom/types/Calendar";
|
||||||
|
|
||||||
import { test } from "./lib/fixtures";
|
import { test } from "./lib/fixtures";
|
||||||
import { createHttpServer, waitFor, selectFirstAvailableTimeSlotNextMonth } from "./lib/testUtils";
|
import { createHttpServer, selectFirstAvailableTimeSlotNextMonth } from "./lib/testUtils";
|
||||||
|
|
||||||
async function getLabelText(field: Locator) {
|
async function getLabelText(field: Locator) {
|
||||||
return await field.locator("label").first().locator("span").first().innerText();
|
return await field.locator("label").first().locator("span").first().innerText();
|
||||||
|
@ -215,13 +215,7 @@ test.describe("Manage Booking Questions", () => {
|
||||||
async function runTestStepsCommonForTeamAndUserEventType(
|
async function runTestStepsCommonForTeamAndUserEventType(
|
||||||
page: Page,
|
page: Page,
|
||||||
context: PlaywrightTestArgs["context"],
|
context: PlaywrightTestArgs["context"],
|
||||||
webhookReceiver: {
|
webhookReceiver: Awaited<ReturnType<typeof addWebhook>>
|
||||||
port: number;
|
|
||||||
close: () => import("http").Server;
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
requestList: (import("http").IncomingMessage & { body?: any })[];
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
) {
|
) {
|
||||||
await page.click('[href$="tabName=advanced"]');
|
await page.click('[href$="tabName=advanced"]');
|
||||||
|
|
||||||
|
@ -311,12 +305,11 @@ async function runTestStepsCommonForTeamAndUserEventType(
|
||||||
await page.locator('[data-testid="field-response"][data-fob-field="how-are-you"]').innerText()
|
await page.locator('[data-testid="field-response"][data-fob-field="how-are-you"]').innerText()
|
||||||
).toBe("I am great!");
|
).toBe("I am great!");
|
||||||
|
|
||||||
await waitFor(() => {
|
await webhookReceiver.waitForRequestCount(1);
|
||||||
expect(webhookReceiver.requestList.length).toBe(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
const [request] = webhookReceiver.requestList;
|
const [request] = webhookReceiver.requestList;
|
||||||
|
|
||||||
|
// @ts-expect-error body is unknown
|
||||||
const payload = request.body.payload;
|
const payload = request.body.payload;
|
||||||
|
|
||||||
expect(payload.responses).toMatchObject({
|
expect(payload.responses).toMatchObject({
|
||||||
|
@ -667,9 +660,7 @@ async function expectWebhookToBeCalled(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
await waitFor(() => {
|
await webhookReceiver.waitForRequestCount(1);
|
||||||
expect(webhookReceiver.requestList.length).toBe(1);
|
|
||||||
});
|
|
||||||
const [request] = webhookReceiver.requestList;
|
const [request] = webhookReceiver.requestList;
|
||||||
|
|
||||||
const body = request.body;
|
const body = request.body;
|
||||||
|
|
|
@ -10,7 +10,6 @@ import {
|
||||||
bookOptinEvent,
|
bookOptinEvent,
|
||||||
createHttpServer,
|
createHttpServer,
|
||||||
selectFirstAvailableTimeSlotNextMonth,
|
selectFirstAvailableTimeSlotNextMonth,
|
||||||
waitFor,
|
|
||||||
gotoRoutingLink,
|
gotoRoutingLink,
|
||||||
createUserWithSeatedEventAndAttendees,
|
createUserWithSeatedEventAndAttendees,
|
||||||
} from "./lib/testUtils";
|
} from "./lib/testUtils";
|
||||||
|
@ -78,10 +77,7 @@ test.describe("BOOKING_CREATED", async () => {
|
||||||
await page.fill('[name="email"]', "test@example.com");
|
await page.fill('[name="email"]', "test@example.com");
|
||||||
await page.press('[name="email"]', "Enter");
|
await page.press('[name="email"]', "Enter");
|
||||||
|
|
||||||
// --- check that webhook was called
|
await webhookReceiver.waitForRequestCount(1);
|
||||||
await waitFor(() => {
|
|
||||||
expect(webhookReceiver.requestList.length).toBe(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
const [request] = webhookReceiver.requestList;
|
const [request] = webhookReceiver.requestList;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
@ -209,10 +205,8 @@ test.describe("BOOKING_REJECTED", async () => {
|
||||||
await page.click('[data-testid="rejection-confirm"]');
|
await page.click('[data-testid="rejection-confirm"]');
|
||||||
await page.waitForResponse((response) => response.url().includes("/api/trpc/bookings/confirm"));
|
await page.waitForResponse((response) => response.url().includes("/api/trpc/bookings/confirm"));
|
||||||
|
|
||||||
// --- check that webhook was called
|
await webhookReceiver.waitForRequestCount(1);
|
||||||
await waitFor(() => {
|
|
||||||
expect(webhookReceiver.requestList.length).toBe(1);
|
|
||||||
});
|
|
||||||
const [request] = webhookReceiver.requestList;
|
const [request] = webhookReceiver.requestList;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const body = request.body as any;
|
const body = request.body as any;
|
||||||
|
@ -332,9 +326,8 @@ test.describe("BOOKING_REQUESTED", async () => {
|
||||||
|
|
||||||
// --- check that webhook was called
|
// --- check that webhook was called
|
||||||
|
|
||||||
await waitFor(() => {
|
await webhookReceiver.waitForRequestCount(1);
|
||||||
expect(webhookReceiver.requestList.length).toBe(1);
|
|
||||||
});
|
|
||||||
const [request] = webhookReceiver.requestList;
|
const [request] = webhookReceiver.requestList;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const body = request.body as any;
|
const body = request.body as any;
|
||||||
|
@ -442,9 +435,7 @@ test.describe("BOOKING_RESCHEDULED", async () => {
|
||||||
expect(newBooking).not.toBeNull();
|
expect(newBooking).not.toBeNull();
|
||||||
|
|
||||||
// --- check that webhook was called
|
// --- check that webhook was called
|
||||||
await waitFor(() => {
|
await webhookReceiver.waitForRequestCount(1);
|
||||||
expect(webhookReceiver.requestList.length).toBe(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
const [request] = webhookReceiver.requestList;
|
const [request] = webhookReceiver.requestList;
|
||||||
|
|
||||||
|
@ -520,9 +511,7 @@ test.describe("BOOKING_RESCHEDULED", async () => {
|
||||||
expect(newBooking).not.toBeNull();
|
expect(newBooking).not.toBeNull();
|
||||||
|
|
||||||
// --- check that webhook was called
|
// --- check that webhook was called
|
||||||
await waitFor(() => {
|
await webhookReceiver.waitForRequestCount(1);
|
||||||
expect(webhookReceiver.requestList.length).toBe(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
const [firstRequest] = webhookReceiver.requestList;
|
const [firstRequest] = webhookReceiver.requestList;
|
||||||
|
|
||||||
|
@ -541,9 +530,7 @@ test.describe("BOOKING_RESCHEDULED", async () => {
|
||||||
|
|
||||||
await expect(page).toHaveURL(/.*booking/);
|
await expect(page).toHaveURL(/.*booking/);
|
||||||
|
|
||||||
await waitFor(() => {
|
await webhookReceiver.waitForRequestCount(2);
|
||||||
expect(webhookReceiver.requestList.length).toBe(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
const [_, secondRequest] = webhookReceiver.requestList;
|
const [_, secondRequest] = webhookReceiver.requestList;
|
||||||
|
|
||||||
|
@ -597,9 +584,8 @@ test.describe("FORM_SUBMITTED", async () => {
|
||||||
await page.fill(`[data-testid="form-field-${fieldName}"]`, "John Doe");
|
await page.fill(`[data-testid="form-field-${fieldName}"]`, "John Doe");
|
||||||
page.click('button[type="submit"]');
|
page.click('button[type="submit"]');
|
||||||
|
|
||||||
await waitFor(() => {
|
await webhookReceiver.waitForRequestCount(1);
|
||||||
expect(webhookReceiver.requestList.length).toBe(1);
|
|
||||||
});
|
|
||||||
const [request] = webhookReceiver.requestList;
|
const [request] = webhookReceiver.requestList;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const body = request.body as any;
|
const body = request.body as any;
|
||||||
|
@ -656,9 +642,9 @@ test.describe("FORM_SUBMITTED", async () => {
|
||||||
const fieldName = "name";
|
const fieldName = "name";
|
||||||
await page.fill(`[data-testid="form-field-${fieldName}"]`, "John Doe");
|
await page.fill(`[data-testid="form-field-${fieldName}"]`, "John Doe");
|
||||||
page.click('button[type="submit"]');
|
page.click('button[type="submit"]');
|
||||||
await waitFor(() => {
|
|
||||||
expect(webhookReceiver.requestList.length).toBe(1);
|
await webhookReceiver.waitForRequestCount(1);
|
||||||
});
|
|
||||||
const [request] = webhookReceiver.requestList;
|
const [request] = webhookReceiver.requestList;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const body = request.body as any;
|
const body = request.body as any;
|
||||||
|
|
Loading…
Reference in New Issue