This commit is contained in:
@@ -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();
|
||||
});
|
||||
Reference in New Issue
Block a user