Skip to content

Commit 02b8780

Browse files
committed
test: add isoWeekToMonday boundary tests and fix render test mock
- Extract isoWeekToMonday to deployer/week.ts for reuse and testability - Add boundary value tests: year boundaries (W1 2025/2026), W53 (2020), Jan 1 Monday (2024 W1), last week of year (W52 2026) - Fix render.test.ts mock to pass through real isoWeekToMonday - Verify card dateRange E2E: weekId -> isoWeekToMonday -> formatted output
1 parent b829c04 commit 02b8780

4 files changed

Lines changed: 78 additions & 12 deletions

File tree

src/cli/commands/render.test.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,14 @@ vi.mock("../../renderer/rss.js", () => ({
4747
buildRSSFeed: (...args: unknown[]) => mockBuildRSSFeed(...args),
4848
}));
4949

50-
// Mock week
51-
vi.mock("../../deployer/week.js", () => ({
52-
getWeekId: () => ({ year: 2026, week: 14, path: "2026/W14" }),
53-
}));
50+
// Mock week (keep real isoWeekToMonday)
51+
vi.mock("../../deployer/week.js", async (importOriginal) => {
52+
const actual = await importOriginal<typeof import("../../deployer/week.js")>();
53+
return {
54+
...actual,
55+
getWeekId: () => ({ year: 2026, week: 14, path: "2026/W14" }),
56+
};
57+
});
5458

5559
const GITHUB_DATA_YAML = `
5660
username: testuser

src/cli/commands/render.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { join } from "node:path";
66
import { parse as parseYaml } from "yaml";
77
import { renderReport } from "../../renderer/index.js";
88
import { renderIndexPage, buildReportEntry, type ReportEntry } from "../../deployer/index-page.js";
9-
import { getWeekId } from "../../deployer/week.js";
9+
import { getWeekId, isoWeekToMonday } from "../../deployer/week.js";
1010
import { parseLocalDate } from "../../collector/date-range.js";
1111
import { generateOGImage, generateIndexOGImage } from "../../renderer/og-image.js";
1212
import { generateCard, generateDarkCard } from "../../renderer/card.js";
@@ -175,12 +175,6 @@ const run = async (options: RenderOptions): Promise<void> => {
175175

176176
// Generate animated SVG summary cards (light + dark)
177177
// Compute Mon-Sun date range from ISO week number (independent of data file)
178-
const isoWeekToMonday = (year: number, week: number): Date => {
179-
const jan4 = new Date(Date.UTC(year, 0, 4));
180-
const dow = jan4.getUTCDay() || 7;
181-
const w1Mon = new Date(jan4.getTime() - (dow - 1) * 86_400_000);
182-
return new Date(w1Mon.getTime() + (week - 1) * 7 * 86_400_000);
183-
};
184178
const fmtShort = (d: Date): string =>
185179
d.toLocaleDateString("en-US", { month: "short", day: "numeric", timeZone: "UTC" });
186180
const monday = isoWeekToMonday(weekId.year, weekId.week);

src/deployer/week.test.ts

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, it, expect } from "vitest";
2-
import { getWeekId, getCurrentWeekId } from "./week.js";
2+
import { getWeekId, getCurrentWeekId, isoWeekToMonday } from "./week.js";
33

44
describe("getWeekId", () => {
55
// -------------------------------------------------------------------
@@ -220,3 +220,63 @@ describe("getCurrentWeekId", () => {
220220
expect(result.path).toBe("2026/W01");
221221
});
222222
});
223+
224+
describe("isoWeekToMonday", () => {
225+
const dayOfWeek = (d: Date): string =>
226+
d.toLocaleDateString("en-US", { weekday: "long", timeZone: "UTC" });
227+
const fmt = (d: Date): string =>
228+
d.toISOString().slice(0, 10);
229+
230+
it("returns Monday for 2026 W14 (Mar 30)", () => {
231+
const mon = isoWeekToMonday(2026, 14);
232+
expect(fmt(mon)).toBe("2026-03-30");
233+
expect(dayOfWeek(mon)).toBe("Monday");
234+
});
235+
236+
it("returns Monday for 2026 W1 (Dec 29, 2025)", () => {
237+
// ISO 2026 W1 starts on Mon Dec 29 2025
238+
const mon = isoWeekToMonday(2026, 1);
239+
expect(fmt(mon)).toBe("2025-12-29");
240+
expect(dayOfWeek(mon)).toBe("Monday");
241+
});
242+
243+
it("returns Monday for 2025 W1 (Dec 30, 2024)", () => {
244+
const mon = isoWeekToMonday(2025, 1);
245+
expect(fmt(mon)).toBe("2024-12-30");
246+
expect(dayOfWeek(mon)).toBe("Monday");
247+
});
248+
249+
it("handles 2024 W1 (Jan 1, 2024 is Monday)", () => {
250+
const mon = isoWeekToMonday(2024, 1);
251+
expect(fmt(mon)).toBe("2024-01-01");
252+
expect(dayOfWeek(mon)).toBe("Monday");
253+
});
254+
255+
it("handles last week of year: 2026 W52", () => {
256+
const mon = isoWeekToMonday(2026, 52);
257+
expect(fmt(mon)).toBe("2026-12-21");
258+
expect(dayOfWeek(mon)).toBe("Monday");
259+
});
260+
261+
it("handles W53 in a long year (2020 has 53 weeks)", () => {
262+
const mon = isoWeekToMonday(2020, 53);
263+
expect(fmt(mon)).toBe("2020-12-28");
264+
expect(dayOfWeek(mon)).toBe("Monday");
265+
});
266+
267+
it("Sunday is always 6 days after Monday", () => {
268+
const cases = [
269+
{ year: 2026, week: 1 },
270+
{ year: 2026, week: 14 },
271+
{ year: 2026, week: 52 },
272+
{ year: 2020, week: 53 },
273+
{ year: 2024, week: 1 },
274+
];
275+
cases.forEach(({ year, week }) => {
276+
const mon = isoWeekToMonday(year, week);
277+
const sun = new Date(mon.getTime() + 6 * 86_400_000);
278+
expect(dayOfWeek(mon)).toBe("Monday");
279+
expect(dayOfWeek(sun)).toBe("Sunday");
280+
});
281+
});
282+
});

src/deployer/week.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ export const getWeekId = (
3434

3535
// Current ISO week ID. Used by daily-fetch to store events for the
3636
// week that is still in progress.
37+
// Monday (00:00 UTC) of the given ISO week. Week 1 contains January 4.
38+
export const isoWeekToMonday = (year: number, week: number): Date => {
39+
const jan4 = new Date(Date.UTC(year, 0, 4));
40+
const dow = jan4.getUTCDay() || 7;
41+
const w1Mon = new Date(jan4.getTime() - (dow - 1) * 86_400_000);
42+
return new Date(w1Mon.getTime() + (week - 1) * 7 * 86_400_000);
43+
};
44+
3745
export const getCurrentWeekId = (
3846
date: Date = new Date(),
3947
timezone: string = "UTC",

0 commit comments

Comments
 (0)