import { describe, expect, it } from "vitest"; import { parseRepeat, parseWhen } from "../src/lib/when"; // A Wednesday, so weekday arithmetic has somewhere to go in both directions. const WED = new Date(2026, 7, 12); const on = (text: string): string | null => parseWhen(text, WED); describe("parseWhen", () => { it("takes an ISO date as written", () => { expect(on("2026-08-20")).toBe("2026-08-20"); expect(on("2026-8-3")).toBe("2026-08-03"); }); it("refuses a date that does not exist", () => { expect(on("2026-02-30")).toBeNull(); expect(on("2026-13-01")).toBeNull(); }); it("knows the words for the days around now", () => { expect(on("today")).toBe("2026-08-12"); expect(on("tod")).toBe("2026-08-12"); expect(on("tomorrow")).toBe("2026-08-13"); expect(on("tmr")).toBe("2026-08-13"); expect(on("yesterday")).toBe("2026-08-11"); }); it("counts forward in days, weeks and months", () => { expect(on("in 3 days")).toBe("2026-08-15"); expect(on("3 days")).toBe("2026-08-15"); expect(on("3d")).toBe("2026-08-15"); expect(on("in a week")).toBe("2026-08-19"); expect(on("2w")).toBe("2026-08-26"); expect(on("in 1 month")).toBe("2026-09-12"); expect(on("next week")).toBe("2026-08-19"); expect(on("next year")).toBe("2027-08-12"); }); it("reads a weekday as the next one, never today", () => { expect(on("friday")).toBe("2026-08-14"); expect(on("fri")).toBe("2026-08-14"); expect(on("monday")).toBe("2026-08-17"); expect(on("wednesday")).toBe("2026-08-19"); expect(on("next friday")).toBe("2026-08-14"); }); it("reads a day and a month either way round", () => { expect(on("20 aug")).toBe("2026-08-20"); expect(on("aug 20")).toBe("2026-08-20"); expect(on("20 august")).toBe("2026-08-20"); expect(on("20 aug 2027")).toBe("2027-08-20"); }); it("rolls a date that has already gone into next year", () => { expect(on("1 aug")).toBe("2027-08-01"); expect(on("1 aug 2026")).toBe("2026-08-01"); }); it("reads a numeric date day first", () => { expect(on("20.08")).toBe("2026-08-20"); expect(on("20/8")).toBe("2026-08-20"); expect(on("20.08.27")).toBe("2027-08-20"); }); it("reads a bare number as a day of the month", () => { expect(on("20")).toBe("2026-08-20"); expect(on("12")).toBe("2026-08-12"); expect(on("3")).toBe("2026-09-03"); }); it("says nothing when the words mean nothing", () => { expect(on("")).toBeNull(); expect(on(" ")).toBeNull(); expect(on("buy milk")).toBeNull(); expect(on("someday")).toBeNull(); expect(on("99")).toBeNull(); }); it("ignores case and extra spaces", () => { expect(on(" In 3 Days ")).toBe("2026-08-15"); expect(on("TOMORROW")).toBe("2026-08-13"); }); }); describe("parseRepeat", () => { it("normalises the everyday phrasings", () => { expect(parseRepeat("daily")).toBe("every day"); expect(parseRepeat("weekly")).toBe("every week"); expect(parseRepeat("monthly")).toBe("every month"); expect(parseRepeat("yearly")).toBe("every year"); expect(parseRepeat("fortnightly")).toBe("every 2 weeks"); }); it("takes a bare unit or a count", () => { expect(parseRepeat("week")).toBe("every week"); expect(parseRepeat("2 weeks")).toBe("every 2 weeks"); expect(parseRepeat("every 3 days")).toBe("every 3 days"); expect(parseRepeat("every 1 day")).toBe("every 1 day"); }); it("takes a weekday with or without the every", () => { expect(parseRepeat("monday")).toBe("every monday"); expect(parseRepeat("mondays")).toBe("every monday"); expect(parseRepeat("every tue")).toBe("every tuesday"); }); it("clears on the words for nothing", () => { expect(parseRepeat("none")).toBe(""); expect(parseRepeat("never")).toBe(""); }); it("passes an unknown every-rule through for Tasks to read", () => { expect(parseRepeat("every 2nd wednesday")).toBe("every 2nd wednesday"); expect(parseRepeat("every month on the last")).toBe("every month on the last"); }); it("says nothing when it is not a rule at all", () => { expect(parseRepeat("")).toBeNull(); expect(parseRepeat("buy milk")).toBeNull(); }); });