Harden schedule calendar operating-days e2e
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { test, expect } from "./fixtures/console-gate";
|
||||
import type { Page } from "@playwright/test";
|
||||
|
||||
// TIRREDESIGN-12 — when both schedule cities are filled, the date-picker
|
||||
// must grey out the days the route does NOT operate. The schedule
|
||||
@@ -13,50 +14,202 @@ function ymd(date: Date): string {
|
||||
].join("");
|
||||
}
|
||||
|
||||
function isoYmd(date: Date): string {
|
||||
return [
|
||||
date.getFullYear(),
|
||||
String(date.getMonth() + 1).padStart(2, "0"),
|
||||
String(date.getDate()).padStart(2, "0"),
|
||||
].join("-");
|
||||
}
|
||||
|
||||
function addDays(date: Date, days: number): Date {
|
||||
const next = new Date(date);
|
||||
next.setDate(next.getDate() + days);
|
||||
return next;
|
||||
}
|
||||
|
||||
async function visibleCalendarCellClasses(page: Page) {
|
||||
return page
|
||||
.locator(".p-datepicker td:not(.p-datepicker-other-month) span")
|
||||
.evaluateAll((nodes) =>
|
||||
nodes.map((node) => ({
|
||||
text: node.textContent?.trim(),
|
||||
className: node.className,
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
test("Schedule calendar greys out non-operating days for the route", async ({ page }) => {
|
||||
const minDate = addDays(new Date(), -1);
|
||||
minDate.setHours(0, 0, 0, 0);
|
||||
const dateTo = addDays(minDate, 6);
|
||||
const daysRequests: string[] = [];
|
||||
|
||||
await page.route("**/api/flights/v1/*/days/**/schedule/", async (route) => {
|
||||
daysRequests.push(route.request().url());
|
||||
await route.fulfill({
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ days: `0${"1".repeat(381)}` }),
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto(`/ru-ru/schedule/route/LED-KUF-${ymd(minDate)}-${ymd(dateTo)}-C0`);
|
||||
await page.goto(
|
||||
`/ru-ru/schedule/route/LED-KUF-${ymd(minDate)}-${ymd(dateTo)}-C0`,
|
||||
);
|
||||
|
||||
// Open the picker.
|
||||
await page.locator("button.p-datepicker-trigger").first().click();
|
||||
const panel = page.locator(".p-datepicker-panel, .p-datepicker").first();
|
||||
await expect(panel).toBeVisible();
|
||||
|
||||
const visibleDaySelector = ".p-datepicker td:not(.p-datepicker-other-month) span";
|
||||
const minDateDay = String(minDate.getDate());
|
||||
const nextDateDay = String(addDays(minDate, 1).getDate());
|
||||
|
||||
await expect.poll(async () => {
|
||||
const cells = await page.locator(visibleDaySelector).evaluateAll((nodes) =>
|
||||
nodes.map((node) => ({
|
||||
text: node.textContent?.trim(),
|
||||
className: node.className,
|
||||
})),
|
||||
);
|
||||
const cells = await visibleCalendarCellClasses(page);
|
||||
return cells.find((cell) => cell.text === minDateDay)?.className ?? "";
|
||||
}, { timeout: 10000 }).toContain("p-disabled");
|
||||
|
||||
const cells = await page.locator(visibleDaySelector).evaluateAll((nodes) =>
|
||||
nodes.map((node) => ({
|
||||
text: node.textContent?.trim(),
|
||||
className: node.className,
|
||||
})),
|
||||
expect(daysRequests[0]).toContain(
|
||||
`/days/${isoYmd(minDate)}/382/route/LED-KUF/schedule/`,
|
||||
);
|
||||
expect(cells.find((cell) => cell.text === nextDateDay)?.className ?? "").not.toContain("p-disabled");
|
||||
|
||||
const cells = await visibleCalendarCellClasses(page);
|
||||
expect(
|
||||
cells.find((cell) => cell.text === nextDateDay)?.className ?? "",
|
||||
).not.toContain("p-disabled");
|
||||
});
|
||||
|
||||
test("Schedule calendar updates an already-open picker when operating days load", async ({ page }) => {
|
||||
const minDate = addDays(new Date(), -1);
|
||||
minDate.setHours(0, 0, 0, 0);
|
||||
const dateTo = addDays(minDate, 6);
|
||||
|
||||
let releaseDays: (() => void) | undefined;
|
||||
await page.route("**/api/flights/v1/*/days/**/schedule/", async (route) => {
|
||||
await new Promise<void>((resolve) => {
|
||||
releaseDays = resolve;
|
||||
});
|
||||
await route.fulfill({
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ days: `0${"1".repeat(381)}` }),
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto(
|
||||
`/ru-ru/schedule/route/LED-KUF-${ymd(minDate)}-${ymd(dateTo)}-C0`,
|
||||
);
|
||||
|
||||
await page.locator("button.p-datepicker-trigger").first().click();
|
||||
const panel = page.locator(".p-datepicker-panel, .p-datepicker").first();
|
||||
await expect(panel).toBeVisible();
|
||||
|
||||
const visibleDaySelector =
|
||||
".p-datepicker td:not(.p-datepicker-other-month) span";
|
||||
const minDateDay = String(minDate.getDate());
|
||||
|
||||
const classBeforeLoad = await page
|
||||
.locator(visibleDaySelector)
|
||||
.evaluateAll(
|
||||
(nodes, day) =>
|
||||
nodes
|
||||
.map((node) => ({
|
||||
text: node.textContent?.trim(),
|
||||
className: node.className,
|
||||
}))
|
||||
.find((cell) => cell.text === day)?.className ?? "",
|
||||
minDateDay,
|
||||
);
|
||||
expect(classBeforeLoad).not.toContain("p-disabled");
|
||||
|
||||
releaseDays?.();
|
||||
|
||||
await expect.poll(async () => {
|
||||
const cells = await visibleCalendarCellClasses(page);
|
||||
return cells.find((cell) => cell.text === minDateDay)?.className ?? "";
|
||||
}, { timeout: 10000 }).toContain("p-disabled");
|
||||
});
|
||||
|
||||
test("Schedule calendar uses the connections days endpoint when transfers are allowed", async ({ page }) => {
|
||||
const minDate = addDays(new Date(), -1);
|
||||
minDate.setHours(0, 0, 0, 0);
|
||||
const dateTo = addDays(minDate, 6);
|
||||
const daysRequests: string[] = [];
|
||||
|
||||
await page.route("**/api/flights/v1/*/days/**/schedule/", async (route) => {
|
||||
daysRequests.push(route.request().url());
|
||||
await route.fulfill({
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({ days: `0${"1".repeat(381)}` }),
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto(
|
||||
`/ru-ru/schedule/route/LED-KUF-${ymd(minDate)}-${ymd(dateTo)}`,
|
||||
);
|
||||
|
||||
await page.locator("button.p-datepicker-trigger").first().click();
|
||||
await expect(
|
||||
page.locator(".p-datepicker-panel, .p-datepicker").first(),
|
||||
).toBeVisible();
|
||||
|
||||
await expect
|
||||
.poll(() => daysRequests[0] ?? "", { timeout: 10000 })
|
||||
.toContain("/connections/LED-KUF-1/schedule/");
|
||||
await expect.poll(async () => {
|
||||
const cells = await visibleCalendarCellClasses(page);
|
||||
return (
|
||||
cells.find((cell) => cell.text === String(minDate.getDate()))?.className ??
|
||||
""
|
||||
);
|
||||
}, { timeout: 10000 }).toContain("p-disabled");
|
||||
});
|
||||
|
||||
test("Schedule return calendar uses swapped route operating days", async ({ page }) => {
|
||||
const minDate = addDays(new Date(), -1);
|
||||
minDate.setHours(0, 0, 0, 0);
|
||||
const dateTo = addDays(minDate, 6);
|
||||
const returnFrom = addDays(dateTo, 1);
|
||||
const returnTo = addDays(returnFrom, 6);
|
||||
const daysRequests: string[] = [];
|
||||
const returnMask = `${"1".repeat(7)}0${"1".repeat(374)}`;
|
||||
|
||||
await page.route("**/api/flights/v1/*/days/**/schedule/", async (route) => {
|
||||
const url = route.request().url();
|
||||
daysRequests.push(url);
|
||||
await route.fulfill({
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({
|
||||
days: url.includes("/connections/KUF-LED-1/")
|
||||
? returnMask
|
||||
: "1".repeat(382),
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto(
|
||||
`/ru-ru/schedule/route/LED-KUF-${ymd(minDate)}-${ymd(dateTo)}/KUF-LED-${ymd(returnFrom)}-${ymd(returnTo)}`,
|
||||
);
|
||||
|
||||
const triggers = page.locator("button.p-datepicker-trigger");
|
||||
await expect(triggers).toHaveCount(2);
|
||||
await triggers.nth(1).click();
|
||||
await expect(
|
||||
page.locator(".p-datepicker-panel, .p-datepicker").first(),
|
||||
).toBeVisible();
|
||||
|
||||
await expect
|
||||
.poll(
|
||||
() => daysRequests.some((url) => url.includes("/connections/KUF-LED-1/")),
|
||||
{ timeout: 10000 },
|
||||
)
|
||||
.toBe(true);
|
||||
|
||||
await expect.poll(async () => {
|
||||
const cells = await visibleCalendarCellClasses(page);
|
||||
return (
|
||||
cells.find((cell) => cell.text === String(returnFrom.getDate()))
|
||||
?.className ?? ""
|
||||
);
|
||||
}, { timeout: 10000 }).toContain("p-disabled");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user