import { describe, it, expect } from "vitest"; import { previousMonth, defaultReferencePeriod, comparisonMeta, syncReferenceOnPeriodChange, } from "./useCompare"; describe("useCompare helpers", () => { describe("previousMonth", () => { it("goes back one month within the same year", () => { expect(previousMonth(2026, 3)).toEqual({ year: 2026, month: 2 }); expect(previousMonth(2026, 12)).toEqual({ year: 2026, month: 11 }); }); it("wraps around January to December of previous year", () => { expect(previousMonth(2026, 1)).toEqual({ year: 2025, month: 12 }); }); }); describe("defaultReferencePeriod", () => { it("returns the month before the given date", () => { expect(defaultReferencePeriod(new Date(2026, 3, 15))).toEqual({ year: 2026, month: 3 }); }); it("wraps around when today is in January", () => { expect(defaultReferencePeriod(new Date(2026, 0, 10))).toEqual({ year: 2025, month: 12 }); }); it("handles the last day of a month", () => { expect(defaultReferencePeriod(new Date(2026, 6, 31))).toEqual({ year: 2026, month: 6 }); }); }); describe("comparisonMeta", () => { it("MoM returns the previous month", () => { expect(comparisonMeta("mom", 2026, 3)).toEqual({ previousYear: 2026, previousMonth: 2 }); }); it("MoM wraps around January", () => { expect(comparisonMeta("mom", 2026, 1)).toEqual({ previousYear: 2025, previousMonth: 12 }); }); it("YoY returns the same month in the previous year", () => { expect(comparisonMeta("yoy", 2026, 3)).toEqual({ previousYear: 2025, previousMonth: 3 }); }); it("YoY for January stays on January of previous year", () => { expect(comparisonMeta("yoy", 2026, 1)).toEqual({ previousYear: 2025, previousMonth: 1 }); }); }); describe("syncReferenceOnPeriodChange", () => { // The ref is seeded with the initial `to`, so the mount call has to===last. it("no-ops on mount, preserving the previous-month default", () => { const r = syncReferenceOnPeriodChange("2026-12-31", "2026-12-31", 2026, 6); expect(r.next).toBeNull(); expect(r.lastSyncedTo).toBe("2026-12-31"); }); // StrictMode double-invokes effects in dev: calling twice with the same `to` // must not sync (a fire-once boolean would wrongly snap to December on run 2). it("is idempotent across a repeated `to` (StrictMode-safe)", () => { const a = syncReferenceOnPeriodChange("2026-12-31", "2026-12-31", 2026, 6); const b = syncReferenceOnPeriodChange(a.lastSyncedTo, "2026-12-31", 2026, 6); expect(a.next).toBeNull(); expect(b.next).toBeNull(); }); it("syncs the reference month when `to` changes (user navigation)", () => { const r = syncReferenceOnPeriodChange("2026-12-31", "2026-06-30", 2026, 12); expect(r.next).toEqual({ year: 2026, month: 6 }); expect(r.lastSyncedTo).toBe("2026-06-30"); }); it("records a changed `to` but does not dispatch when it already matches state", () => { const r = syncReferenceOnPeriodChange("2026-12-31", "2026-06-30", 2026, 6); expect(r.next).toBeNull(); expect(r.lastSyncedTo).toBe("2026-06-30"); }); it("ignores an unparseable `to`", () => { const r = syncReferenceOnPeriodChange("2026-12-31", "garbage", 2026, 6); expect(r.next).toBeNull(); expect(r.lastSyncedTo).toBe("garbage"); }); }); });