// Pure-logic tests for the expiry-reminder cadence: which reminder kind // (if any) applies to a relay subscription row right now. The send/dedup // path hits SQLite + SMTP and isn't unit-tested here; this nails the // decision that drives it. import { test, describe } from "node:test"; import assert from "node:assert/strict"; import { reminderKindFor } from "../subscription-reminders.js"; const sub = (days_left, expired = false) => ({ tier: "pro", expires_at: "2026-07-01T00:00:00.000Z", expired, days_left, }); describe("reminderKindFor", () => { test("upcoming: smallest crossed threshold wins", () => { assert.equal(reminderKindFor(sub(8)), null); // beyond 7d assert.equal(reminderKindFor(sub(7)), "upcoming_7d"); assert.equal(reminderKindFor(sub(5)), "upcoming_7d"); assert.equal(reminderKindFor(sub(2)), "upcoming_7d"); assert.equal(reminderKindFor(sub(1)), "upcoming_1d"); assert.equal(reminderKindFor(sub(0)), "upcoming_1d"); // expires today, not yet lapsed }); test("lapsed: only within the lapsed window", () => { assert.equal(reminderKindFor(sub(0, true)), "lapsed"); assert.equal(reminderKindFor(sub(-1, true)), "lapsed"); assert.equal(reminderKindFor(sub(-3, true)), "lapsed"); assert.equal(reminderKindFor(sub(-4, true)), null); // aged out (window=3) }); test("null-safe / malformed input", () => { assert.equal(reminderKindFor(null), null); assert.equal(reminderKindFor({}), null); assert.equal(reminderKindFor({ expired: false }), null); // no days_left assert.equal(reminderKindFor({ days_left: "soon" }), null); }); test("respects custom thresholds", () => { const upcoming = [ { days: 14, kind: "upcoming_14d" }, { days: 3, kind: "upcoming_3d" }, ]; assert.equal(reminderKindFor(sub(14), { upcoming }), "upcoming_14d"); assert.equal(reminderKindFor(sub(3), { upcoming }), "upcoming_3d"); assert.equal(reminderKindFor(sub(15), { upcoming }), null); }); });