) => {
+ if (vars) {
+ return Object.entries(vars).reduce(
+ (s: string, [k, v]) => s.replace(`{${k}}`, String(v)),
+ key,
+ );
+ }
+ return key;
+ },
+ }),
+}));
+
+vi.mock("@/i18n/resolver.js", () => ({
+ localeToLanguage: () => "ru",
+ normalizeLocaleParam: (l: string) => l,
+ DEFAULT_LANGUAGE: "ru",
+}));
+
+vi.mock("../hooks/useScheduleDetails.js", () => ({
+ useScheduleDetails: () => ({ flights: [], loading: true, error: null }),
+}));
+
+vi.mock("../seo.js", () => ({
+ buildScheduleDetailsSeo: () => ({}),
+}));
+
+vi.mock("@/ui/layout/PageLayout.js", () => ({
+ PageLayout: ({
+ children,
+ breadcrumbs,
+ }: {
+ children?: React.ReactNode;
+ breadcrumbs?: { label: string; url?: string }[];
+ }) => (
+
+
+ {breadcrumbs?.map((b, i) => (
+
+ {b.label}
+
+ ))}
+
+ {children}
+
+ ),
+}));
+
+vi.mock("@/ui/layout/PageTabs.js", () => ({
+ PageTabs: () =>
,
+}));
+
+vi.mock("@/ui/flights/FlightListSkeleton.js", () => ({
+ FlightListSkeleton: () =>
,
+}));
+
+vi.mock("@/ui/seo/SeoHead.js", () => ({
+ SeoHead: () => null,
+}));
+
+// ---------------------------------------------------------------------------
+
+const flightId: IScheduleFlightId = {
+ carrier: "SU",
+ flightNumber: "1234",
+ date: "20260515",
+};
+
+describe("ScheduleDetailsPage breadcrumbs", () => {
+ beforeEach(() => {
+ mockSearchParamsGet = () => null;
+ });
+
+ it("shows 1-item trail when no ?request= param (share-link)", () => {
+ render(
+ ,
+ );
+ expect(screen.queryByTestId("crumb-0")).toBeTruthy();
+ expect(screen.queryByTestId("crumb-1")).toBeNull();
+ });
+
+ it("shows 2-item trail with route leaf when ?request= carries schedule area (one-way)", () => {
+ mockSearchParamsGet = (k) =>
+ k === "request"
+ ? "schedule-route-NBC-KHV-20220307-20220313"
+ : null;
+
+ render(
+ ,
+ );
+
+ const crumb0 = screen.getByTestId("crumb-0");
+ const crumb1 = screen.getByTestId("crumb-1");
+ expect(crumb0.textContent).toContain("SCHEDULE.TITLE");
+ // Leaf label key is BREADCRUMBS.SCHEDULE-ROUTE (the mock t() returns the
+ // key since it has no literal {…} placeholders in the key string itself)
+ expect(crumb1.textContent).toContain("BREADCRUMBS.SCHEDULE-ROUTE");
+ // Back URL must rebuild a schedule search URL with the IATA codes
+ const backUrl = crumb1.getAttribute("data-url") ?? "";
+ expect(backUrl).toContain("/schedule/");
+ expect(backUrl).toContain("NBC");
+ expect(backUrl).toContain("KHV");
+ });
+
+ it("ignores ?request= that carries onlineboard area", () => {
+ mockSearchParamsGet = (k) =>
+ k === "request"
+ ? "onlineboard-route-MOW-LED-20260515"
+ : null;
+
+ render(
+ ,
+ );
+
+ // Should stay at 1-item trail — no leaf
+ expect(screen.getByTestId("crumb-0")).toBeTruthy();
+ expect(screen.queryByTestId("crumb-1")).toBeNull();
+ });
+});
diff --git a/src/features/schedule/components/ScheduleDetailsPage.tsx b/src/features/schedule/components/ScheduleDetailsPage.tsx
index 786ff7e0..95392e13 100644
--- a/src/features/schedule/components/ScheduleDetailsPage.tsx
+++ b/src/features/schedule/components/ScheduleDetailsPage.tsx
@@ -268,7 +268,7 @@ export const ScheduleDetailsPage: FC = ({
}
title={{title} }
- breadcrumbs={[{ label: t("SCHEDULE.TITLE"), url: scheduleHref }]}
+ breadcrumbs={breadcrumbs}
>
{/* Angular renders `flight-details-full-route` once at the top for