Fix schedule details local date navigation
ci-deploy / build-deploy-test (push) Successful in 1m50s

This commit is contained in:
2026-05-15 21:55:55 +03:00
parent f6943a53ce
commit cac3846657
2 changed files with 184 additions and 4 deletions
@@ -138,13 +138,20 @@ export const ScheduleSearchPage: FC<ScheduleSearchPageProps> = ({ params }) => {
childIds && childIds.length > 1
? childIds
: [flight.flightId];
const buildSeg = (id: typeof flight.flightId): string =>
buildFlightUrlParams({
const buildSeg = (
id: typeof flight.flightId,
leg?: typeof allLegs[number],
): string => {
const localDate = leg?.departure.times.scheduledDeparture.local
?.slice(0, 10)
.replace(/-/g, "");
return buildFlightUrlParams({
carrier: id.carrier,
flightNumber: id.flightNumber,
...(id.suffix ? { suffix: id.suffix } : {}),
date: id.date,
date: localDate || id.date,
});
};
// Interleave airport codes between flight segments so the URL
// round-trips through `parseFlightSegments` (3-char codes are
// skipped) AND keeps Angular-compatible structure for SEO.
@@ -152,7 +159,7 @@ export const ScheduleSearchPage: FC<ScheduleSearchPageProps> = ({ params }) => {
flightIds.forEach((id, i) => {
const leg = allLegs[i] ?? allLegs[allLegs.length - 1];
if (i === 0 && leg) parts.push(leg.departure.scheduled.airportCode);
parts.push(buildSeg(id));
parts.push(buildSeg(id, leg));
if (leg) parts.push(leg.arrival.scheduled.airportCode);
});
const segment = parts.join("/");
@@ -0,0 +1,173 @@
import { test, expect } from "./fixtures/console-gate";
import {
routeAppSettingsFixture,
routeDictionaryFixtures,
} from "./helpers/api-fixtures";
// TIRREDESIGN-28: SU0634 KJA -> HKT departs after midnight local time while
// 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 details request receives 2026-05-19 and the aircraft link is rendered.
const ROUTE_URL = "/ru-ru/schedule/route/KJA-HKT-20260519-20260525-C0";
const PLANE_PARK_URL = "http://www.aeroflot.ru/cms/ru/flight/plane_park";
const su0634Search = [
{
routeType: "Direct",
operatingBy: { scheduled: "SU", operators: [] },
status: "Scheduled",
id: "su0634-kja-hkt",
flightId: {
carrier: "SU",
flightNumber: "0634",
suffix: "",
date: "2026-05-18",
dateLT: "2026-05-19",
},
flyingTime: "08:10:00",
leg: {
departure: {
scheduled: {
city: "Красноярск",
airport: "Емельяново",
countryCode: "RU",
cityCode: "KJA",
airportCode: "KJA",
},
terminal: "1",
times: {
scheduledDeparture: {
utc: "2026-05-18T22:05:00Z",
local: "2026-05-19T05:05:00+07:00",
dayChange: { value: 0, title: "" },
localTime: "05:05",
tzOffset: 420,
},
},
},
arrival: {
scheduled: {
city: "Пхукет",
airport: "Пхукет",
countryCode: "TH",
cityCode: "HKT",
airportCode: "HKT",
},
terminal: "I",
times: {
scheduledArrival: {
utc: "2026-05-19T06:15:00Z",
local: "2026-05-19T13:15:00+07:00",
dayChange: { value: 0, title: "" },
localTime: "13:15",
tzOffset: 420,
},
},
},
flags: {
checkinAvailable: false,
purchaseAvailable: true,
statusAvailable: false,
routeChanged: false,
returnToAirport: false,
},
updated: "2026-05-15T03:29:55Z",
status: "Scheduled",
operatingBy: { scheduled: "SU", operators: [] },
transition: {},
daysOfWeek: { current: "2", flight: "25" },
flyingTime: "08:10:00",
equipment: {
meal: [{ type: "Business" }, { type: "Economy" }, { type: "Comfort" }],
aircraft: {
scheduled: { type: "333", title: "Airbus A330-300" },
actualType: { type: "333", title: "Airbus A330-300" },
actual: {
type: "333",
title: "Airbus A330-300",
registration: "73786",
name: "В. Брумель",
},
},
},
trafficRestrictions: [""],
},
},
];
const su0634Details = {
data: {
routes: su0634Search,
partners: [],
daysOfFlight: ["20260515", "20260519", "20260522", "20260526"],
},
};
test("TIRREDESIGN-28: SU0634 schedule details uses local date and opens plane park", async ({
page,
context,
consoleMessages,
}) => {
await routeDictionaryFixtures(page);
await routeAppSettingsFixture(page);
await page.route("**/api/flights/v1/*/days/**/schedule/", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({ days: "1111111" }),
});
});
await page.route("**/api/flights/1/*/schedule?**", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify(su0634Search),
});
});
await page.route("**/api/flights/v1.1/*/schedule/details?**", async (route) => {
const url = new URL(route.request().url());
const date = url.searchParams.get("dates[0]");
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify(
date === "2026-05-19T00:00:00"
? su0634Details
: { data: { routes: [], partners: [], daysOfFlight: [] } },
),
});
});
await context.route(PLANE_PARK_URL, async (route) => {
await route.fulfill({
status: 200,
contentType: "text/html",
body: "<!doctype html><title>Plane park</title>",
});
});
await page.goto(ROUTE_URL);
const card = page.locator(".flight-card--clickable").first();
await expect(card).toBeVisible({ timeout: 30000 });
await card.click();
const detailsBtn = page.locator('[data-testid="flight-details-button"]');
await expect(detailsBtn).toBeVisible({ timeout: 10000 });
await detailsBtn.click();
await expect(page).toHaveURL(/\/ru-ru\/schedule\/KJA\/SU0634-20260519\/HKT/);
const details = page.locator('[data-testid="schedule-leg-details"]');
await expect(details).toBeVisible({ timeout: 15000 });
const link = details.locator("a.schedule-leg-details__link");
await expect(link).toHaveText("Airbus A330-300");
await expect(link).toHaveAttribute("href", PLANE_PARK_URL);
await expect(link).toHaveAttribute("target", "_blank");
const popupPromise = page.waitForEvent("popup");
await link.click();
const popup = await popupPromise;
await expect(popup).toHaveURL(PLANE_PARK_URL);
await popup.close();
});