import assert from 'node:assert/strict' import test from 'node:test' import { DEFAULT_SOURCES, calloutsFromSections, deliveryPreview, failedSection, isDryRun, notifyBody, reportMarkdown, resolveDate, resolveOutput, resolveSources, resolveTimezone, skippedSection, } from './format.ts' import { aqiCategory, weatherLabel } from './open-meteo.ts' import { homeSection } from './sources/home.ts' test('resolveSources defaults to calendar and weather', () => { assert.deepEqual(resolveSources({}), DEFAULT_SOURCES) }) test('resolveSources accepts optional inbox, health, and home', () => { assert.deepEqual(resolveSources({ sources: ['calendar', 'weather', 'inbox', 'health', 'home'] }), [ 'calendar', 'weather', 'inbox', 'health', 'home', ]) }) test('resolveSources rejects unknown sources', () => { assert.throws( () => resolveSources({ sources: ['discord'] as never }), /Unknown source "discord"/, ) }) test('resolveOutput accepts email or notify and rejects others', () => { assert.equal(resolveOutput({}), 'email') assert.equal(resolveOutput({ output: 'notify' }), 'notify') assert.throws(() => resolveOutput({ output: 'discord' as never }), /Unknown output/) }) test('isDryRun is opt-in', () => { assert.equal(isDryRun({}), false) assert.equal(isDryRun({ dryRun: true }), true) }) test('resolveDate uses an explicit YYYY-MM-DD', () => { assert.equal(resolveDate({ date: '2026-08-22' }, 'UTC'), '2026-08-22') }) test('resolveTimezone rejects invalid zones', () => { assert.equal(resolveTimezone({}), 'UTC') assert.throws(() => resolveTimezone({ timezone: 'Not/AZone' }), /RangeError|invalid/i) }) test('report markdown and notify stay Discord-free', () => { const report = { title: 'Saturday, August 22 · Denver, CO', date: '2026-08-22', callouts: [{ title: 'US AQI 140', detail: 'Unhealthy for sensitive groups', severity: 'warning' as const }], sections: [ { id: 'weather' as const, title: 'Weather', status: 'ok' as const, summary: 'Clear', items: [{ title: 'Clear sky, 28° / 14°C', detail: 'Current 22°C' }], }, ], } const markdown = reportMarkdown(report) const notify = notifyBody(report) assert.match(markdown, /Needs attention/) assert.match(notify, /US AQI 140/) assert.doesNotMatch(markdown, /discord/i) assert.doesNotMatch(notify, /discord/i) assert.doesNotMatch(deliveryPreview({ ...report, markdown, notifyText: notify } as never, 'email').text, /discord/i) }) test('notify preview uses a short subject', () => { const report = { date: '2026-08-22', title: 'Saturday, August 22', callouts: [] as Array<{ title: string }>, sections: [], markdown: '# Saturday, August 22\n', notifyText: 'all clear', } const preview = deliveryPreview(report as never, 'notify') assert.equal(preview.subject, 'Briefing all clear · 2026-08-22') assert.equal(preview.text, 'all clear') }) test('failed and skipped sections keep source ids', () => { const failed = failedSection('inbox', new Error('missing gmail.readonly')) assert.equal(failed.id, 'inbox') assert.equal(failed.status, 'error') const skipped = skippedSection('home', 'Pass home.items') assert.equal(skipped.status, 'skipped') }) test('callouts only include warning and critical items', () => { const callouts = calloutsFromSections([ { id: 'health', title: 'Health', status: 'warning', items: [ { title: 'ok', severity: 'good' }, { title: 'watch', severity: 'warning' }, { title: 'bad', severity: 'critical' }, ], }, ]) assert.deepEqual(callouts.map((item) => item.title), ['watch', 'bad']) }) test('home section uses caller items and skips Discord-style defaults', async () => { const skipped = await homeSection({}) assert.equal(skipped.status, 'skipped') assert.match(skipped.summary || '', /home\.items/) assert.doesNotMatch(skipped.summary || '', /post to discord/i) const section = await homeSection({ home: { items: [{ title: 'Thermostat 70°', detail: 'Heat' }] }, }) assert.equal(section.status, 'ok') assert.equal(section.items[0]?.title, 'Thermostat 70°') }) test('Open-Meteo helpers map codes and AQI bands', () => { assert.equal(weatherLabel(0), 'Clear sky') assert.equal(weatherLabel(99), 'Thunderstorm with heavy hail') assert.equal(aqiCategory(12), 'Good') assert.equal(aqiCategory(120), 'Unhealthy for sensitive groups') assert.equal(aqiCategory(250), 'Very unhealthy') })