parseRecipientConfig (backward-compat: legacy string[] -> emails) + resolveRecipientEmails (expands userIds/roleIds/everyone-with-interests.view into deduped addresses) + resolveNotificationRecipients (load setting, fallback to inquiry_contact_email). Wired into the website-intake email path so berth/contact/residential staff alerts honor the richer recipients. TDD: parseRecipientConfig unit tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
48 lines
1.4 KiB
TypeScript
48 lines
1.4 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
|
|
import { parseRecipientConfig } from '@/lib/services/notification-recipients';
|
|
|
|
describe('parseRecipientConfig', () => {
|
|
it('treats a legacy string[] as explicit emails (backward-compat)', () => {
|
|
expect(parseRecipientConfig(['a@x.com', 'b@x.com'])).toEqual({
|
|
emails: ['a@x.com', 'b@x.com'],
|
|
userIds: [],
|
|
roleIds: [],
|
|
everyone: false,
|
|
});
|
|
});
|
|
|
|
it('reads the structured object shape', () => {
|
|
expect(
|
|
parseRecipientConfig({
|
|
emails: ['a@x.com'],
|
|
userIds: ['u1', 'u2'],
|
|
roleIds: ['r1'],
|
|
everyone: true,
|
|
}),
|
|
).toEqual({
|
|
emails: ['a@x.com'],
|
|
userIds: ['u1', 'u2'],
|
|
roleIds: ['r1'],
|
|
everyone: true,
|
|
});
|
|
});
|
|
|
|
it('filters non-string / empty entries and coerces everyone defensively', () => {
|
|
expect(
|
|
parseRecipientConfig({
|
|
emails: ['a@x.com', 2, '', null],
|
|
userIds: 'nope',
|
|
everyone: 'yes',
|
|
}),
|
|
).toEqual({ emails: ['a@x.com'], userIds: [], roleIds: [], everyone: false });
|
|
});
|
|
|
|
it('returns empty for null / garbage', () => {
|
|
const empty = { emails: [], userIds: [], roleIds: [], everyone: false };
|
|
expect(parseRecipientConfig(null)).toEqual(empty);
|
|
expect(parseRecipientConfig('nope')).toEqual(empty);
|
|
expect(parseRecipientConfig(42)).toEqual(empty);
|
|
});
|
|
});
|