// apps/hq/test/milestones-templates.test.ts — composed (front + per-module tail) onboarding // template resolution. import { describe, it, expect, beforeEach } from 'vitest' import { openDb, type DB } from '../src/db' import { milestoneTemplate, FRONT_FALLBACK, TAIL_FALLBACK } from '../src/repos-milestones' describe('composed milestone templates (front + tail)', () => { let db: DB beforeEach(() => { db = openDb(':memory:') }) it('falls back to the code FRONT_FALLBACK + TAIL_FALLBACK when nothing is configured', async () => { expect(await milestoneTemplate(db, 'SMS')).toEqual([...FRONT_FALLBACK, ...TAIL_FALLBACK]) expect(await milestoneTemplate(db)).toEqual([...FRONT_FALLBACK, ...TAIL_FALLBACK]) }) it('starts with the 4 front keys then the SMS tail', async () => { const keys = (await milestoneTemplate(db, 'SMS')).map((e) => e.key) expect(keys.slice(0, 4)).toEqual(FRONT_FALLBACK.map((f) => f.key)) }) it('uses the configured front for every module and with no moduleCode', async () => { await db.run(`INSERT INTO setting (key, value) VALUES ('project.milestone_template.front', ?)`, JSON.stringify([{ key: 'f1', label: 'F1' }])) expect((await milestoneTemplate(db, 'SMS'))[0]).toEqual({ key: 'f1', label: 'F1' }) expect((await milestoneTemplate(db))[0]).toEqual({ key: 'f1', label: 'F1' }) }) it('tail: falls back to the global tail template when no module-specific one exists', async () => { await db.run(`INSERT INTO setting (key, value) VALUES ('project.milestone_template', ?)`, JSON.stringify([{ key: 'a', label: 'A' }])) expect(await milestoneTemplate(db, 'SMS')).toEqual([...FRONT_FALLBACK, { key: 'a', label: 'A' }]) }) it('tail: prefers the module-specific template over the global one', async () => { await db.run(`INSERT INTO setting (key, value) VALUES ('project.milestone_template', ?)`, JSON.stringify([{ key: 'a', label: 'A' }])) await db.run(`INSERT INTO setting (key, value) VALUES ('project.milestone_template:SMS', ?)`, JSON.stringify([{ key: 'doc', label: 'Document collection' }])) expect(await milestoneTemplate(db, 'SMS')) .toEqual([...FRONT_FALLBACK, { key: 'doc', label: 'Document collection' }]) // A different module still gets the global tail. expect(await milestoneTemplate(db, 'RTGS')).toEqual([...FRONT_FALLBACK, { key: 'a', label: 'A' }]) }) it('with no moduleCode: front + global tail when set, else TAIL_FALLBACK', async () => { expect(await milestoneTemplate(db)).toEqual([...FRONT_FALLBACK, ...TAIL_FALLBACK]) await db.run(`INSERT INTO setting (key, value) VALUES ('project.milestone_template', ?)`, JSON.stringify([{ key: 'a', label: 'A' }])) expect(await milestoneTemplate(db)).toEqual([...FRONT_FALLBACK, { key: 'a', label: 'A' }]) }) it('a malformed or empty per-module tail setting is treated as absent', async () => { await db.run(`INSERT INTO setting (key, value) VALUES ('project.milestone_template:SMS', ?)`, 'not json') expect(await milestoneTemplate(db, 'SMS')).toEqual([...FRONT_FALLBACK, ...TAIL_FALLBACK]) await db.run(`UPDATE setting SET value=? WHERE key='project.milestone_template:SMS'`, '[]') expect(await milestoneTemplate(db, 'SMS')).toEqual([...FRONT_FALLBACK, ...TAIL_FALLBACK]) }) })