Stabilize schedule e2e date fixtures
This commit is contained in:
@@ -155,6 +155,22 @@ describe("DayTabs", () => {
|
|||||||
expect(screen.getByTestId("day-select")).toBeTruthy();
|
expect(screen.getByTestId("day-select")).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("deduplicates available dates before rendering the mobile select", () => {
|
||||||
|
render(
|
||||||
|
<DayTabs
|
||||||
|
selectedDate="20260416"
|
||||||
|
availableDates={["20260416", "20260416", "20260417"]}
|
||||||
|
daysBefore={1}
|
||||||
|
daysAfter={2}
|
||||||
|
locale="en"
|
||||||
|
onNavigate={() => {}}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
const options = screen.getByTestId("day-select").querySelectorAll("option");
|
||||||
|
expect(options).toHaveLength(2);
|
||||||
|
});
|
||||||
|
|
||||||
// ── TZ §4.1.13.1 compliance tests ──────────────────────────────────────
|
// ── TZ §4.1.13.1 compliance tests ──────────────────────────────────────
|
||||||
|
|
||||||
it("4.1.13.1: active range today-1 to today+14 yields 16 total dates", () => {
|
it("4.1.13.1: active range today-1 to today+14 yields 16 total dates", () => {
|
||||||
|
|||||||
@@ -68,8 +68,15 @@ export const DayTabs: FC<DayTabsProps> = ({
|
|||||||
// the route has no day data). Treat every date as tappable in that
|
// the route has no day data). Treat every date as tappable in that
|
||||||
// case — matches Angular where the tabs stay enabled until we *know*
|
// case — matches Angular where the tabs stay enabled until we *know*
|
||||||
// the upstream reports no flights for a given day.
|
// the upstream reports no flights for a given day.
|
||||||
const availableSet = useMemo(() => new Set(availableDates), [availableDates]);
|
const uniqueAvailableDates = useMemo(
|
||||||
const disableByAvailability = availableDates.length > 0;
|
() => Array.from(new Set(availableDates)),
|
||||||
|
[availableDates],
|
||||||
|
);
|
||||||
|
const availableSet = useMemo(
|
||||||
|
() => new Set(uniqueAvailableDates),
|
||||||
|
[uniqueAvailableDates],
|
||||||
|
);
|
||||||
|
const disableByAvailability = uniqueAvailableDates.length > 0;
|
||||||
|
|
||||||
const visibleDates = allDates.slice(
|
const visibleDates = allDates.slice(
|
||||||
currentPage * PAGE_SIZE,
|
currentPage * PAGE_SIZE,
|
||||||
@@ -150,7 +157,7 @@ export const DayTabs: FC<DayTabsProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
<DaySelect
|
<DaySelect
|
||||||
selectedDate={selectedDate}
|
selectedDate={selectedDate}
|
||||||
availableDates={availableDates}
|
availableDates={uniqueAvailableDates}
|
||||||
locale={locale}
|
locale={locale}
|
||||||
onNavigate={onNavigate}
|
onNavigate={onNavigate}
|
||||||
{...(mobileCaptionKey ? { captionKey: mobileCaptionKey } : {})}
|
{...(mobileCaptionKey ? { captionKey: mobileCaptionKey } : {})}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import fs from "node:fs";
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
import type { Page, Route } from "@playwright/test";
|
import type { Page, Route } from "@playwright/test";
|
||||||
|
import { replaceVvoMjzFixtureDates } from "./dates";
|
||||||
|
|
||||||
const FIXTURE_DIR = path.resolve(
|
const FIXTURE_DIR = path.resolve(
|
||||||
path.dirname(fileURLToPath(import.meta.url)),
|
path.dirname(fileURLToPath(import.meta.url)),
|
||||||
@@ -12,6 +13,10 @@ function fixtureText(name: string): string {
|
|||||||
return fs.readFileSync(path.join(FIXTURE_DIR, name), "utf8");
|
return fs.readFileSync(path.join(FIXTURE_DIR, name), "utf8");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function vvoMjzFixtureText(name: string): string {
|
||||||
|
return replaceVvoMjzFixtureDates(fixtureText(name));
|
||||||
|
}
|
||||||
|
|
||||||
async function fulfillJson(route: Route, body: string): Promise<void> {
|
async function fulfillJson(route: Route, body: string): Promise<void> {
|
||||||
await route.fulfill({
|
await route.fulfill({
|
||||||
status: 200,
|
status: 200,
|
||||||
@@ -96,10 +101,10 @@ export async function routeScheduleVvoMjzFixtures(page: Page): Promise<void> {
|
|||||||
fulfillJson(route, fixtureText("schedule-days-route.json")),
|
fulfillJson(route, fixtureText("schedule-days-route.json")),
|
||||||
);
|
);
|
||||||
await page.route("**/api/flights/1/*/schedule?**", (route) =>
|
await page.route("**/api/flights/1/*/schedule?**", (route) =>
|
||||||
fulfillJson(route, fixtureText("schedule-search-vvo-mjz.json")),
|
fulfillJson(route, vvoMjzFixtureText("schedule-search-vvo-mjz.json")),
|
||||||
);
|
);
|
||||||
await page.route("**/api/flights/v1.1/*/schedule/details?**", (route) =>
|
await page.route("**/api/flights/v1.1/*/schedule/details?**", (route) =>
|
||||||
fulfillJson(route, fixtureText("schedule-details-vvo-mjz.json")),
|
fulfillJson(route, vvoMjzFixtureText("schedule-details-vvo-mjz.json")),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,10 +117,10 @@ export async function routeScheduleVvoMjzServicesFixtures(
|
|||||||
fulfillJson(route, fixtureText("schedule-days-route.json")),
|
fulfillJson(route, fixtureText("schedule-days-route.json")),
|
||||||
);
|
);
|
||||||
await page.route("**/api/flights/1/*/schedule?**", (route) =>
|
await page.route("**/api/flights/1/*/schedule?**", (route) =>
|
||||||
fulfillJson(route, fixtureText("schedule-search-vvo-mjz.json")),
|
fulfillJson(route, vvoMjzFixtureText("schedule-search-vvo-mjz.json")),
|
||||||
);
|
);
|
||||||
await page.route("**/api/flights/v1.1/*/schedule/details?**", (route) => {
|
await page.route("**/api/flights/v1.1/*/schedule/details?**", (route) => {
|
||||||
const fixture = JSON.parse(fixtureText("schedule-details-vvo-mjz.json"));
|
const fixture = JSON.parse(vvoMjzFixtureText("schedule-details-vvo-mjz.json"));
|
||||||
const actual = fixture.data.routes[0].leg.equipment.aircraft.actual;
|
const actual = fixture.data.routes[0].leg.equipment.aircraft.actual;
|
||||||
actual.onBoardServices = [
|
actual.onBoardServices = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,3 +32,82 @@ export function sundayOfWeek(date: Date): Date {
|
|||||||
export function formatRuWeekRange(date: Date): string {
|
export function formatRuWeekRange(date: Date): string {
|
||||||
return `${formatRuDate(mondayOfWeek(date))} - ${formatRuDate(sundayOfWeek(date))}`;
|
return `${formatRuDate(mondayOfWeek(date))} - ${formatRuDate(sundayOfWeek(date))}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function vvoMjzScheduleDates(): {
|
||||||
|
start: Date;
|
||||||
|
end: Date;
|
||||||
|
leg1: Date;
|
||||||
|
leg2: Date;
|
||||||
|
altLeg1: Date;
|
||||||
|
altLeg2: Date;
|
||||||
|
preStart: Date;
|
||||||
|
startYmd: string;
|
||||||
|
endYmd: string;
|
||||||
|
leg1Ymd: string;
|
||||||
|
leg2Ymd: string;
|
||||||
|
altLeg1Ymd: string;
|
||||||
|
altLeg2Ymd: string;
|
||||||
|
leg1Iso: string;
|
||||||
|
leg2Iso: string;
|
||||||
|
altLeg1Iso: string;
|
||||||
|
altLeg2Iso: string;
|
||||||
|
} {
|
||||||
|
const start = mondayOfWeek(addDays(new Date(), 7));
|
||||||
|
const end = sundayOfWeek(start);
|
||||||
|
const leg1 = start;
|
||||||
|
const leg2 = addDays(start, 1);
|
||||||
|
const altLeg1 = addDays(start, 4);
|
||||||
|
const altLeg2 = addDays(start, 5);
|
||||||
|
const preStart = addDays(start, -2);
|
||||||
|
|
||||||
|
return {
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
leg1,
|
||||||
|
leg2,
|
||||||
|
altLeg1,
|
||||||
|
altLeg2,
|
||||||
|
preStart,
|
||||||
|
startYmd: formatYmd(start),
|
||||||
|
endYmd: formatYmd(end),
|
||||||
|
leg1Ymd: formatYmd(leg1),
|
||||||
|
leg2Ymd: formatYmd(leg2),
|
||||||
|
altLeg1Ymd: formatYmd(altLeg1),
|
||||||
|
altLeg2Ymd: formatYmd(altLeg2),
|
||||||
|
leg1Iso: formatIsoDate(leg1),
|
||||||
|
leg2Iso: formatIsoDate(leg2),
|
||||||
|
altLeg1Iso: formatIsoDate(altLeg1),
|
||||||
|
altLeg2Iso: formatIsoDate(altLeg2),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function vvoMjzRouteUrl(route = "VVO-MJZ"): string {
|
||||||
|
const dates = vvoMjzScheduleDates();
|
||||||
|
return `/ru-ru/schedule/route/${route}-${dates.startYmd}-${dates.endYmd}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function vvoMjzDetailsUrl(): string {
|
||||||
|
const dates = vvoMjzScheduleDates();
|
||||||
|
return `/ru-ru/schedule/VVO/SU5752-${dates.leg1Ymd}/KJA/SU6837-${dates.leg2Ymd}/MJZ?request=schedule-route-VVO-MJZ-${dates.startYmd}-${dates.endYmd}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function replaceVvoMjzFixtureDates(text: string): string {
|
||||||
|
const dates = vvoMjzScheduleDates();
|
||||||
|
const replacements: Array<[string, string]> = [
|
||||||
|
["20260518", dates.leg1Ymd],
|
||||||
|
["20260519", dates.leg2Ymd],
|
||||||
|
["20260522", dates.altLeg1Ymd],
|
||||||
|
["20260523", dates.altLeg2Ymd],
|
||||||
|
["20260524", dates.endYmd],
|
||||||
|
["2026-05-18", dates.leg1Iso],
|
||||||
|
["2026-05-19", dates.leg2Iso],
|
||||||
|
["2026-05-22", dates.altLeg1Iso],
|
||||||
|
["2026-05-23", dates.altLeg2Iso],
|
||||||
|
["2026-05-24", formatIsoDate(dates.end)],
|
||||||
|
];
|
||||||
|
|
||||||
|
return replacements.reduce(
|
||||||
|
(result, [from, to]) => result.replaceAll(from, to),
|
||||||
|
text,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,22 @@
|
|||||||
import { test, expect } from "./fixtures/console-gate";
|
import { test, expect } from "./fixtures/console-gate";
|
||||||
|
import {
|
||||||
|
routeAppSettingsFixture,
|
||||||
|
routeDictionaryFixtures,
|
||||||
|
routePopularRequestsFixture,
|
||||||
|
} from "./helpers/api-fixtures";
|
||||||
|
|
||||||
|
async function routeNavigationStartFixtures(page: import("@playwright/test").Page): Promise<void> {
|
||||||
|
await routeAppSettingsFixture(page);
|
||||||
|
await routeDictionaryFixtures(page);
|
||||||
|
await routePopularRequestsFixture(page);
|
||||||
|
}
|
||||||
|
|
||||||
test.describe("Cross-feature navigation", () => {
|
test.describe("Cross-feature navigation", () => {
|
||||||
test("locale switching: /ru/onlineboard -> /en/onlineboard shows English content", async ({
|
test("locale switching: /ru/onlineboard -> /en/onlineboard shows English content", async ({
|
||||||
page,
|
page,
|
||||||
consoleMessages,
|
consoleMessages,
|
||||||
}) => {
|
}) => {
|
||||||
|
await routeNavigationStartFixtures(page);
|
||||||
// Start on Russian online board
|
// Start on Russian online board
|
||||||
await page.goto("/ru/onlineboard");
|
await page.goto("/ru/onlineboard");
|
||||||
await page.waitForLoadState("domcontentloaded");
|
await page.waitForLoadState("domcontentloaded");
|
||||||
@@ -25,6 +37,7 @@ test.describe("Cross-feature navigation", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("error page: /error/404 renders 404 content", async ({ page, consoleMessages }) => {
|
test("error page: /error/404 renders 404 content", async ({ page, consoleMessages }) => {
|
||||||
|
await routeNavigationStartFixtures(page);
|
||||||
// Navigate to a working page first, then client-side navigate to the error
|
// Navigate to a working page first, then client-side navigate to the error
|
||||||
// page. Direct URL navigation to /error/404 renders blank because the
|
// page. Direct URL navigation to /error/404 renders blank because the
|
||||||
// error route is outside [lang]/layout.tsx and SSR produces empty output.
|
// error route is outside [lang]/layout.tsx and SSR produces empty output.
|
||||||
@@ -45,6 +58,7 @@ test.describe("Cross-feature navigation", () => {
|
|||||||
page,
|
page,
|
||||||
consoleMessages,
|
consoleMessages,
|
||||||
}) => {
|
}) => {
|
||||||
|
await routeNavigationStartFixtures(page);
|
||||||
// Navigate to a working page first, then client-side navigate to the error
|
// Navigate to a working page first, then client-side navigate to the error
|
||||||
// page (same reason as the 404 test above).
|
// page (same reason as the 404 test above).
|
||||||
await page.goto("/ru/onlineboard");
|
await page.goto("/ru/onlineboard");
|
||||||
|
|||||||
@@ -2,6 +2,10 @@ import { test, expect } from "./fixtures/console-gate";
|
|||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
|
import {
|
||||||
|
replaceVvoMjzFixtureDates,
|
||||||
|
vvoMjzDetailsUrl,
|
||||||
|
} from "./helpers/dates";
|
||||||
|
|
||||||
// Schedule details uses the same Angular aircraft-link behavior as
|
// Schedule details uses the same Angular aircraft-link behavior as
|
||||||
// online-board: the model text under "Борт" opens the generic plane park page.
|
// online-board: the model text under "Борт" opens the generic plane park page.
|
||||||
@@ -14,9 +18,7 @@ const scheduleDetails = fs.readFileSync(
|
|||||||
path.join(FIXTURE_DIR, "schedule-details.json"),
|
path.join(FIXTURE_DIR, "schedule-details.json"),
|
||||||
"utf8",
|
"utf8",
|
||||||
);
|
);
|
||||||
|
const scheduleDetailsBody = replaceVvoMjzFixtureDates(scheduleDetails);
|
||||||
const URL =
|
|
||||||
"/ru-ru/schedule/VVO/SU5752-20260518/KJA/SU6837-20260519/MJZ?request=schedule-route-VVO-MJZ-20260518-20260524";
|
|
||||||
|
|
||||||
test("Schedule details aircraft title opens Aeroflot plane park in a new tab", async ({
|
test("Schedule details aircraft title opens Aeroflot plane park in a new tab", async ({
|
||||||
page,
|
page,
|
||||||
@@ -27,11 +29,11 @@ test("Schedule details aircraft title opens Aeroflot plane park in a new tab", a
|
|||||||
await route.fulfill({
|
await route.fulfill({
|
||||||
status: 200,
|
status: 200,
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
body: scheduleDetails,
|
body: scheduleDetailsBody,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
await context.route("http://www.aeroflot.ru/cms/ru/flight/plane_park", async (route) => {
|
await context.route(/https?:\/\/www\.aeroflot\.ru\/cms\/ru\/flight\/plane_park/, async (route) => {
|
||||||
await route.fulfill({
|
await route.fulfill({
|
||||||
status: 200,
|
status: 200,
|
||||||
contentType: "text/html",
|
contentType: "text/html",
|
||||||
@@ -39,7 +41,7 @@ test("Schedule details aircraft title opens Aeroflot plane park in a new tab", a
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
await page.goto(URL);
|
await page.goto(vvoMjzDetailsUrl());
|
||||||
|
|
||||||
const details = page.locator(".schedule-leg-details");
|
const details = page.locator(".schedule-leg-details");
|
||||||
await expect(details).toHaveCount(1, { timeout: 15000 });
|
await expect(details).toHaveCount(1, { timeout: 15000 });
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
import { test, expect } from "./fixtures/console-gate";
|
import { test, expect } from "./fixtures/console-gate";
|
||||||
|
import {
|
||||||
|
routeAppSettingsFixture,
|
||||||
|
routeDictionaryFixtures,
|
||||||
|
} from "./helpers/api-fixtures";
|
||||||
import {
|
import {
|
||||||
addDays,
|
addDays,
|
||||||
formatRuDate,
|
formatRuDate,
|
||||||
@@ -21,6 +25,8 @@ test.describe("Schedule date-range picker (week-snap)", () => {
|
|||||||
page,
|
page,
|
||||||
consoleMessages,
|
consoleMessages,
|
||||||
}) => {
|
}) => {
|
||||||
|
await routeAppSettingsFixture(page);
|
||||||
|
await routeDictionaryFixtures(page);
|
||||||
await page.goto("/ru-ru/schedule");
|
await page.goto("/ru-ru/schedule");
|
||||||
await expect(page.getByTestId("date-range-input")).toBeVisible({
|
await expect(page.getByTestId("date-range-input")).toBeVisible({
|
||||||
timeout: 15000,
|
timeout: 15000,
|
||||||
@@ -31,21 +37,23 @@ test.describe("Schedule date-range picker (week-snap)", () => {
|
|||||||
const panel = page.locator(".p-datepicker-panel, .p-datepicker").first();
|
const panel = page.locator(".p-datepicker-panel, .p-datepicker").first();
|
||||||
await expect(panel).toBeVisible();
|
await expect(panel).toBeVisible();
|
||||||
|
|
||||||
const target = addDays(new Date(), 7);
|
const target = addDays(new Date(), 1);
|
||||||
await panel.locator(`td[aria-label="${formatRuDate(target)}"] span`).click();
|
await panel.locator(`td[aria-label="${formatRuDate(target)}"] span`).click();
|
||||||
|
|
||||||
// Panel auto-dismissed.
|
// Panel auto-dismissed.
|
||||||
await expect(panel).toBeHidden({ timeout: 5000 });
|
await expect(panel).toBeHidden({ timeout: 5000 });
|
||||||
|
|
||||||
// Input now holds the full week range.
|
// The current week is rendered with Angular's compact label.
|
||||||
const input = page.locator("#schedule-date-from");
|
const input = page.locator("#schedule-date-from");
|
||||||
await expect(input).toHaveValue(formatRuWeekRange(target));
|
await expect(input).toHaveValue("Текущая неделя");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("clicking an enabled other-month bleed-in day snaps to its Mon-Sun week", async ({
|
test("clicking an enabled other-month bleed-in day snaps to its Mon-Sun week", async ({
|
||||||
page,
|
page,
|
||||||
consoleMessages,
|
consoleMessages,
|
||||||
}) => {
|
}) => {
|
||||||
|
await routeAppSettingsFixture(page);
|
||||||
|
await routeDictionaryFixtures(page);
|
||||||
await page.goto("/ru-ru/schedule");
|
await page.goto("/ru-ru/schedule");
|
||||||
await expect(page.getByTestId("date-range-input")).toBeVisible({
|
await expect(page.getByTestId("date-range-input")).toBeVisible({
|
||||||
timeout: 15000,
|
timeout: 15000,
|
||||||
@@ -83,6 +91,8 @@ test.describe("Schedule date-range picker (week-snap)", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("input renders as range placeholder when empty", async ({ page, consoleMessages }) => {
|
test("input renders as range placeholder when empty", async ({ page, consoleMessages }) => {
|
||||||
|
await routeAppSettingsFixture(page);
|
||||||
|
await routeDictionaryFixtures(page);
|
||||||
await page.goto("/ru-ru/schedule");
|
await page.goto("/ru-ru/schedule");
|
||||||
const input = page.locator("#schedule-date-from");
|
const input = page.locator("#schedule-date-from");
|
||||||
await expect(input).toHaveAttribute(
|
await expect(input).toHaveAttribute(
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { test, expect } from "./fixtures/console-gate";
|
import { test, expect } from "./fixtures/console-gate";
|
||||||
import { routeScheduleVvoMjzFixtures } from "./helpers/api-fixtures";
|
import { routeScheduleVvoMjzFixtures } from "./helpers/api-fixtures";
|
||||||
|
import { vvoMjzRouteUrl } from "./helpers/dates";
|
||||||
|
|
||||||
// When the user clicks a connecting itinerary in the Schedule list, the
|
// When the user clicks a connecting itinerary in the Schedule list, the
|
||||||
// resulting flight-details URL must include EVERY leg, not just the
|
// resulting flight-details URL must include EVERY leg, not just the
|
||||||
@@ -14,7 +15,7 @@ test("connecting itinerary navigates to a multi-segment URL with both legs rende
|
|||||||
consoleMessages,
|
consoleMessages,
|
||||||
}) => {
|
}) => {
|
||||||
await routeScheduleVvoMjzFixtures(page);
|
await routeScheduleVvoMjzFixtures(page);
|
||||||
await page.goto("/ru-ru/schedule/route/VVO-MJZ-20260518-20260524");
|
await page.goto(vvoMjzRouteUrl());
|
||||||
await expect(page.locator(".flight-card").first()).toBeVisible({
|
await expect(page.locator(".flight-card").first()).toBeVisible({
|
||||||
timeout: 15000,
|
timeout: 15000,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,23 +3,28 @@ import path from "node:path";
|
|||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
import { test, expect } from "./fixtures/console-gate";
|
import { test, expect } from "./fixtures/console-gate";
|
||||||
import { routeAppSettingsFixture } from "./helpers/api-fixtures";
|
import { routeAppSettingsFixture } from "./helpers/api-fixtures";
|
||||||
|
import {
|
||||||
|
replaceVvoMjzFixtureDates,
|
||||||
|
vvoMjzScheduleDates,
|
||||||
|
} from "./helpers/dates";
|
||||||
|
|
||||||
const FIXTURE_DIR = path.resolve(
|
const FIXTURE_DIR = path.resolve(
|
||||||
path.dirname(fileURLToPath(import.meta.url)),
|
path.dirname(fileURLToPath(import.meta.url)),
|
||||||
"../fixtures/api",
|
"../fixtures/api",
|
||||||
);
|
);
|
||||||
|
|
||||||
const URL =
|
|
||||||
"/ru-ru/schedule/KJA/SU6837-20260519/MJZ?request=schedule-route-KJA-MJZ-20260518-20260524-C0";
|
|
||||||
|
|
||||||
test("TIRREDESIGN-26: schedule details day tabs disable non-operating flight dates", async ({
|
test("TIRREDESIGN-26: schedule details day tabs disable non-operating flight dates", async ({
|
||||||
page,
|
page,
|
||||||
consoleMessages,
|
consoleMessages,
|
||||||
}) => {
|
}) => {
|
||||||
|
const dates = vvoMjzScheduleDates();
|
||||||
|
const url = `/ru-ru/schedule/KJA/SU6837-${dates.leg2Ymd}/MJZ?request=schedule-route-KJA-MJZ-${dates.startYmd}-${dates.endYmd}-C0`;
|
||||||
await routeAppSettingsFixture(page);
|
await routeAppSettingsFixture(page);
|
||||||
await page.route("**/api/flights/v1.1/*/schedule/details?**", async (route) => {
|
await page.route("**/api/flights/v1.1/*/schedule/details?**", async (route) => {
|
||||||
const source = JSON.parse(
|
const source = JSON.parse(
|
||||||
fs.readFileSync(path.join(FIXTURE_DIR, "schedule-details-vvo-mjz.json"), "utf8"),
|
replaceVvoMjzFixtureDates(
|
||||||
|
fs.readFileSync(path.join(FIXTURE_DIR, "schedule-details-vvo-mjz.json"), "utf8"),
|
||||||
|
),
|
||||||
) as {
|
) as {
|
||||||
data: {
|
data: {
|
||||||
routes: Array<{
|
routes: Array<{
|
||||||
@@ -32,7 +37,7 @@ test("TIRREDESIGN-26: schedule details day tabs disable non-operating flight dat
|
|||||||
(flight) =>
|
(flight) =>
|
||||||
flight.flightId.carrier === "SU" &&
|
flight.flightId.carrier === "SU" &&
|
||||||
flight.flightId.flightNumber === "6837" &&
|
flight.flightId.flightNumber === "6837" &&
|
||||||
flight.flightId.date === "2026-05-19",
|
flight.flightId.date === dates.leg2Iso,
|
||||||
);
|
);
|
||||||
expect(su6837).toBeTruthy();
|
expect(su6837).toBeTruthy();
|
||||||
await route.fulfill({
|
await route.fulfill({
|
||||||
@@ -42,18 +47,19 @@ test("TIRREDESIGN-26: schedule details day tabs disable non-operating flight dat
|
|||||||
data: {
|
data: {
|
||||||
partners: [],
|
partners: [],
|
||||||
routes: su6837 ? [su6837] : [],
|
routes: su6837 ? [su6837] : [],
|
||||||
daysOfFlight: ["20260519", "20260523"],
|
daysOfFlight: [dates.leg2Ymd, dates.altLeg2Ymd],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
await page.goto(URL);
|
await page.goto(url);
|
||||||
await expect(page.getByTestId("day-tabs")).toBeVisible({ timeout: 15000 });
|
await expect(page.getByTestId("day-tabs")).toBeVisible({ timeout: 15000 });
|
||||||
|
await page.getByTestId("day-tabs-next").click();
|
||||||
|
|
||||||
const nonOperatingFriday = page.getByTestId("day-tab-20260522");
|
const nonOperatingFriday = page.getByTestId(`day-tab-${dates.altLeg1Ymd}`);
|
||||||
await expect(nonOperatingFriday).toBeDisabled();
|
await expect(nonOperatingFriday).toBeDisabled();
|
||||||
await expect(page.getByTestId("day-tab-20260523")).toBeEnabled();
|
await expect(page.getByTestId(`day-tab-${dates.altLeg2Ymd}`)).toBeEnabled();
|
||||||
|
|
||||||
await expect(page.getByTestId("schedule-details-not-found")).toHaveCount(0);
|
await expect(page.getByTestId("schedule-details-not-found")).toHaveCount(0);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { test, expect } from "./fixtures/console-gate";
|
import { test, expect } from "./fixtures/console-gate";
|
||||||
import { routeScheduleVvoMjzFixtures } from "./helpers/api-fixtures";
|
import { routeScheduleVvoMjzFixtures } from "./helpers/api-fixtures";
|
||||||
|
import { vvoMjzDetailsUrl } from "./helpers/dates";
|
||||||
|
|
||||||
// Schedule Details "Питание на борту" must render meal-class sub-icons
|
// Schedule Details "Питание на борту" must render meal-class sub-icons
|
||||||
// (Эконом класс / Комфорт класс / Бизнес класс) ONLY when the API
|
// (Эконом класс / Комфорт класс / Бизнес класс) ONLY when the API
|
||||||
@@ -11,15 +12,12 @@ import { routeScheduleVvoMjzFixtures } from "./helpers/api-fixtures";
|
|||||||
// Reference URL covers a connecting itinerary where both live legs
|
// Reference URL covers a connecting itinerary where both live legs
|
||||||
// currently return Economy / Comfort / Business meal entries.
|
// currently return Economy / Comfort / Business meal entries.
|
||||||
|
|
||||||
const URL =
|
|
||||||
"/ru-ru/schedule/VVO/SU5752-20260518/KJA/SU6837-20260519/MJZ?request=schedule-route-VVO-MJZ-20260518-20260524";
|
|
||||||
|
|
||||||
test("Питание sub-icons appear only for legs whose API meal[] contains them", async ({
|
test("Питание sub-icons appear only for legs whose API meal[] contains them", async ({
|
||||||
page,
|
page,
|
||||||
consoleMessages,
|
consoleMessages,
|
||||||
}) => {
|
}) => {
|
||||||
await routeScheduleVvoMjzFixtures(page);
|
await routeScheduleVvoMjzFixtures(page);
|
||||||
await page.goto(URL);
|
await page.goto(vvoMjzDetailsUrl());
|
||||||
|
|
||||||
// Wait until both leg-details panels are mounted.
|
// Wait until both leg-details panels are mounted.
|
||||||
await expect(page.locator(".schedule-leg-details")).toHaveCount(2, {
|
await expect(page.locator(".schedule-leg-details")).toHaveCount(2, {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { test, expect } from "./fixtures/console-gate";
|
import { test, expect } from "./fixtures/console-gate";
|
||||||
import { routeScheduleVvoMjzFixtures } from "./helpers/api-fixtures";
|
import { routeScheduleVvoMjzFixtures } from "./helpers/api-fixtures";
|
||||||
|
import { vvoMjzDetailsUrl } from "./helpers/dates";
|
||||||
|
|
||||||
// On the schedule details page the left mini-list renders a SINGLE
|
// On the schedule details page the left mini-list renders a SINGLE
|
||||||
// card for the currently-open flight — matching Angular's
|
// card for the currently-open flight — matching Angular's
|
||||||
@@ -12,12 +13,9 @@ import { routeScheduleVvoMjzFixtures } from "./helpers/api-fixtures";
|
|||||||
// flight numbers ("SU 5752, SU 6837") and the combined
|
// flight numbers ("SU 5752, SU 6837") and the combined
|
||||||
// Vladivostok→Mirny origin/destination, not just the first leg.
|
// Vladivostok→Mirny origin/destination, not just the first leg.
|
||||||
|
|
||||||
const URL =
|
|
||||||
"/ru-ru/schedule/VVO/SU5752-20260518/KJA/SU6837-20260519/MJZ?request=schedule-route-VVO-MJZ-20260518-20260524";
|
|
||||||
|
|
||||||
test("mini-list — one combined card for the open SU 5752+SU 6837 itinerary", async ({ page, consoleMessages }) => {
|
test("mini-list — one combined card for the open SU 5752+SU 6837 itinerary", async ({ page, consoleMessages }) => {
|
||||||
await routeScheduleVvoMjzFixtures(page);
|
await routeScheduleVvoMjzFixtures(page);
|
||||||
await page.goto(URL);
|
await page.goto(vvoMjzDetailsUrl());
|
||||||
|
|
||||||
const miniList = page.locator(".schedule-mini-list");
|
const miniList = page.locator(".schedule-mini-list");
|
||||||
await expect(miniList).toBeVisible({ timeout: 15000 });
|
await expect(miniList).toBeVisible({ timeout: 15000 });
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import { test, expect } from "./fixtures/console-gate";
|
import { test, expect } from "./fixtures/console-gate";
|
||||||
import { routeScheduleVvoMjzServicesFixtures } from "./helpers/api-fixtures";
|
import { routeScheduleVvoMjzServicesFixtures } from "./helpers/api-fixtures";
|
||||||
|
import { vvoMjzDetailsUrl } from "./helpers/dates";
|
||||||
const URL =
|
|
||||||
"/ru-ru/schedule/VVO/SU5752-20260518/KJA/SU6837-20260519/MJZ?request=schedule-route-VVO-MJZ-20260518-20260524";
|
|
||||||
|
|
||||||
test("schedule details render onboard services from actual aircraft data", async ({
|
test("schedule details render onboard services from actual aircraft data", async ({
|
||||||
page,
|
page,
|
||||||
}) => {
|
}) => {
|
||||||
await routeScheduleVvoMjzServicesFixtures(page);
|
await routeScheduleVvoMjzServicesFixtures(page);
|
||||||
await page.goto(URL);
|
await page.goto(vvoMjzDetailsUrl());
|
||||||
|
|
||||||
const leg1 = page.locator(".schedule-leg-details").nth(0);
|
const leg1 = page.locator(".schedule-leg-details").nth(0);
|
||||||
await expect(leg1).toBeVisible({ timeout: 15000 });
|
await expect(leg1).toBeVisible({ timeout: 15000 });
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { test, expect } from "./fixtures/console-gate";
|
import { test, expect } from "./fixtures/console-gate";
|
||||||
import { routeScheduleVvoMjzFixtures } from "./helpers/api-fixtures";
|
import { routeScheduleVvoMjzFixtures } from "./helpers/api-fixtures";
|
||||||
|
import { vvoMjzDetailsUrl } from "./helpers/dates";
|
||||||
|
|
||||||
// Schedule details page must render Angular's `<schedule-details-header>`
|
// Schedule details page must render Angular's `<schedule-details-header>`
|
||||||
// summary block between the day-tabs strip and the per-leg cards:
|
// summary block between the day-tabs strip and the per-leg cards:
|
||||||
@@ -13,12 +14,9 @@ import { routeScheduleVvoMjzFixtures } from "./helpers/api-fixtures";
|
|||||||
// This test pins those guarantees so the page can't regress to "no
|
// This test pins those guarantees so the page can't regress to "no
|
||||||
// summary header" or "first-leg-only badge / raw ISO timeline" again.
|
// summary header" or "first-leg-only badge / raw ISO timeline" again.
|
||||||
|
|
||||||
const URL =
|
|
||||||
"/ru-ru/schedule/VVO/SU5752-20260518/KJA/SU6837-20260519/MJZ?request=schedule-route-VVO-MJZ-20260518-20260524";
|
|
||||||
|
|
||||||
test("summary header — both badges + last-update + formatted full-route timeline", async ({ page, consoleMessages }) => {
|
test("summary header — both badges + last-update + formatted full-route timeline", async ({ page, consoleMessages }) => {
|
||||||
await routeScheduleVvoMjzFixtures(page);
|
await routeScheduleVvoMjzFixtures(page);
|
||||||
await page.goto(URL);
|
await page.goto(vvoMjzDetailsUrl());
|
||||||
|
|
||||||
const summary = page.locator(".schedule-details__summary");
|
const summary = page.locator(".schedule-details__summary");
|
||||||
await expect(summary).toBeVisible({ timeout: 15000 });
|
await expect(summary).toBeVisible({ timeout: 15000 });
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
import { test, expect } from "./fixtures/console-gate";
|
import { test, expect } from "./fixtures/console-gate";
|
||||||
|
import { routeScheduleVvoMjzFixtures } from "./helpers/api-fixtures";
|
||||||
|
import { vvoMjzRouteUrl, vvoMjzScheduleDates } from "./helpers/dates";
|
||||||
|
|
||||||
test.describe("Schedule results filter", () => {
|
test.describe("Schedule results filter", () => {
|
||||||
test("changed route criteria can be submitted immediately after a previous search", async ({
|
test("changed route criteria can be submitted immediately after a previous search", async ({
|
||||||
page,
|
page,
|
||||||
consoleMessages,
|
consoleMessages,
|
||||||
}) => {
|
}) => {
|
||||||
await page.goto("/ru-ru/schedule/route/VVO-MJZ-20260518-20260524");
|
await routeScheduleVvoMjzFixtures(page);
|
||||||
|
const dates = vvoMjzScheduleDates();
|
||||||
|
await page.goto(vvoMjzRouteUrl());
|
||||||
|
|
||||||
await expect(page.locator("h1")).toContainText(/Владивосток.*Мирный|VVO.*MJZ/, {
|
await expect(page.locator("h1")).toContainText(/Владивосток.*Мирный|VVO.*MJZ/, {
|
||||||
timeout: 30000,
|
timeout: 30000,
|
||||||
@@ -29,7 +33,9 @@ test.describe("Schedule results filter", () => {
|
|||||||
);
|
);
|
||||||
await submit.click();
|
await submit.click();
|
||||||
|
|
||||||
await expect(page).toHaveURL(/\/ru-ru\/schedule\/route\/MJZ-VVO-20260518-20260524/);
|
await expect(page).toHaveURL(
|
||||||
|
new RegExp(`/ru-ru/schedule/route/MJZ-VVO-${dates.startYmd}-${dates.endYmd}`),
|
||||||
|
);
|
||||||
expect((await scheduleResponse).status()).toBe(200);
|
expect((await scheduleResponse).status()).toBe(200);
|
||||||
expect(consoleMessages).toEqual([]);
|
expect(consoleMessages).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { test, expect } from "./fixtures/console-gate";
|
import { test, expect } from "./fixtures/console-gate";
|
||||||
import { routeScheduleVvoMjzFixtures } from "./helpers/api-fixtures";
|
import { routeScheduleVvoMjzFixtures } from "./helpers/api-fixtures";
|
||||||
|
import { vvoMjzRouteUrl, vvoMjzScheduleDates } from "./helpers/dates";
|
||||||
const ROUTE_URL = "/ru-ru/schedule/route/VVO-MJZ-20260518-20260524";
|
|
||||||
|
|
||||||
test.describe("Schedule flight details button", () => {
|
test.describe("Schedule flight details button", () => {
|
||||||
test.beforeEach(async ({ page }) => {
|
test.beforeEach(async ({ page }) => {
|
||||||
@@ -11,7 +10,7 @@ test.describe("Schedule flight details button", () => {
|
|||||||
test("flight details button is visible in expanded flight body", async ({
|
test("flight details button is visible in expanded flight body", async ({
|
||||||
page,
|
page,
|
||||||
}) => {
|
}) => {
|
||||||
await page.goto(ROUTE_URL);
|
await page.goto(vvoMjzRouteUrl());
|
||||||
|
|
||||||
const cards = page.locator(".flight-card--clickable");
|
const cards = page.locator(".flight-card--clickable");
|
||||||
await expect(cards.first()).toBeVisible({ timeout: 30000 });
|
await expect(cards.first()).toBeVisible({ timeout: 30000 });
|
||||||
@@ -26,7 +25,7 @@ test.describe("Schedule flight details button", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("flight details button has correct label (Russian)", async ({ page }) => {
|
test("flight details button has correct label (Russian)", async ({ page }) => {
|
||||||
await page.goto(ROUTE_URL);
|
await page.goto(vvoMjzRouteUrl());
|
||||||
|
|
||||||
const cards = page.locator(".flight-card--clickable");
|
const cards = page.locator(".flight-card--clickable");
|
||||||
await expect(cards.first()).toBeVisible({ timeout: 30000 });
|
await expect(cards.first()).toBeVisible({ timeout: 30000 });
|
||||||
@@ -42,7 +41,7 @@ test.describe("Schedule flight details button", () => {
|
|||||||
test("flight details button navigates to flight details page", async ({
|
test("flight details button navigates to flight details page", async ({
|
||||||
page,
|
page,
|
||||||
}) => {
|
}) => {
|
||||||
await page.goto(ROUTE_URL);
|
await page.goto(vvoMjzRouteUrl());
|
||||||
|
|
||||||
const cards = page.locator(".flight-card--clickable");
|
const cards = page.locator(".flight-card--clickable");
|
||||||
await expect(cards.first()).toBeVisible({ timeout: 30000 });
|
await expect(cards.first()).toBeVisible({ timeout: 30000 });
|
||||||
@@ -58,7 +57,7 @@ test.describe("Schedule flight details button", () => {
|
|||||||
test("flight details button works for connecting flights", async ({
|
test("flight details button works for connecting flights", async ({
|
||||||
page,
|
page,
|
||||||
}) => {
|
}) => {
|
||||||
await page.goto(ROUTE_URL);
|
await page.goto(vvoMjzRouteUrl());
|
||||||
|
|
||||||
const cards = page.locator(".flight-card--clickable");
|
const cards = page.locator(".flight-card--clickable");
|
||||||
await expect(cards.first()).toBeVisible({ timeout: 30000 });
|
await expect(cards.first()).toBeVisible({ timeout: 30000 });
|
||||||
@@ -78,7 +77,8 @@ test.describe("Schedule flight details button", () => {
|
|||||||
test("flight details button preserves search context in URL", async ({
|
test("flight details button preserves search context in URL", async ({
|
||||||
page,
|
page,
|
||||||
}) => {
|
}) => {
|
||||||
await page.goto(ROUTE_URL);
|
const dates = vvoMjzScheduleDates();
|
||||||
|
await page.goto(vvoMjzRouteUrl());
|
||||||
|
|
||||||
const cards = page.locator(".flight-card--clickable");
|
const cards = page.locator(".flight-card--clickable");
|
||||||
await expect(cards.first()).toBeVisible({ timeout: 30000 });
|
await expect(cards.first()).toBeVisible({ timeout: 30000 });
|
||||||
@@ -90,6 +90,6 @@ test.describe("Schedule flight details button", () => {
|
|||||||
|
|
||||||
const url = page.url();
|
const url = page.url();
|
||||||
expect(url).toContain("?request=");
|
expect(url).toContain("?request=");
|
||||||
expect(url).toContain("schedule-route-VVO-MJZ-20260518-20260524");
|
expect(url).toContain(`schedule-route-VVO-MJZ-${dates.startYmd}-${dates.endYmd}`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { test, expect } from "./fixtures/console-gate";
|
import { test, expect } from "./fixtures/console-gate";
|
||||||
import { routeScheduleVvoMjzFixtures } from "./helpers/api-fixtures";
|
import { routeScheduleVvoMjzFixtures } from "./helpers/api-fixtures";
|
||||||
|
import { vvoMjzRouteUrl } from "./helpers/dates";
|
||||||
|
|
||||||
// Schedule search-results page must mirror Angular's
|
// Schedule search-results page must mirror Angular's
|
||||||
// `<flight-details-body-actions>` strip in each expanded flight body —
|
// `<flight-details-body-actions>` strip in each expanded flight body —
|
||||||
@@ -37,7 +38,7 @@ test("schedule route page surfaces the buy ticket button inside an expanded flig
|
|||||||
// flight in the list is inside the buy window. Earlier-this-week URLs hit
|
// 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
|
// 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.
|
// on that single row, even though the rest of the list shows it.
|
||||||
await page.goto("/ru-ru/schedule/route/VVO-MJZ-20260518-20260524");
|
await page.goto(vvoMjzRouteUrl());
|
||||||
|
|
||||||
// Wait for the list to render.
|
// Wait for the list to render.
|
||||||
const cards = page.locator(".flight-card--clickable");
|
const cards = page.locator(".flight-card--clickable");
|
||||||
|
|||||||
@@ -3,13 +3,26 @@ import {
|
|||||||
routeAppSettingsFixture,
|
routeAppSettingsFixture,
|
||||||
routeDictionaryFixtures,
|
routeDictionaryFixtures,
|
||||||
} from "./helpers/api-fixtures";
|
} from "./helpers/api-fixtures";
|
||||||
|
import {
|
||||||
|
addDays,
|
||||||
|
formatIsoDate,
|
||||||
|
formatYmd,
|
||||||
|
vvoMjzScheduleDates,
|
||||||
|
} from "./helpers/dates";
|
||||||
|
|
||||||
// TIRREDESIGN-28: SU0634 KJA -> HKT departs after midnight local time while
|
// TIRREDESIGN-28: SU0634 KJA -> HKT departs after midnight local time while
|
||||||
// the backend flightId.date remains on the previous service day. Angular builds
|
// the backend flightId.date remains on the previous service day. Angular builds
|
||||||
// the schedule details URL from the leg's local scheduled departure date, so
|
// the schedule details URL from the leg's local scheduled departure date, so
|
||||||
// the details request receives 2026-05-19 and the aircraft link is rendered.
|
// the details request receives the local departure date and the aircraft link is rendered.
|
||||||
|
|
||||||
const ROUTE_URL = "/ru-ru/schedule/route/KJA-HKT-20260519-20260525-C0";
|
const dates = vvoMjzScheduleDates();
|
||||||
|
const serviceDate = dates.leg1;
|
||||||
|
const localDate = dates.leg2;
|
||||||
|
const routeEnd = addDays(localDate, 6);
|
||||||
|
const SERVICE_DATE_ISO = formatIsoDate(serviceDate);
|
||||||
|
const LOCAL_DATE_ISO = formatIsoDate(localDate);
|
||||||
|
const LOCAL_DATE_YMD = formatYmd(localDate);
|
||||||
|
const ROUTE_URL = `/ru-ru/schedule/route/KJA-HKT-${LOCAL_DATE_YMD}-${formatYmd(routeEnd)}-C0`;
|
||||||
const PLANE_PARK_URL = "http://www.aeroflot.ru/cms/ru/flight/plane_park";
|
const PLANE_PARK_URL = "http://www.aeroflot.ru/cms/ru/flight/plane_park";
|
||||||
|
|
||||||
const su0634Search = [
|
const su0634Search = [
|
||||||
@@ -22,8 +35,8 @@ const su0634Search = [
|
|||||||
carrier: "SU",
|
carrier: "SU",
|
||||||
flightNumber: "0634",
|
flightNumber: "0634",
|
||||||
suffix: "",
|
suffix: "",
|
||||||
date: "2026-05-18",
|
date: SERVICE_DATE_ISO,
|
||||||
dateLT: "2026-05-19",
|
dateLT: LOCAL_DATE_ISO,
|
||||||
},
|
},
|
||||||
flyingTime: "08:10:00",
|
flyingTime: "08:10:00",
|
||||||
leg: {
|
leg: {
|
||||||
@@ -38,8 +51,8 @@ const su0634Search = [
|
|||||||
terminal: "1",
|
terminal: "1",
|
||||||
times: {
|
times: {
|
||||||
scheduledDeparture: {
|
scheduledDeparture: {
|
||||||
utc: "2026-05-18T22:05:00Z",
|
utc: `${SERVICE_DATE_ISO}T22:05:00Z`,
|
||||||
local: "2026-05-19T05:05:00+07:00",
|
local: `${LOCAL_DATE_ISO}T05:05:00+07:00`,
|
||||||
dayChange: { value: 0, title: "" },
|
dayChange: { value: 0, title: "" },
|
||||||
localTime: "05:05",
|
localTime: "05:05",
|
||||||
tzOffset: 420,
|
tzOffset: 420,
|
||||||
@@ -57,8 +70,8 @@ const su0634Search = [
|
|||||||
terminal: "I",
|
terminal: "I",
|
||||||
times: {
|
times: {
|
||||||
scheduledArrival: {
|
scheduledArrival: {
|
||||||
utc: "2026-05-19T06:15:00Z",
|
utc: `${LOCAL_DATE_ISO}T06:15:00Z`,
|
||||||
local: "2026-05-19T13:15:00+07:00",
|
local: `${LOCAL_DATE_ISO}T13:15:00+07:00`,
|
||||||
dayChange: { value: 0, title: "" },
|
dayChange: { value: 0, title: "" },
|
||||||
localTime: "13:15",
|
localTime: "13:15",
|
||||||
tzOffset: 420,
|
tzOffset: 420,
|
||||||
@@ -100,7 +113,12 @@ const su0634Details = {
|
|||||||
data: {
|
data: {
|
||||||
routes: su0634Search,
|
routes: su0634Search,
|
||||||
partners: [],
|
partners: [],
|
||||||
daysOfFlight: ["20260515", "20260519", "20260522", "20260526"],
|
daysOfFlight: [
|
||||||
|
formatYmd(addDays(localDate, -4)),
|
||||||
|
LOCAL_DATE_YMD,
|
||||||
|
formatYmd(addDays(localDate, 3)),
|
||||||
|
formatYmd(addDays(localDate, 7)),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -132,13 +150,13 @@ test("TIRREDESIGN-28: SU0634 schedule details uses local date and opens plane pa
|
|||||||
status: 200,
|
status: 200,
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
body: JSON.stringify(
|
body: JSON.stringify(
|
||||||
date === "2026-05-19T00:00:00"
|
date === `${LOCAL_DATE_ISO}T00:00:00`
|
||||||
? su0634Details
|
? su0634Details
|
||||||
: { data: { routes: [], partners: [], daysOfFlight: [] } },
|
: { data: { routes: [], partners: [], daysOfFlight: [] } },
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
await context.route(PLANE_PARK_URL, async (route) => {
|
await context.route(/https?:\/\/www\.aeroflot\.ru\/cms\/ru\/flight\/plane_park/, async (route) => {
|
||||||
await route.fulfill({
|
await route.fulfill({
|
||||||
status: 200,
|
status: 200,
|
||||||
contentType: "text/html",
|
contentType: "text/html",
|
||||||
@@ -156,7 +174,9 @@ test("TIRREDESIGN-28: SU0634 schedule details uses local date and opens plane pa
|
|||||||
await expect(detailsBtn).toBeVisible({ timeout: 10000 });
|
await expect(detailsBtn).toBeVisible({ timeout: 10000 });
|
||||||
await detailsBtn.click();
|
await detailsBtn.click();
|
||||||
|
|
||||||
await expect(page).toHaveURL(/\/ru-ru\/schedule\/KJA\/SU0634-20260519\/HKT/);
|
await expect(page).toHaveURL(
|
||||||
|
new RegExp(`/ru-ru/schedule/KJA/SU0634-${LOCAL_DATE_YMD}/HKT`),
|
||||||
|
);
|
||||||
|
|
||||||
const details = page.locator('[data-testid="schedule-leg-details"]');
|
const details = page.locator('[data-testid="schedule-leg-details"]');
|
||||||
await expect(details).toBeVisible({ timeout: 15000 });
|
await expect(details).toBeVisible({ timeout: 15000 });
|
||||||
|
|||||||
Reference in New Issue
Block a user