| 1 | // @effect-diagnostics globalDate:off -- Tests exercise local calendar and elapsed-time snooze input. |
| 2 | import { afterEach, describe, expect, it, vi } from "vite-plus/test"; |
| 3 | import { localSnoozeDate, localSnoozeTime, resolveCustomSnooze } from "./threadSettled.ts"; |
| 4 | |
| 5 | const now = new Date(2026, 8, 14, 14, 30); |
| 6 | |
| 7 | afterEach(() => vi.unstubAllEnvs()); |
| 8 | |
| 9 | describe("custom snooze", () => { |
| 10 | it("converts local date and time to an absolute wake time", () => { |
| 11 | expect(resolveCustomSnooze({ mode: "date", date: "2026-09-15", time: "09:15" }, now)).toBe( |
| 12 | new Date(2026, 8, 15, 9, 15).toISOString(), |
| 13 | ); |
| 14 | }); |
| 15 | |
| 16 | it.each([ |
| 17 | ["2026-09-14", "14:30"], |
| 18 | ["2026-09-13", "09:00"], |
| 19 | ["2027-02-29", "09:00"], |
| 20 | ["2026-13-01", "09:00"], |
| 21 | ["2026-09-15", "24:00"], |
| 22 | ["2026-09-15", "09:60"], |
| 23 | ["", "09:00"], |
| 24 | ["2026-09-15", ""], |
| 25 | ])("rejects invalid or non-future calendar input %s %s", (date, time) => { |
| 26 | expect(resolveCustomSnooze({ mode: "date", date, time }, now)).toBeNull(); |
| 27 | }); |
| 28 | |
| 29 | it.each([ |
| 30 | ["minutes", "45", 45 * 60_000], |
| 31 | ["hours", "1.5", 90 * 60_000], |
| 32 | ["days", "2", 48 * 3_600_000], |
| 33 | ] as const)("resolves %s from the confirmation time", (unit, amount, elapsed) => { |
| 34 | const confirmedAt = new Date(now.getTime() + 5 * 60_000); |
| 35 | expect(resolveCustomSnooze({ mode: "duration", amount, unit }, confirmedAt)).toBe( |
| 36 | new Date(confirmedAt.getTime() + elapsed).toISOString(), |
| 37 | ); |
| 38 | }); |
| 39 | |
| 40 | it.each(["", "0", "-1", "NaN", "Infinity", "1e300"])("rejects invalid duration %s", (amount) => { |
| 41 | expect(resolveCustomSnooze({ mode: "duration", amount, unit: "hours" }, now)).toBeNull(); |
| 42 | }); |
| 43 | |
| 44 | it("rejects nonexistent local times at the spring DST transition", () => { |
| 45 | vi.stubEnv("TZ", "America/Los_Angeles"); |
| 46 | expect( |
| 47 | resolveCustomSnooze( |
| 48 | { mode: "date", date: "2027-03-14", time: "02:30" }, |
| 49 | new Date("2027-03-01T00:00:00Z"), |
| 50 | ), |
| 51 | ).toBeNull(); |
| 52 | }); |
| 53 | |
| 54 | it("treats duration days as 24 hours across DST", () => { |
| 55 | vi.stubEnv("TZ", "America/Los_Angeles"); |
| 56 | const before = new Date(2027, 2, 13, 12); |
| 57 | const wake = resolveCustomSnooze({ mode: "duration", amount: "1", unit: "days" }, before); |
| 58 | expect(wake).toBe(new Date(2027, 2, 14, 13).toISOString()); |
| 59 | }); |
| 60 | |
| 61 | it("formats local input values without converting to UTC", () => { |
| 62 | const date = new Date(2026, 0, 2, 3, 4); |
| 63 | expect(localSnoozeDate(date)).toBe("2026-01-02"); |
| 64 | expect(localSnoozeTime(date)).toBe("03:04"); |
| 65 | }); |
| 66 | }); |