Files
flights_web/tests/integration/schedule/seo-integration.test.ts
T
gnezim c67686463a Add schedule parity harness, integration tests, barrel, and MF expose (Phase 3E)
Registers schedule URL serializer in parity harness with 18-entry fixture
corpus and fast-check fuzz. 10 URL round-trip integration tests, 6 SEO/
JSON-LD integration tests. Updates barrel and MF expose from stub to real.
2026-04-15 09:31:19 +03:00

112 lines
3.2 KiB
TypeScript

/**
* Integration tests for Schedule SEO + JSON-LD.
*
* Verifies SEO builders produce complete, well-formed output and
* JSON-LD schemas conform to schema.org types.
*/
import { describe, it, expect } from "vitest";
import {
buildScheduleStartSeo,
buildScheduleSearchSeo,
buildScheduleDetailsSeo,
} from "@/features/schedule/seo.js";
import {
buildScheduleFlightJsonLd,
buildScheduleFlightListJsonLd,
} from "@/features/schedule/json-ld.js";
import { SCHEDULE_FLIGHT_1, SCHEDULE_FLIGHT_2 } from "./fixtures.js";
import type { IScheduleFlightId } from "@/features/schedule/types.js";
function stubT(key: string, opts?: Record<string, unknown>): string {
if (opts && Object.keys(opts).length > 0) {
const vars = Object.entries(opts)
.map(([k, v]) => `${k}=${v}`)
.join(",");
return `${key}|${vars}`;
}
return key;
}
const CANONICAL = "https://www.aeroflot.ru";
describe("Schedule SEO integration", () => {
it("start page SEO has all required fields", () => {
const result = buildScheduleStartSeo(stubT, "ru", CANONICAL);
expect(result.title).toBeTruthy();
expect(result.description).toBeTruthy();
expect(result.canonical).toBeTruthy();
expect(result.og).toBeDefined();
expect(result.hreflang).toBeDefined();
expect(result.hreflang).toHaveLength(10);
});
it("search page SEO canonical matches route format", () => {
const params = {
type: "route" as const,
outbound: {
departure: "SVO",
arrival: "LED",
dateFrom: "20250115",
dateTo: "20250122",
},
};
const result = buildScheduleSearchSeo(stubT, params, "ru", CANONICAL);
expect(result.canonical).toBe(
"https://www.aeroflot.ru/ru/schedule/route/SVO-LED-20250115-20250122",
);
});
it("details page SEO uses article og type", () => {
const flightIds: IScheduleFlightId[] = [
{ carrier: "SU", flightNumber: "0012", date: "20220527" },
];
const result = buildScheduleDetailsSeo(
stubT,
[SCHEDULE_FLIGHT_1],
"ru",
CANONICAL,
flightIds,
);
expect(result.og.type).toBe("article");
});
});
describe("Schedule JSON-LD integration", () => {
it("single flight produces valid Flight schema", () => {
const jsonLd = buildScheduleFlightJsonLd(SCHEDULE_FLIGHT_1);
expect(jsonLd["@type"]).toBe("Flight");
expect(jsonLd.flightNumber).toBe("SU0012");
expect(jsonLd.departureAirport).toBeDefined();
expect(jsonLd.arrivalAirport).toBeDefined();
});
it("flight list produces valid ItemList schema", () => {
const jsonLd = buildScheduleFlightListJsonLd(
[SCHEDULE_FLIGHT_1, SCHEDULE_FLIGHT_2],
"Schedule SVO to LED",
);
expect(jsonLd["@type"]).toBe("ItemList");
expect(jsonLd.description).toBe("Schedule SVO to LED");
const items = jsonLd.itemListElement as unknown as Array<{ position: number }>;
expect(items).toHaveLength(2);
expect(items[0]).toHaveProperty("position", 1);
expect(items[1]).toHaveProperty("position", 2);
});
it("empty flight list produces valid ItemList", () => {
const jsonLd = buildScheduleFlightListJsonLd([], "No flights");
expect(jsonLd["@type"]).toBe("ItemList");
expect(jsonLd.itemListElement).toEqual([]);
});
});