99 lines
2.8 KiB
TypeScript
99 lines
2.8 KiB
TypeScript
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<string, Record<string, string | string[]>> = {
|
|
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 });
|
|
});
|
|
});
|