import { expect, test } from "@playwright/test"; import { getBrusselsHour, getGreetingPeriod } from "../src/i18n/greeting"; // 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); });