llmMock.test.ts
2,092 bytes
| 1 | import { describe, expect, it } from 'vitest' |
|---|---|
| 2 | import { CATEGORY_IDS, initialCoverage, type Segment } from '../../shared/types' |
| 3 | import { createLlmMock } from './llmMock' |
| 4 | |
| 5 | function segment(id: string, speaker: Segment['speaker'], text: string): Segment { |
| 6 | return { id, ts: new Date().toISOString(), speaker, text } |
| 7 | } |
| 8 | |
| 9 | describe('llmMock interview script', () => { |
| 10 | it('clears one category per turn in fixed order and eventually reaches done', async () => { |
| 11 | const llm = createLlmMock() |
| 12 | let coverage = initialCoverage() |
| 13 | const segments: Segment[] = [] |
| 14 | |
| 15 | for (let i = 0; i < CATEGORY_IDS.length; i++) { |
| 16 | segments.push(segment(`S${i + 1}`, 'user', `answer ${i}`)) |
| 17 | const turn = await llm.nextTurn({ summary: '', segments, coverage }) |
| 18 | expect(turn.coverage[CATEGORY_IDS[i]]).toBe('clear') |
| 19 | coverage = turn.coverage |
| 20 | if (i < CATEGORY_IDS.length - 1) { |
| 21 | expect(turn.done).toBe(false) |
| 22 | expect(turn.nextQuestion).toContain(CATEGORY_IDS[i + 1]) |
| 23 | } else { |
| 24 | expect(turn.done).toBe(true) |
| 25 | } |
| 26 | } |
| 27 | |
| 28 | expect(Object.values(coverage).every((level) => level === 'clear')).toBe(true) |
| 29 | }) |
| 30 | |
| 31 | it('ends the interview when the last user segment is exactly "done"', async () => { |
| 32 | const llm = createLlmMock() |
| 33 | const coverage = initialCoverage() |
| 34 | const segments: Segment[] = [segment('S1', 'user', ' Done ')] |
| 35 | const turn = await llm.nextTurn({ summary: '', segments, coverage }) |
| 36 | expect(turn.done).toBe(true) |
| 37 | expect(turn.coverage).toEqual(coverage) |
| 38 | }) |
| 39 | }) |
| 40 | |
| 41 | describe('llmMock generation', () => { |
| 42 | it('emits a SPEC.md with a valid marker and a bogus marker', async () => { |
| 43 | const llm = createLlmMock() |
| 44 | const content = await llm.generateFile({ file: 'SPEC.md', prompt: '', segments: [] }) |
| 45 | expect(content).toContain('[S1]') |
| 46 | expect(content).toContain('[S999]') |
| 47 | }) |
| 48 | |
| 49 | it('emits a HANDOFF.md with a claude launch command', async () => { |
| 50 | const llm = createLlmMock() |
| 51 | const content = await llm.generateFile({ file: 'HANDOFF.md', prompt: '', segments: [] }) |
| 52 | expect(content).toContain('claude') |
| 53 | }) |
| 54 | }) |
| 55 | |