diff --git a/src/routes/[lang]/onlineboard/_guards.test.ts b/src/routes/[lang]/onlineboard/_guards.test.ts new file mode 100644 index 00000000..dcc9c46f --- /dev/null +++ b/src/routes/[lang]/onlineboard/_guards.test.ts @@ -0,0 +1,42 @@ +/** + * Unit tests for boardDateRedirect guard utility. + * + * Clock frozen at 2026-05-15 (noon local). Board window: 2026-05-14 … 2026-05-29. + */ + +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { boardDateRedirect } from "./_guards.js"; + +describe("boardDateRedirect (clock frozen 2026-05-15)", () => { + beforeEach(() => { + vi.useFakeTimers(); + vi.setSystemTime(new Date(2026, 4, 15, 12)); // May 15 2026 noon + }); + afterEach(() => { + vi.useRealTimers(); + }); + + it("returns null for a date inside the window (today)", () => { + expect(boardDateRedirect("ru-ru", "20260515")).toBeNull(); + }); + + it("returns null for the earliest allowed date (today - 1)", () => { + expect(boardDateRedirect("ru-ru", "20260514")).toBeNull(); + }); + + it("returns null for the latest allowed date (today + 14)", () => { + expect(boardDateRedirect("ru-ru", "20260529")).toBeNull(); + }); + + it("redirects when date is too early (today - 2)", () => { + expect(boardDateRedirect("ru-ru", "20260513")).toBe("/ru-ru/onlineboard"); + }); + + it("redirects when date is too late (today + 15)", () => { + expect(boardDateRedirect("ru-ru", "20260530")).toBe("/ru-ru/onlineboard"); + }); + + it("uses the supplied locale in the redirect path", () => { + expect(boardDateRedirect("en-us", "20260101")).toBe("/en-us/onlineboard"); + }); +}); diff --git a/src/routes/[lang]/onlineboard/_guards.ts b/src/routes/[lang]/onlineboard/_guards.ts new file mode 100644 index 00000000..22a39215 --- /dev/null +++ b/src/routes/[lang]/onlineboard/_guards.ts @@ -0,0 +1,19 @@ +/** + * Shared date-window guard for Online-Board routes per TZ §4.1.2 ¶3-4. + * + * Out-of-window dates redirect to the Online-Board start page instead of 404. + * Parse failures (malformed URLs) continue to produce 404 via existing logic. + */ + +import { isInBoardWindow } from "@/shared/dateWindow.js"; + +/** + * Returns the redirect target path when the given yyyymmdd date falls outside + * the Online-Board [-1, +14] day window. Returns null to allow normal render. + * + * Only called after a successful URL parse — malformed dates never reach here. + */ +export function boardDateRedirect(locale: string, yyyymmdd: string): string | null { + if (!isInBoardWindow(yyyymmdd)) return `/${locale}/onlineboard`; + return null; +}