learning_ai_common_plat/packages/gentle-notifications/src/client.test.ts
saravanakumardb1 be03efa111 feat(shared-packages): add 9 @bytelyst/* client packages with 100% API coverage
Packages added:
- @bytelyst/referral-client — referral API client + share helpers
- @bytelyst/subscription-client — subscription/plan API client + cache
- @bytelyst/celebrations — milestone triggers, confetti, positive messages
- @bytelyst/gentle-notifications — ND-friendly messaging, forbidden phrases
- @bytelyst/accessibility — VoiceOver/TalkBack label generators
- @bytelyst/quick-actions — progressive disclosure, smart defaults
- @bytelyst/time-references — familiar duration references
- @bytelyst/org-client — org/workspace/membership/license API client
- @bytelyst/marketplace-client — listing/review/install API client

All packages: pure TS, ESM, globalThis.fetch, no Node.js deps.
99 Vitest tests across 9 packages, 79/79 public methods covered.

Review fixes applied:
- time-references: fix module-level mutable state leak + add clearCustomReferences()
- accessibility: fix parameter reassignment in formatDurationForA11y/numberToWords
- subscription-client: fix flaky daysRemaining test (ms boundary race)
2026-03-19 13:10:09 -07:00

98 lines
3.6 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { createGentleNotificationEngine, FORBIDDEN_PHRASES } from './client.js';
describe('createGentleNotificationEngine', () => {
it('should return default config', () => {
const engine = createGentleNotificationEngine();
const config = engine.getDefaultConfig();
expect(config.maxPerHour).toBe(3);
expect(config.tone).toBe('encouraging');
expect(config.adaptiveFrequency).toBe(true);
expect(config.dismissCount).toBe(0);
expect(config.suppressThreshold).toBe(5);
});
it('should return a message for known type', () => {
const engine = createGentleNotificationEngine();
const msg = engine.getMessage('reminder');
expect(msg.title.length).toBeGreaterThan(0);
expect(msg.body.length).toBeGreaterThan(0);
expect(['encouraging', 'neutral', 'minimal']).toContain(msg.tone);
});
it('should return fallback for unknown type', () => {
const engine = createGentleNotificationEngine();
const msg = engine.getMessage('nonexistent_type');
expect(msg.title).toBe('Hey');
expect(msg.body.length).toBeGreaterThan(0);
});
it('should suppress when dismiss threshold reached', () => {
const engine = createGentleNotificationEngine();
const config = { ...engine.getDefaultConfig(), dismissCount: 5 };
expect(engine.shouldSuppress(config)).toBe(true);
});
it('should not suppress when below threshold', () => {
const engine = createGentleNotificationEngine();
const config = { ...engine.getDefaultConfig(), dismissCount: 2 };
expect(engine.shouldSuppress(config)).toBe(false);
});
it('should record dismissal and reduce frequency', () => {
const engine = createGentleNotificationEngine();
let config = engine.getDefaultConfig();
expect(config.dismissCount).toBe(0);
config = engine.recordDismissal(config);
expect(config.dismissCount).toBe(1);
// Record enough to trigger suppression
for (let i = 0; i < 4; i++) {
config = engine.recordDismissal(config);
}
expect(config.dismissCount).toBe(5);
expect(config.maxPerHour).toBeLessThan(3);
});
it('should reset dismissals', () => {
const engine = createGentleNotificationEngine();
let config = engine.getDefaultConfig();
config = engine.recordDismissal(config);
config = engine.recordDismissal(config);
expect(config.dismissCount).toBe(2);
config = engine.resetDismissals(config);
expect(config.dismissCount).toBe(0);
});
it('should allow registering custom messages', () => {
const engine = createGentleNotificationEngine();
engine.registerMessages('fasting', [
{ title: 'Fasting Reminder', body: 'Your body is doing great things!', tone: 'encouraging' },
]);
const msg = engine.getMessage('fasting');
expect(msg.title).toBe('Fasting Reminder');
});
it('should export FORBIDDEN_PHRASES', () => {
expect(FORBIDDEN_PHRASES).toContain("You haven't");
expect(FORBIDDEN_PHRASES).toContain('You failed');
expect(FORBIDDEN_PHRASES.length).toBeGreaterThanOrEqual(8);
});
it('should detect forbidden phrases', () => {
const engine = createGentleNotificationEngine();
expect(engine.containsForbiddenPhrase("You haven't done this yet")).toBe(true);
expect(engine.containsForbiddenPhrase('Great job today!')).toBe(false);
expect(engine.containsForbiddenPhrase('you failed the test')).toBe(true);
});
it('should respect custom initial config', () => {
const engine = createGentleNotificationEngine({ maxPerHour: 10, tone: 'minimal' });
const config = engine.getDefaultConfig();
expect(config.maxPerHour).toBe(10);
expect(config.tone).toBe('minimal');
});
});