feat(11-02): Task 2 — humanizeLeadMinutes tests + body dispatch assertion (D-09)
- Add 8 bucket tests: 30→'30 min', 59→'59 min', 60→'1 hr', 90→'1 hr', 120→'2 hrs', 1440→'1 day', 2880→'2 days', 10080→'7 days' - Add body-in-dispatch test: 1440-min lead → body='Starts in 1 day' (driven by configured lead, not live minutes-to-start delta) - humanizeLeadMinutes implementation already committed in Task 1 GREEN - All 23 tests GREEN
This commit is contained in:
@@ -567,6 +567,91 @@ describe('reminderScheduler — CR-01: sentReminders Map pruning', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ── D-09: humanizeLeadMinutes body formatter ─────────────────────────────────
|
||||
|
||||
describe('humanizeLeadMinutes — D-09 humanized push body formatter', () => {
|
||||
it('maps 30 min → "Starts in 30 min"', async () => {
|
||||
const { humanizeLeadMinutes } = await import('../../src/broker/reminderScheduler.js');
|
||||
expect(humanizeLeadMinutes(30)).toBe('Starts in 30 min');
|
||||
});
|
||||
|
||||
it('maps 59 min → "Starts in 59 min" (< 60 bucket)', async () => {
|
||||
const { humanizeLeadMinutes } = await import('../../src/broker/reminderScheduler.js');
|
||||
expect(humanizeLeadMinutes(59)).toBe('Starts in 59 min');
|
||||
});
|
||||
|
||||
it('maps 60 min → "Starts in 1 hour"', async () => {
|
||||
const { humanizeLeadMinutes } = await import('../../src/broker/reminderScheduler.js');
|
||||
expect(humanizeLeadMinutes(60)).toBe('Starts in 1 hour');
|
||||
});
|
||||
|
||||
it('maps 90 min → "Starts in 1 hour" (60–119 bucket, not 2 hours)', async () => {
|
||||
// Math.round(90/60)=2 would give "2 hours" — branch ordering must prevent this
|
||||
const { humanizeLeadMinutes } = await import('../../src/broker/reminderScheduler.js');
|
||||
expect(humanizeLeadMinutes(90)).toBe('Starts in 1 hour');
|
||||
});
|
||||
|
||||
it('maps 120 min → "Starts in 2 hours"', async () => {
|
||||
const { humanizeLeadMinutes } = await import('../../src/broker/reminderScheduler.js');
|
||||
expect(humanizeLeadMinutes(120)).toBe('Starts in 2 hours');
|
||||
});
|
||||
|
||||
it('maps 1440 min → "Starts in 1 day"', async () => {
|
||||
const { humanizeLeadMinutes } = await import('../../src/broker/reminderScheduler.js');
|
||||
expect(humanizeLeadMinutes(1440)).toBe('Starts in 1 day');
|
||||
});
|
||||
|
||||
it('maps 2880 min → "Starts in 2 days"', async () => {
|
||||
const { humanizeLeadMinutes } = await import('../../src/broker/reminderScheduler.js');
|
||||
expect(humanizeLeadMinutes(2880)).toBe('Starts in 2 days');
|
||||
});
|
||||
|
||||
it('maps 10080 min → "Starts in 7 days"', async () => {
|
||||
const { humanizeLeadMinutes } = await import('../../src/broker/reminderScheduler.js');
|
||||
expect(humanizeLeadMinutes(10080)).toBe('Starts in 7 days');
|
||||
});
|
||||
});
|
||||
|
||||
describe('reminderScheduler — D-09: humanized push body in dispatch', () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('dispatched notification body is humanized from configured lead (not live minutes-to-start)', async () => {
|
||||
// D-09: body driven by event.reminderLeadMinutes (DB ground truth), not by (dtstart - now)
|
||||
// A 1440-min (1 day) lead event should produce "Starts in 1 day", not "Starts in 30 min"
|
||||
const now = new Date('2026-06-15T10:00:00Z');
|
||||
vi.setSystemTime(now);
|
||||
|
||||
const { db } = await import('../../src/db/client.js');
|
||||
const { dispatchPush } = await import('../../src/lib/pushDispatcher.js');
|
||||
const { runReminderCheck } = await import('../../src/broker/reminderScheduler.js');
|
||||
|
||||
// Event exactly 1440 min (1 day) from now → fire time = dtstartUtc - 1440min = now
|
||||
const dtstartUtc = new Date('2026-06-16T10:00:00Z'); // tomorrow 10:00Z
|
||||
const row = makeEventRow({
|
||||
uid: 'humanize-body-uid',
|
||||
title: 'Meeting Tomorrow',
|
||||
dtstartUtc,
|
||||
reminderLeadMinutes: 1440,
|
||||
});
|
||||
|
||||
mockTwoQueries(vi.mocked(db), [row]);
|
||||
await runReminderCheck(now);
|
||||
|
||||
expect(vi.mocked(dispatchPush)).toHaveBeenCalledOnce();
|
||||
const [, payload] = vi.mocked(dispatchPush).mock.calls[0]!;
|
||||
// Body must be "Starts in 1 day" (configured lead), not "Starts in 1470 min" (live delta)
|
||||
expect((payload as { body: string }).body).toBe('Starts in 1 day');
|
||||
});
|
||||
});
|
||||
|
||||
// ── T-05-19: per-subscription error isolation ────────────────────────────────
|
||||
|
||||
describe('reminderScheduler — T-05-19: per-subscription error isolation', () => {
|
||||
|
||||
Reference in New Issue
Block a user