Files
MobilityOps/frontend/e2e/greeting.spec.ts
NuklearRabbit 81e3fd63bd
MobilityOps acceptance / backend (push) Failing after 19s
MobilityOps acceptance / frontend (push) Successful in 25s
MobilityOps acceptance / e2e (push) Skipped
M54: harden operations and demo resilience
2026-08-24 03:31:03 +02:00

84 lines
4.3 KiB
TypeScript

import { expect, test } from "@playwright/test";
import { getBrusselsHour, getGreetingPeriod } from "../src/i18n/greeting";
import { brusselsLocalToIso, toBrusselsDate, tryBrusselsLocalToIso } from "../src/i18n/brusselsDateTime";
// Pure Node-context boundary tests for the central, clock-injectable greeting function
// (section 9 of the Fleet Ops final localization brief). Every case below constructs an
// explicit UTC instant that corresponds to a specific Europe/Brussels wall-clock time --
// this is what "clock injection" buys: no real time needs to pass, and DST is exercised
// by picking instants either side of the CET/CEST transition.
// 2026-01-15 is CET (UTC+1): 04:59 Brussels = 03:59 UTC.
function cet(hour: number, minute = 0): Date {
return new Date(Date.UTC(2026, 0, 15, hour - 1, minute));
}
// 2026-07-15 is CEST (UTC+2): 04:59 Brussels = 02:59 UTC.
function cest(hour: number, minute = 0): Date {
return new Date(Date.UTC(2026, 6, 15, hour - 2, minute));
}
test("period boundaries are correct in winter time (CET, UTC+1)", () => {
expect(getGreetingPeriod(cet(4, 59))).toBe("night");
expect(getGreetingPeriod(cet(5, 0))).toBe("morning");
expect(getGreetingPeriod(cet(11, 59))).toBe("morning");
expect(getGreetingPeriod(cet(12, 0))).toBe("afternoon");
expect(getGreetingPeriod(cet(17, 59))).toBe("afternoon");
expect(getGreetingPeriod(cet(18, 0))).toBe("evening");
expect(getGreetingPeriod(cet(22, 59))).toBe("evening");
expect(getGreetingPeriod(cet(23, 0))).toBe("night");
});
test("period boundaries are correct in summer time (CEST, UTC+2)", () => {
expect(getGreetingPeriod(cest(4, 59))).toBe("night");
expect(getGreetingPeriod(cest(5, 0))).toBe("morning");
expect(getGreetingPeriod(cest(11, 59))).toBe("morning");
expect(getGreetingPeriod(cest(12, 0))).toBe("afternoon");
expect(getGreetingPeriod(cest(17, 59))).toBe("afternoon");
expect(getGreetingPeriod(cest(18, 0))).toBe("evening");
expect(getGreetingPeriod(cest(22, 59))).toBe("evening");
expect(getGreetingPeriod(cest(23, 0))).toBe("night");
});
test("DST transition (2026-03-29, clocks spring forward 02:00 -> 03:00 CEST): the Brussels hour never regresses or skips a period incorrectly", () => {
// 00:30 UTC = 01:30 CET, still "night" (before the 05:00 boundary regardless).
const beforeTransition = new Date(Date.UTC(2026, 2, 29, 0, 30));
expect(getBrusselsHour(beforeTransition)).toBe(1);
expect(getGreetingPeriod(beforeTransition)).toBe("night");
// 09:00 UTC on transition day = 11:00 CEST (already sprung forward) -- still morning.
const afterTransition = new Date(Date.UTC(2026, 2, 29, 9, 0));
expect(getBrusselsHour(afterTransition)).toBe(11);
expect(getGreetingPeriod(afterTransition)).toBe("morning");
// Autumn transition, 2026-10-25: fall-back happens at 01:00 UTC (03:00 CEST -> 02:00
// CET), so 00:30 UTC is still CEST -> 02:30 Brussels.
const beforeFallBack = new Date(Date.UTC(2026, 9, 25, 0, 30));
expect(getBrusselsHour(beforeFallBack)).toBe(2);
expect(getGreetingPeriod(beforeFallBack)).toBe("night");
// 09:00 UTC on fall-back day = 10:00 CET (already fallen back) -- still morning.
const afterFallBack = new Date(Date.UTC(2026, 9, 25, 9, 0));
expect(getBrusselsHour(afterFallBack)).toBe(10);
expect(getGreetingPeriod(afterFallBack)).toBe("morning");
});
test("default argument uses the real current time when no clock is injected", () => {
const period = getGreetingPeriod();
expect(["morning", "afternoon", "evening", "night"]).toContain(period);
});
test("Brussels wall-clock conversion is DST-aware and rejects impossible local times", () => {
expect(brusselsLocalToIso("2026-01-15T12:00")).toBe("2026-01-15T11:00:00.000Z");
expect(brusselsLocalToIso("2026-07-15T12:00")).toBe("2026-07-15T10:00:00.000Z");
expect(tryBrusselsLocalToIso("2026-03-29T02:30")).toBeNull();
expect(tryBrusselsLocalToIso("2026-02-30T12:00")).toBeNull();
// The repeated autumn hour resolves deterministically to the post-transition CET instant.
expect(brusselsLocalToIso("2026-10-25T02:30")).toBe("2026-10-25T01:30:00.000Z");
});
test("Brussels calendar dates do not depend on the browser or runner timezone", () => {
expect(toBrusselsDate(new Date("2026-01-01T23:30:00.000Z"))).toBe("2026-01-02");
expect(toBrusselsDate(new Date("2026-07-01T22:30:00.000Z"))).toBe("2026-07-02");
});