import { describe, expect, it } from "vitest"; import { addDays, habitDoneInPeriod, habitStreak, localDateIn, weekdayOf, weekStartOf, } from "./coach.js"; const dates = (...values: string[]) => new Set(values); describe("calendar dates", () => { it("reads the date in the user's time zone, not the server's", () => { const instant = new Date("2026-10-03T23:30:00Z"); expect(localDateIn("UTC", instant)).toBe("2026-10-03"); expect(localDateIn("Europe/Vienna", instant)).toBe("2026-10-04"); expect(localDateIn("America/Los_Angeles", instant)).toBe("2026-10-03"); expect(localDateIn("Pacific/Kiritimati", new Date("2026-10-03T10:30:00Z"))).toBe("2026-10-04"); }); it("moves across months, years and daylight saving changes by whole days", () => { expect(addDays("2026-10-31", 1)).toBe("2026-11-01"); expect(addDays("2027-01-01", -1)).toBe("2026-12-31"); expect(addDays("2026-03-28", 2)).toBe("2026-03-30"); expect(weekdayOf("2026-10-03")).toBe(6); expect(weekStartOf("2026-10-03")).toBe("2026-09-28"); expect(weekStartOf("2026-10-04")).toBe("2026-09-28"); expect(weekStartOf("2026-10-05")).toBe("2026-10-05"); }); }); describe("habit streaks", () => { const saturday = "2026-10-03"; it("counts consecutive days and keeps today open until it is done", () => { const done = dates("2026-09-30", "2026-10-01", "2026-10-02"); expect(habitStreak("daily", done, saturday)).toBe(3); expect(habitStreak("daily", new Set([...done, saturday]), saturday)).toBe(4); expect(habitStreak("daily", dates("2026-09-30", "2026-10-01"), saturday)).toBe(0); expect(habitStreak("daily", dates(), saturday)).toBe(0); }); it("skips weekends for weekday habits", () => { const monday = "2026-10-05"; const done = dates("2026-10-01", "2026-10-02"); expect(habitStreak("weekdays", done, saturday)).toBe(2); expect(habitStreak("weekdays", done, monday)).toBe(2); expect(habitStreak("weekdays", new Set([...done, monday]), monday)).toBe(3); expect(habitStreak("weekdays", dates("2026-10-01"), monday)).toBe(0); }); it("counts weeks with at least one done day for weekly habits", () => { const done = dates("2026-09-15", "2026-09-26", "2026-09-29"); expect(habitStreak("weekly", done, saturday)).toBe(3); expect(habitStreak("weekly", dates("2026-09-15", "2026-09-26"), saturday)).toBe(2); expect(habitStreak("weekly", dates("2026-09-15"), saturday)).toBe(0); }); it("reads a weekly habit as done for the rest of the week", () => { expect(habitDoneInPeriod("weekly", dates("2026-09-29"), saturday)).toBe(true); expect(habitDoneInPeriod("weekly", dates("2026-09-27"), saturday)).toBe(false); expect(habitDoneInPeriod("daily", dates("2026-10-02"), saturday)).toBe(false); expect(habitDoneInPeriod("daily", dates(saturday), saturday)).toBe(true); }); });