import { describe, it, expect } from 'vitest'; import { summarizeScenes } from '@/lib/classroom/complete-summary'; import type { Scene, QuizQuestion } from '@/lib/types/stage'; function slide(id: string, order: number): Scene { return { id, stageId: 's1', type: 'slide', title: id, order, content: { type: 'slide', canvas: {} as never }, }; } function quizScene(id: string, order: number, questions: QuizQuestion[]): Scene { return { id, stageId: 's1', type: 'quiz', title: id, order, content: { type: 'quiz', questions }, }; } function interactive(id: string, order: number): Scene { return { id, stageId: 's1', type: 'interactive', title: id, order, content: { type: 'interactive', url: 'about:blank' }, }; } const choiceQ = (id: string, answer: string[]): QuizQuestion => ({ id, type: 'single', question: id, options: [ { value: 'a', label: 'A' }, { value: 'b', label: 'B' }, ], answer, hasAnswer: true, points: 1, }); describe('summarizeScenes', () => { it('counts scenes by type and omits zeros', () => { const scenes = [slide('s1', 0), slide('s2', 1), interactive('i1', 2)]; const result = summarizeScenes(scenes, () => ({})); expect(result.countsByType).toEqual({ slide: 2, interactive: 1 }); expect(result.quiz).toBeNull(); }); it('returns null quiz when no quiz scenes exist', () => { const result = summarizeScenes([slide('s1', 0)], () => ({})); expect(result.quiz).toBeNull(); }); it('aggregates quiz answers across multiple quiz scenes', () => { const scenes = [ quizScene('q1', 0, [choiceQ('qa', ['a']), choiceQ('qb', ['b'])]), quizScene('q2', 1, [choiceQ('qc', ['a'])]), ]; const answers: Record> = { q1: { qa: 'a', qb: 'a' }, q2: { qc: 'a' }, }; const result = summarizeScenes(scenes, (sceneId) => answers[sceneId] ?? {}); expect(result.quiz).toEqual({ correct: 2, total: 3, pct: Math.round((2 / 3) * 100) }); expect(result.countsByType.quiz).toBe(2); }); it('returns null quiz when quiz scenes exist but have no gradeable questions', () => { const saOnly = quizScene('q1', 0, [ { id: 'sa', type: 'short_answer', question: 'x', answer: [], hasAnswer: false, }, ]); const result = summarizeScenes([saOnly], () => ({})); expect(result.quiz).toBeNull(); expect(result.countsByType.quiz).toBe(1); }); it('treats missing answers as incorrect (not skipped)', () => { const scenes = [quizScene('q1', 0, [choiceQ('qa', ['a']), choiceQ('qb', ['b'])])]; const result = summarizeScenes(scenes, () => ({})); expect(result.quiz).toEqual({ correct: 0, total: 2, pct: 0 }); }); });