1// @effect-diagnostics globalDate:off -- Tests exercise local calendar and elapsed-time snooze input.
2import { afterEach, describe, expect, it, vi } from "vite-plus/test";
3import { localSnoozeDate, localSnoozeTime, resolveCustomSnooze } from "./threadSettled.ts";
4
5const now = new Date(2026, 8, 14, 14, 30);
6
7afterEach(() => vi.unstubAllEnvs());
8
9describe("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});