import { describe, test, expect } from 'bun:test'; import { composeDigest } from '$lib/server/stats/digest'; import type { SnapshotPayload } from '$lib/types/stats'; const payload: SnapshotPayload = { asOfDate: '2026-09-14', activity: { dau: 102, wau: 363, mau: 852, core: 61, returningShare: 38, newPlayers: 20, resurrected: 4, churned: 25, netGrowth: -1, corePrevious: 60, previous: null }, dailySeries: [], kpis: { d1Return: 12.2, return7: 18, overallReturnRate: 22.8, completionRate: null, shareRate: null, firstTryRate: 33.7, avgGuesses: 4.1 }, retention: { cohorts: [], curves: { d1: [], d7: [], d30: [] }, timeToSecondPlay: [], segmentMix: [] }, verseMix: { coverage: [], testamentMix: [], entropy: [], repeatIntervals: [], firstTryByBook: [], retentionByBook: [], retentionByGuessBucket: [], achievability: [] }, habit: { streakSurvival: [], streakLengths: [], calendar: [], weekdayHour: [] }, growth: { lifecycleFunnel: [], signups: [] }, totals: { completions: 31775, players: 6589, yesterdayCompletions: 102, yesterdayAvgGuesses: 4.1, bestDay: null }, signals: [ { id: 'd1_return', severity: 'bad', title: 'D1 return', detail: 'D1 return is 12.2%, below the 20% target.', action: 'Test a "come back tomorrow" prompt.' } ], meta: { hasStartedData: false, hasShareData: false, firstEventDate: null } }; describe('composeDigest', () => { test('includes the core numbers in plain language', () => { const message = composeDigest(payload); expect(message).toContain('2026-09-14'); expect(message).toContain('363'); expect(message).toContain('12.2'); expect(message).toContain('Top signal: D1 return'); expect(message).toContain('/admin/stats?date=2026-09-14'); }); test('is at most a handful of lines', () => { expect(composeDigest(payload).split('\n').length).toBeLessThanOrEqual(6); }); test('shows an em-dash for missing metrics', () => { const message = composeDigest({ ...payload, kpis: { ...payload.kpis, d1Return: null, return7: null } }); expect(message).toContain('D1 return —%'); }); });