fix: resolve flaky 'Book on column layout' E2E test (#28682)

In column view, time slots are always visible. selectFirstAvailableTimeSlotNextMonth
could click stale time slots from the current month before the schedule data refreshed
for the new month. Since isQuickAvailabilityCheckFeatureEnabled is always true in E2E,
isTimeSlotAvailable would check the stale slot against the new month's schedule data,
find no match, and permanently disable the confirm button.

Fix: wait for initial schedule data to load before setting up a waitForResponse listener
for getSchedule, then click incrementMonth and await the response before selecting slots.

Ported from calcom/cal#1107.
This commit is contained in:
Sahitya Chandra
2026-03-31 20:04:15 +05:30
committed by GitHub
parent 78ddc1b2ae
commit 77b2be13b2
2 changed files with 37 additions and 15 deletions
+13 -15
View File
@@ -1,16 +1,3 @@
import { test, todo } from "./lib/fixtures";
import {
bookFirstEvent,
bookOptinEvent,
bookTimeSlot,
confirmBooking,
confirmReschedule,
expectSlotNotAllowedToBook,
selectFirstAvailableTimeSlotNextMonth,
testEmail,
testName,
cancelBookingFromBookingsList,
} from "./lib/testUtils";
import { WEBAPP_URL } from "@calcom/lib/constants";
import { generateHashedLink } from "@calcom/lib/generateHashedLink";
import { randomString } from "@calcom/lib/random";
@@ -18,6 +5,19 @@ import { SchedulingType } from "@calcom/prisma/enums";
import type { Schedule, TimeRange } from "@calcom/types/schedule";
import { expect } from "@playwright/test";
import { JSDOM } from "jsdom";
import { test, todo } from "./lib/fixtures";
import {
bookFirstEvent,
bookOptinEvent,
bookTimeSlot,
cancelBookingFromBookingsList,
confirmBooking,
confirmReschedule,
expectSlotNotAllowedToBook,
selectFirstAvailableTimeSlotNextMonth,
testEmail,
testName,
} from "./lib/testUtils";
const freeUserObj = { name: `Free-user-${randomString(3)}` };
test.describe.configure({ mode: "parallel" });
@@ -486,8 +486,6 @@ test.describe("Booking on different layouts", () => {
await page.click('[data-testid="toggle-group-item-column_view"]');
// Use the standard helper to select an available time slot next month
// This is more robust than manually clicking incrementMonth and reloading
await selectFirstAvailableTimeSlotNextMonth(page);
// Fill what is this meeting about? name email and notes
+24
View File
@@ -109,7 +109,22 @@ export async function selectFirstAvailableTimeSlotNextMonth(page: Page | Frame)
// Wait for the booker to be ready before interacting
const incrementMonth = page.getByTestId("incrementMonth");
await incrementMonth.waitFor();
// Wait for the initial schedule data to load (available days rendered in date picker).
// This ensures the waitForResponse listener below only catches the month-change response,
// not the initial page load response. Without this, column view can race: stale time slots
// from the current month get clicked before the new month's schedule data arrives, causing
// the quick availability check to permanently disable the confirm button.
await page.locator('[data-testid="day"][data-disabled="false"]').nth(0).waitFor();
// Listen for the getSchedule response triggered by the month change.
// waitForResponse is only available on Page, not Frame.
const scheduleResponse =
"waitForResponse" in page
? page.waitForResponse((resp) => resp.url().includes("getSchedule") && resp.status() === 200)
: Promise.resolve();
await incrementMonth.click();
await scheduleResponse;
// Wait for available day to appear after month increment
const firstAvailableDay = page.locator('[data-testid="day"][data-disabled="false"]').nth(0);
@@ -125,7 +140,16 @@ export async function selectSecondAvailableTimeSlotNextMonth(page: Page) {
// Wait for the booker to be ready before interacting
const incrementMonth = page.getByTestId("incrementMonth");
await incrementMonth.waitFor();
// Wait for initial schedule data to load before changing month (see selectFirstAvailableTimeSlotNextMonth)
await page.locator('[data-testid="day"][data-disabled="false"]').nth(0).waitFor();
// Listen for the getSchedule response triggered by the month change
const scheduleResponse = page.waitForResponse(
(resp) => resp.url().includes("getSchedule") && resp.status() === 200
);
await incrementMonth.click();
await scheduleResponse;
// Wait for available day to appear after month increment
const secondAvailableDay = page.locator('[data-testid="day"][data-disabled="false"]').nth(1);