Files
pn-new-crm/tests/unit/services/document-reminders-cadence.test.ts
Matt Ciaccio 978df1c4d7 feat(reminders): cadence-aware framework with auto/manual modes
isReminderDue now keys off doc.remindersDisabled and the effective
cadence (per-doc override → template default), dropping the implicit
interests.reminderEnabled gate so non-EOI docs auto-remind correctly.
sendReminderIfAllowed gains an options bag — auto:true keeps the 9-16
window + cadence cooldown for the cron, auto:false bypasses both for
manual UI sends. signerId targets a specific pending signer (must be
next in sequential mode). 7 unit tests cover the cadence math.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 02:50:00 +02:00

71 lines
2.3 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { isReminderDue } from '@/lib/services/document-reminders';
const now = new Date('2026-04-28T12:00:00Z');
function args(overrides: Partial<Parameters<typeof isReminderDue>[0]> = {}) {
return {
status: 'sent' as const,
documensoId: 'doc-1',
remindersDisabled: false,
reminderCadenceOverride: null,
templateCadenceDays: 7,
lastReminderAt: null,
now,
...overrides,
};
}
describe('isReminderDue', () => {
it('returns true when no prior reminder exists and cadence is set', () => {
expect(isReminderDue(args())).toBe(true);
});
it('returns false when document is completed', () => {
expect(isReminderDue(args({ status: 'completed' }))).toBe(false);
});
it('returns false when document has no Documenso id', () => {
expect(isReminderDue(args({ documensoId: null }))).toBe(false);
});
it('returns false when reminders are disabled per-doc', () => {
expect(isReminderDue(args({ remindersDisabled: true }))).toBe(false);
});
it('returns false when neither override nor template cadence is set', () => {
expect(isReminderDue(args({ templateCadenceDays: null }))).toBe(false);
});
it('respects per-doc override over template default', () => {
// 1-day override, last fired 12h ago → not due
const lastReminderAt = new Date(now.getTime() - 12 * 60 * 60 * 1000);
expect(
isReminderDue(args({ templateCadenceDays: 7, reminderCadenceOverride: 1, lastReminderAt })),
).toBe(false);
// 1-day override, last fired 25h ago → due
const earlier = new Date(now.getTime() - 25 * 60 * 60 * 1000);
expect(
isReminderDue(
args({
templateCadenceDays: 7,
reminderCadenceOverride: 1,
lastReminderAt: earlier,
}),
),
).toBe(true);
});
it('treats template cadence as the fallback when no override', () => {
// 7-day template, last fired 6 days ago → not due
const lastReminderAt = new Date(now.getTime() - 6 * 24 * 60 * 60 * 1000);
expect(isReminderDue(args({ lastReminderAt }))).toBe(false);
// 7 days exactly → due
const sevenDays = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
expect(isReminderDue(args({ lastReminderAt: sevenDays }))).toBe(true);
});
});