1c5e85ea8e
Covers one-way search, round-trip search, multi-flight details (catch-all), and airport-code-interleaved details format. Reuses online-board's flight param parser for individual flight segments.
503 lines
14 KiB
TypeScript
503 lines
14 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import {
|
|
parseScheduleRouteParams,
|
|
buildScheduleRouteParams,
|
|
parseScheduleUrl,
|
|
buildScheduleUrl,
|
|
type ScheduleParams,
|
|
} from "./url";
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// parseScheduleRouteParams
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe("parseScheduleRouteParams", () => {
|
|
it("parses route without time range or connections", () => {
|
|
expect(parseScheduleRouteParams("MOW-KUF-20220425-20220501")).toEqual({
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
});
|
|
});
|
|
|
|
it("parses route with time range", () => {
|
|
expect(parseScheduleRouteParams("MOW-KUF-20220425-20220501-06002200")).toEqual({
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
timeFrom: "0600",
|
|
timeTo: "2200",
|
|
});
|
|
});
|
|
|
|
it("parses route with connections only", () => {
|
|
expect(parseScheduleRouteParams("MOW-KUF-20220425-20220501-C1")).toEqual({
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
connections: 1,
|
|
});
|
|
});
|
|
|
|
it("parses route with connections=0", () => {
|
|
expect(parseScheduleRouteParams("MOW-KUF-20220425-20220501-C0")).toEqual({
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
connections: 0,
|
|
});
|
|
});
|
|
|
|
it("parses route with time range and connections", () => {
|
|
expect(parseScheduleRouteParams("MOW-KUF-20220425-20220501-06002200-C0")).toEqual({
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
timeFrom: "0600",
|
|
timeTo: "2200",
|
|
connections: 0,
|
|
});
|
|
});
|
|
|
|
it("returns null for empty string", () => {
|
|
expect(parseScheduleRouteParams("")).toBeNull();
|
|
});
|
|
|
|
it("returns null for insufficient segments", () => {
|
|
expect(parseScheduleRouteParams("MOW-KUF-20220425")).toBeNull();
|
|
});
|
|
|
|
it("returns null for invalid dateFrom", () => {
|
|
expect(parseScheduleRouteParams("MOW-KUF-2022-20220501")).toBeNull();
|
|
});
|
|
|
|
it("returns null for invalid dateTo", () => {
|
|
expect(parseScheduleRouteParams("MOW-KUF-20220425-2022")).toBeNull();
|
|
});
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// buildScheduleRouteParams
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe("buildScheduleRouteParams", () => {
|
|
it("builds route without time range or connections", () => {
|
|
expect(buildScheduleRouteParams({
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
})).toBe("MOW-KUF-20220425-20220501");
|
|
});
|
|
|
|
it("builds route with time range", () => {
|
|
expect(buildScheduleRouteParams({
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
timeFrom: "0600",
|
|
timeTo: "2200",
|
|
})).toBe("MOW-KUF-20220425-20220501-06002200");
|
|
});
|
|
|
|
it("builds route with connections", () => {
|
|
expect(buildScheduleRouteParams({
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
connections: 1,
|
|
})).toBe("MOW-KUF-20220425-20220501-C1");
|
|
});
|
|
|
|
it("builds route with connections=0", () => {
|
|
expect(buildScheduleRouteParams({
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
connections: 0,
|
|
})).toBe("MOW-KUF-20220425-20220501-C0");
|
|
});
|
|
|
|
it("builds route with time range and connections", () => {
|
|
expect(buildScheduleRouteParams({
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
timeFrom: "0600",
|
|
timeTo: "2200",
|
|
connections: 0,
|
|
})).toBe("MOW-KUF-20220425-20220501-06002200-C0");
|
|
});
|
|
|
|
it("omits time range when only timeFrom is provided", () => {
|
|
expect(buildScheduleRouteParams({
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
timeFrom: "0600",
|
|
})).toBe("MOW-KUF-20220425-20220501");
|
|
});
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// parseScheduleUrl
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe("parseScheduleUrl", () => {
|
|
it("parses start page (no trailing slash)", () => {
|
|
expect(parseScheduleUrl("/schedule")).toEqual({ type: "start" });
|
|
});
|
|
|
|
it("parses start page (with trailing slash)", () => {
|
|
expect(parseScheduleUrl("/schedule/")).toEqual({ type: "start" });
|
|
});
|
|
|
|
it("parses one-way route search", () => {
|
|
expect(parseScheduleUrl("/schedule/route/MOW-KUF-20220425-20220501")).toEqual({
|
|
type: "route",
|
|
outbound: {
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
},
|
|
});
|
|
});
|
|
|
|
it("parses one-way route with time range", () => {
|
|
expect(parseScheduleUrl("/schedule/route/MOW-KUF-20220425-20220501-06002200")).toEqual({
|
|
type: "route",
|
|
outbound: {
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
timeFrom: "0600",
|
|
timeTo: "2200",
|
|
},
|
|
});
|
|
});
|
|
|
|
it("parses one-way route with connections", () => {
|
|
expect(parseScheduleUrl("/schedule/route/MOW-KUF-20220425-20220501-C1")).toEqual({
|
|
type: "route",
|
|
outbound: {
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
connections: 1,
|
|
},
|
|
});
|
|
});
|
|
|
|
it("parses round-trip route search", () => {
|
|
expect(parseScheduleUrl("/schedule/route/MOW-KUF-20220425-20220501/KUF-MOW-20220502-20220508")).toEqual({
|
|
type: "roundtrip",
|
|
outbound: {
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
},
|
|
inbound: {
|
|
departure: "KUF",
|
|
arrival: "MOW",
|
|
dateFrom: "20220502",
|
|
dateTo: "20220508",
|
|
},
|
|
});
|
|
});
|
|
|
|
it("parses round-trip with time ranges", () => {
|
|
expect(parseScheduleUrl("/schedule/route/MOW-KUF-20220425-20220501-06002200/KUF-MOW-20220502-20220508-06002200")).toEqual({
|
|
type: "roundtrip",
|
|
outbound: {
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
timeFrom: "0600",
|
|
timeTo: "2200",
|
|
},
|
|
inbound: {
|
|
departure: "KUF",
|
|
arrival: "MOW",
|
|
dateFrom: "20220502",
|
|
dateTo: "20220508",
|
|
timeFrom: "0600",
|
|
timeTo: "2200",
|
|
},
|
|
});
|
|
});
|
|
|
|
it("parses round-trip with connections", () => {
|
|
expect(parseScheduleUrl("/schedule/route/MOW-KUF-20220425-20220501-C0/KUF-MOW-20220502-20220508-C0")).toEqual({
|
|
type: "roundtrip",
|
|
outbound: {
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
connections: 0,
|
|
},
|
|
inbound: {
|
|
departure: "KUF",
|
|
arrival: "MOW",
|
|
dateFrom: "20220502",
|
|
dateTo: "20220508",
|
|
connections: 0,
|
|
},
|
|
});
|
|
});
|
|
|
|
it("parses single-flight details", () => {
|
|
expect(parseScheduleUrl("/schedule/SU0012-20220527")).toEqual({
|
|
type: "details",
|
|
flights: [
|
|
{ carrier: "SU", flightNumber: "0012", date: "20220527" },
|
|
],
|
|
});
|
|
});
|
|
|
|
it("parses multi-flight details (connecting)", () => {
|
|
expect(parseScheduleUrl("/schedule/SU0012-20220501/SU0013-20220507")).toEqual({
|
|
type: "details",
|
|
flights: [
|
|
{ carrier: "SU", flightNumber: "0012", date: "20220501" },
|
|
{ carrier: "SU", flightNumber: "0013", date: "20220507" },
|
|
],
|
|
});
|
|
});
|
|
|
|
it("parses details with airport codes interleaved", () => {
|
|
// Format: /{depCode}/{flight-date}/{arrCode}/{depCode2}/{flight2-date}/{arrCode2}
|
|
// Airport codes (3-letter) are skipped, flight segments are parsed
|
|
expect(parseScheduleUrl("/schedule/SVO/SU0012-20220501/LED/LED/SU0013-20220507/SVO")).toEqual({
|
|
type: "details",
|
|
flights: [
|
|
{ carrier: "SU", flightNumber: "0012", date: "20220501" },
|
|
{ carrier: "SU", flightNumber: "0013", date: "20220507" },
|
|
],
|
|
});
|
|
});
|
|
|
|
it("returns null for empty string", () => {
|
|
expect(parseScheduleUrl("")).toBeNull();
|
|
});
|
|
|
|
it("returns null for non-schedule path", () => {
|
|
expect(parseScheduleUrl("/some/other/path")).toBeNull();
|
|
});
|
|
|
|
it("returns null for invalid route params", () => {
|
|
expect(parseScheduleUrl("/schedule/route/")).toBeNull();
|
|
});
|
|
|
|
it("handles path without leading slash", () => {
|
|
expect(parseScheduleUrl("schedule")).toEqual({ type: "start" });
|
|
});
|
|
|
|
it("handles path without leading slash for route", () => {
|
|
expect(parseScheduleUrl("schedule/route/MOW-KUF-20220425-20220501")).toEqual({
|
|
type: "route",
|
|
outbound: {
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
},
|
|
});
|
|
});
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// buildScheduleUrl
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe("buildScheduleUrl", () => {
|
|
it("builds start page URL", () => {
|
|
expect(buildScheduleUrl({ type: "start" })).toBe("schedule");
|
|
});
|
|
|
|
it("builds one-way route URL", () => {
|
|
expect(buildScheduleUrl({
|
|
type: "route",
|
|
outbound: {
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
},
|
|
})).toBe("schedule/route/MOW-KUF-20220425-20220501");
|
|
});
|
|
|
|
it("builds one-way route with time range and connections", () => {
|
|
expect(buildScheduleUrl({
|
|
type: "route",
|
|
outbound: {
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
timeFrom: "0600",
|
|
timeTo: "2200",
|
|
connections: 0,
|
|
},
|
|
})).toBe("schedule/route/MOW-KUF-20220425-20220501-06002200-C0");
|
|
});
|
|
|
|
it("builds round-trip route URL", () => {
|
|
expect(buildScheduleUrl({
|
|
type: "roundtrip",
|
|
outbound: {
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
},
|
|
inbound: {
|
|
departure: "KUF",
|
|
arrival: "MOW",
|
|
dateFrom: "20220502",
|
|
dateTo: "20220508",
|
|
},
|
|
})).toBe("schedule/route/MOW-KUF-20220425-20220501/KUF-MOW-20220502-20220508");
|
|
});
|
|
|
|
it("builds round-trip with time ranges and connections", () => {
|
|
expect(buildScheduleUrl({
|
|
type: "roundtrip",
|
|
outbound: {
|
|
departure: "MOW",
|
|
arrival: "KUF",
|
|
dateFrom: "20220425",
|
|
dateTo: "20220501",
|
|
timeFrom: "0600",
|
|
timeTo: "2200",
|
|
connections: 0,
|
|
},
|
|
inbound: {
|
|
departure: "KUF",
|
|
arrival: "MOW",
|
|
dateFrom: "20220502",
|
|
dateTo: "20220508",
|
|
timeFrom: "0600",
|
|
timeTo: "2200",
|
|
connections: 0,
|
|
},
|
|
})).toBe("schedule/route/MOW-KUF-20220425-20220501-06002200-C0/KUF-MOW-20220502-20220508-06002200-C0");
|
|
});
|
|
|
|
it("builds single-flight details URL", () => {
|
|
expect(buildScheduleUrl({
|
|
type: "details",
|
|
flights: [
|
|
{ carrier: "SU", flightNumber: "0012", date: "20220527" },
|
|
],
|
|
})).toBe("schedule/SU0012-20220527");
|
|
});
|
|
|
|
it("builds multi-flight details URL", () => {
|
|
expect(buildScheduleUrl({
|
|
type: "details",
|
|
flights: [
|
|
{ carrier: "SU", flightNumber: "0012", date: "20220501" },
|
|
{ carrier: "SU", flightNumber: "0013", date: "20220507" },
|
|
],
|
|
})).toBe("schedule/SU0012-20220501/SU0013-20220507");
|
|
});
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Roundtrip tests: build -> parse -> build
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe("roundtrip: build -> parse -> build", () => {
|
|
const cases: Array<{ name: string; params: ScheduleParams }> = [
|
|
{ name: "start", params: { type: "start" } },
|
|
{
|
|
name: "one-way route without extras",
|
|
params: {
|
|
type: "route",
|
|
outbound: { departure: "MOW", arrival: "KUF", dateFrom: "20220425", dateTo: "20220501" },
|
|
},
|
|
},
|
|
{
|
|
name: "one-way route with time range",
|
|
params: {
|
|
type: "route",
|
|
outbound: { departure: "MOW", arrival: "KUF", dateFrom: "20220425", dateTo: "20220501", timeFrom: "0600", timeTo: "2200" },
|
|
},
|
|
},
|
|
{
|
|
name: "one-way route with connections",
|
|
params: {
|
|
type: "route",
|
|
outbound: { departure: "MOW", arrival: "KUF", dateFrom: "20220425", dateTo: "20220501", connections: 1 },
|
|
},
|
|
},
|
|
{
|
|
name: "one-way route with time range and connections",
|
|
params: {
|
|
type: "route",
|
|
outbound: { departure: "MOW", arrival: "KUF", dateFrom: "20220425", dateTo: "20220501", timeFrom: "0600", timeTo: "2200", connections: 0 },
|
|
},
|
|
},
|
|
{
|
|
name: "round-trip without extras",
|
|
params: {
|
|
type: "roundtrip",
|
|
outbound: { departure: "MOW", arrival: "KUF", dateFrom: "20220425", dateTo: "20220501" },
|
|
inbound: { departure: "KUF", arrival: "MOW", dateFrom: "20220502", dateTo: "20220508" },
|
|
},
|
|
},
|
|
{
|
|
name: "round-trip with time range and connections",
|
|
params: {
|
|
type: "roundtrip",
|
|
outbound: { departure: "MOW", arrival: "KUF", dateFrom: "20220425", dateTo: "20220501", timeFrom: "0600", timeTo: "2200", connections: 0 },
|
|
inbound: { departure: "KUF", arrival: "MOW", dateFrom: "20220502", dateTo: "20220508", timeFrom: "0600", timeTo: "2200", connections: 0 },
|
|
},
|
|
},
|
|
{
|
|
name: "single-flight details",
|
|
params: {
|
|
type: "details",
|
|
flights: [{ carrier: "SU", flightNumber: "0012", date: "20220527" }],
|
|
},
|
|
},
|
|
{
|
|
name: "multi-flight details",
|
|
params: {
|
|
type: "details",
|
|
flights: [
|
|
{ carrier: "SU", flightNumber: "0012", date: "20220501" },
|
|
{ carrier: "SU", flightNumber: "0013", date: "20220507" },
|
|
],
|
|
},
|
|
},
|
|
];
|
|
|
|
for (const { name, params } of cases) {
|
|
it(`roundtrips ${name}`, () => {
|
|
const url = buildScheduleUrl(params);
|
|
const parsed = parseScheduleUrl(url);
|
|
expect(parsed).not.toBeNull();
|
|
if (parsed === null) return;
|
|
const rebuilt = buildScheduleUrl(parsed);
|
|
expect(rebuilt).toBe(url);
|
|
});
|
|
}
|
|
});
|