Commit
test demo fixture expansion
commit
c0ee0c9
1 changed file with +62 and −0
added src/lib/demo-fixtures.test.ts +62 −0
| @@ -0,0 +1,62 @@ | ||
| 1 | +import { describe, expect, it } from 'vitest'; | |
| 2 | +import { buildDebateResult, FIXTURES, resultToStageEvents } from './demo-fixtures'; | |
| 3 | + | |
| 4 | +describe('demo fixtures', () => { | |
| 5 | + it('ships at least two hand-authored debates', () => { | |
| 6 | + expect(FIXTURES.length).toBeGreaterThanOrEqual(2); | |
| 7 | + }); | |
| 8 | + | |
| 9 | + for (const spec of FIXTURES) { | |
| 10 | + describe(spec.question.slice(0, 40), () => { | |
| 11 | + const result = buildDebateResult(spec); | |
| 12 | + | |
| 13 | + it('has one distinct initial answer per model', () => { | |
| 14 | + expect(result.initialAnswers).toHaveLength(spec.models.length); | |
| 15 | + const unique = new Set(result.initialAnswers.map((a) => a.content)); | |
| 16 | + expect(unique.size).toBe(result.initialAnswers.length); | |
| 17 | + }); | |
| 18 | + | |
| 19 | + it('produces a synthesis and non-zero cost attributed per model', () => { | |
| 20 | + expect(result.synthesis).not.toBeNull(); | |
| 21 | + expect(result.synthesis!.finalAnswer.length).toBeGreaterThan(20); | |
| 22 | + expect(result.totals.costUsd).toBeGreaterThan(0); | |
| 23 | + expect(Object.keys(result.totals.costByModel).length).toBeGreaterThanOrEqual(spec.models.length); | |
| 24 | + }); | |
| 25 | + | |
| 26 | + it('marks convergence.converged consistently with the threshold', () => { | |
| 27 | + const threshold = spec.convergenceThreshold ?? 85; | |
| 28 | + for (const round of result.rounds) { | |
| 29 | + expect(round.convergence!.converged).toBe(round.convergence!.score >= threshold); | |
| 30 | + } | |
| 31 | + }); | |
| 32 | + | |
| 33 | + it('final answers reflect the last revision content', () => { | |
| 34 | + const lastRound = result.rounds.at(-1)!; | |
| 35 | + for (const rev of lastRound.revisions) { | |
| 36 | + const final = result.finalAnswers.find((a) => a.participantId === rev.participantId); | |
| 37 | + expect(final?.content).toBe(rev.content); | |
| 38 | + } | |
| 39 | + }); | |
| 40 | + | |
| 41 | + it('critique reviews resolve to real, non-self participants', () => { | |
| 42 | + const ids = new Set(result.participants.map((p) => p.id)); | |
| 43 | + for (const round of result.rounds) { | |
| 44 | + for (const c of round.critiques) { | |
| 45 | + for (const r of c.reviews) { | |
| 46 | + expect(ids.has(r.targetParticipantId)).toBe(true); | |
| 47 | + expect(r.targetParticipantId).not.toBe(c.reviewerParticipantId); | |
| 48 | + } | |
| 49 | + } | |
| 50 | + } | |
| 51 | + }); | |
| 52 | + | |
| 53 | + it('serializes to the expected durable events', () => { | |
| 54 | + const events = resultToStageEvents(result); | |
| 55 | + const count = (t: string) => events.filter((e) => e.type === t).length; | |
| 56 | + expect(count('answer_completed')).toBe(spec.models.length); | |
| 57 | + expect(count('synthesis_completed')).toBe(1); | |
| 58 | + expect(count('convergence_result')).toBe(result.rounds.length); | |
| 59 | + }); | |
| 60 | + }); | |
| 61 | + } | |
| 62 | +}); |