69 lines
2.8 KiB
TypeScript
69 lines
2.8 KiB
TypeScript
import { test, expect } from "./fixtures/console-gate";
|
|
import { routeScheduleVvoMjzFixtures } from "./helpers/api-fixtures";
|
|
|
|
// Schedule search-results page must mirror Angular's
|
|
// `<flight-details-body-actions>` strip in each expanded flight body —
|
|
// that's where Angular surfaces the buy ticket button (TZ §4.1.14.4.4).
|
|
// The component had been silently dropped during a refactor that confused
|
|
// the search-results page with the dedicated `flight-schedule-details`
|
|
// page (which DOES suppress buy/share because its page-level summary
|
|
// owns those affordances).
|
|
|
|
test("schedule route page surfaces the buy ticket button inside an expanded flight body", async ({
|
|
page,
|
|
}) => {
|
|
await page.addInitScript(() => {
|
|
const fixedTime = new Date("2026-05-17T00:00:00+03:00").getTime();
|
|
const RealDate = Date;
|
|
const FixedDate = function fixedDate(
|
|
this: Date,
|
|
...args: unknown[]
|
|
) {
|
|
return args.length === 0
|
|
? new RealDate(fixedTime)
|
|
: Reflect.construct(RealDate, args);
|
|
} as unknown as DateConstructor;
|
|
FixedDate.now = () => fixedTime;
|
|
FixedDate.parse = RealDate.parse;
|
|
FixedDate.UTC = RealDate.UTC;
|
|
Object.defineProperty(FixedDate, "prototype", {
|
|
value: RealDate.prototype,
|
|
});
|
|
Object.setPrototypeOf(FixedDate, RealDate);
|
|
window.Date = FixedDate;
|
|
});
|
|
await routeScheduleVvoMjzFixtures(page);
|
|
// Pick a calendar week well clear of the 2h pre-departure cutoff so every
|
|
// flight in the list is inside the buy window. Earlier-this-week URLs hit
|
|
// a "today's first flight is < 2h out" edge case and the buy button hides
|
|
// on that single row, even though the rest of the list shows it.
|
|
await page.goto("/ru-ru/schedule/route/VVO-MJZ-20260518-20260524");
|
|
|
|
// Wait for the list to render.
|
|
const cards = page.locator(".flight-card--clickable");
|
|
await expect(cards.first()).toBeVisible({ timeout: 30000 });
|
|
|
|
// Expand each card in turn until we find one whose body strip shows the
|
|
// buy button — Angular's parity contract is "buy button surfaces on
|
|
// search results page", not "on every single row regardless of status",
|
|
// so we just need one positive proof per spec run.
|
|
const total = await cards.count();
|
|
let foundBuy = false;
|
|
for (let i = 0; i < total && i < 8; i++) {
|
|
await cards.nth(i).click();
|
|
const actions = page
|
|
.locator('[data-testid="schedule-flight-body-actions"]')
|
|
.nth(i);
|
|
await expect(actions).toBeVisible({ timeout: 10000 });
|
|
const buy = actions.locator('[data-testid="buy-ticket-button"]');
|
|
if (await buy.isVisible()) {
|
|
foundBuy = true;
|
|
break;
|
|
}
|
|
// Collapse before opening the next so we don't accumulate expanded
|
|
// rows that fight for viewport.
|
|
await cards.nth(i).click();
|
|
}
|
|
expect(foundBuy, "expected at least one expanded flight body to render buy ticket button").toBe(true);
|
|
});
|