Files
flights_web/tests/e2e/breadcrumbs-parity.spec.ts

166 lines
6.6 KiB
TypeScript

import { test, expect } from "./fixtures/console-gate";
import type { Page } from "@playwright/test";
import { formatYmd, mondayOfWeek, sundayOfWeek } from "./helpers/dates";
import { routeDictionaryFixtures } from "./helpers/api-fixtures";
// Angular's breadcrumb trail (audited live on flights.test.aeroflot.ru):
// /schedule → [Главная]
// /schedule/route/... → [Главная, Расписание рейсов]
// /schedule/<dep>/<flt>/<arr> → [Главная, Расписание рейсов]
// /schedule/<dep>/<flt>/<arr>?request=schedule-route-…
// → [Главная, Расписание рейсов, "{depCity} - {arrCity}"]
// (no "Маршрут:" prefix; leaf links back to /schedule/route/...)
// /onlineboard → [Главная]
// /onlineboard/route/... → [Главная, Онлайн-Табло]
// /onlineboard/<flt>-<date> → [Главная, Онлайн-Табло]
// /onlineboard/<flt>-<date>?request=onlineboard-flight-…
// → […, "Рейс: SU 6188"] (carrier and number space-separated)
// /onlineboard/<flt>-<date>?request=onlineboard-route-…
// → […, "Маршрут: {depCity} - {arrCity}"]
// /onlineboard/<flt>-<date>?request=onlineboard-departure-<airportIATA>-…
// → […, "Вылет: {airportName}"] (airport name, e.g. SVO → "Шереметьево")
// /onlineboard/<flt>-<date>?request=onlineboard-arrival-<cityIATA>-…
// → […, "Прилет: {cityName}"]
async function readCrumbs(page: Page) {
return page.evaluate(() =>
Array.from(document.querySelectorAll(".breadcrumbs__item")).map((li) => ({
text:
li.textContent
?.replace(/\s+/g, " ")
.replace(/\/$/, "")
.trim() ?? "",
href: li.querySelector("a")?.getAttribute("href") ?? null,
})),
);
}
const today = new Date();
const todayYmd = formatYmd(today);
const weekFrom = formatYmd(mondayOfWeek(today));
const weekTo = formatYmd(sundayOfWeek(today));
const cases: { name: string; url: string; expected: { text: string; href: string | null }[] }[] = [
{
name: "Schedule start page",
url: "/ru-ru/schedule",
expected: [
{ text: "Главная", href: "https://www.aeroflot.ru" },
],
},
{
name: "Schedule route page",
url: `/ru-ru/schedule/route/MOW-LED-${weekFrom}-${weekTo}`,
expected: [
{ text: "Главная", href: "https://www.aeroflot.ru" },
{ text: "Расписание рейсов", href: "/ru-ru/schedule" },
],
},
{
name: "Schedule details page (share-link, no ?request=)",
url: `/ru-ru/schedule/SVO/SU6951-${todayYmd}/LED`,
expected: [
{ text: "Главная", href: "https://www.aeroflot.ru" },
{ text: "Расписание рейсов", href: "/ru-ru/schedule" },
],
},
{
name: "Schedule details page (with ?request=schedule-route)",
url: `/ru-ru/schedule/SVO/SU6951-${todayYmd}/LED?request=schedule-route-MOW-LED-${weekFrom}-${weekTo}`,
expected: [
{ text: "Главная", href: "https://www.aeroflot.ru" },
{ text: "Расписание рейсов", href: "/ru-ru/schedule" },
{
text: "Москва - Санкт-Петербург",
href: `/ru-ru/schedule/route/MOW-LED-${weekFrom}-${weekTo}`,
},
],
},
{
name: "Onlineboard start page",
url: "/ru-ru/onlineboard",
expected: [
{ text: "Главная", href: "https://www.aeroflot.ru" },
],
},
{
name: "Onlineboard route page",
url: `/ru-ru/onlineboard/route/MOW-LED-${todayYmd}`,
expected: [
{ text: "Главная", href: "https://www.aeroflot.ru" },
{ text: "Онлайн-Табло", href: "/ru-ru/onlineboard" },
],
},
{
name: "Onlineboard details page (share-link, no ?request=)",
url: `/ru-ru/onlineboard/SU0006-${todayYmd}`,
expected: [
{ text: "Главная", href: "https://www.aeroflot.ru" },
{ text: "Онлайн-Табло", href: "/ru-ru/onlineboard" },
],
},
{
name: "Onlineboard details page (with ?request=onlineboard-flight)",
url: `/ru-ru/onlineboard/SU6188-${todayYmd}?request=onlineboard-flight-SU6188-${todayYmd}`,
expected: [
{ text: "Главная", href: "https://www.aeroflot.ru" },
{ text: "Онлайн-Табло", href: "/ru-ru/onlineboard" },
{
text: "Рейс: SU 6188",
href: `/ru-ru/onlineboard/flight/SU6188-${todayYmd}`,
},
],
},
{
name: "Onlineboard details page (with ?request=onlineboard-route)",
url: `/ru-ru/onlineboard/SU6188-${todayYmd}?request=onlineboard-route-MOW-LED-${todayYmd}`,
expected: [
{ text: "Главная", href: "https://www.aeroflot.ru" },
{ text: "Онлайн-Табло", href: "/ru-ru/onlineboard" },
{
text: "Маршрут: Москва - Санкт-Петербург",
href: `/ru-ru/onlineboard/route/MOW-LED-${todayYmd}`,
},
],
},
{
name: "Onlineboard details page (with ?request=onlineboard-departure, airport IATA)",
url: `/ru-ru/onlineboard/SU6188-${todayYmd}?request=onlineboard-departure-SVO-${todayYmd}`,
expected: [
{ text: "Главная", href: "https://www.aeroflot.ru" },
{ text: "Онлайн-Табло", href: "/ru-ru/onlineboard" },
{
text: "Вылет: Шереметьево",
href: `/ru-ru/onlineboard/departure/SVO-${todayYmd}`,
},
],
},
{
name: "Onlineboard details page (with ?request=onlineboard-arrival, city IATA)",
url: `/ru-ru/onlineboard/SU6188-${todayYmd}?request=onlineboard-arrival-LED-${todayYmd}`,
expected: [
{ text: "Главная", href: "https://www.aeroflot.ru" },
{ text: "Онлайн-Табло", href: "/ru-ru/onlineboard" },
{
text: "Прилет: Санкт-Петербург",
href: `/ru-ru/onlineboard/arrival/LED-${todayYmd}`,
},
],
},
];
test.describe("Breadcrumb parity with Angular", () => {
for (const c of cases) {
test(c.name, async ({ page, consoleMessages }) => {
await routeDictionaryFixtures(page);
await page.goto(c.url);
await expect(page.getByTestId("breadcrumbs")).toBeVisible({ timeout: 15000 });
// Poll on the full items array — the leaf depends on dictionaries
// fetched asynchronously, so labels arrive after the initial paint.
await expect
.poll(async () => readCrumbs(page), { timeout: 15000 })
.toEqual(c.expected);
});
}
});