import { describe, expect, test } from 'vitest';
import type { PersistedClassroomData } from '@/lib/server/classroom-storage';
import {
buildCourseModuleOutputDigest,
formatPreviousModuleContext,
} from '@/lib/course-framework/module-digest';
function classroomFixture(): PersistedClassroomData {
return {
id: 'classroom-actual-1',
createdAt: '2026-08-15T09:00:00.000Z',
stage: { id: 'stage-1', name: '实际生成的机器学习基础' } as never,
scenes: [
{
id: 'scene-slide',
stageId: 'stage-1',
order: 1,
title: '监督学习基础',
type: 'slide',
content: {
type: 'slide',
canvas: {
id: 'slide-1',
viewportSize: 1000,
viewportRatio: 0.5625,
theme: {},
elements: [
{
id: 'text-1',
type: 'text',
content: '
特征、标签与训练样本
',
},
],
},
},
actions: [{ id: 'speech-1', type: 'speech', text: '比较监督学习和无监督学习。' }],
},
{
id: 'scene-interactive',
stageId: 'stage-1',
order: 2,
title: '分类边界实验室',
type: 'interactive',
content: {
type: 'interactive',
widgetType: 'simulation',
widgetConfig: { type: 'simulation', concept: '决策边界', challenge: '调整样本分布' },
html: '拖动数据点观察边界变化
',
},
},
{
id: 'scene-quiz',
stageId: 'stage-1',
order: 3,
title: '概念检查',
type: 'quiz',
content: {
type: 'quiz',
questions: [
{
id: 'q-1',
type: 'single',
question: '标签在监督学习中承担什么作用?',
},
],
},
},
{
id: 'scene-pbl',
stageId: 'stage-1',
order: 4,
title: '识别真实业务问题',
type: 'pbl',
content: {
type: 'pbl',
projectV2: {
title: '业务问题分类项目',
description: '判断问题适合监督学习还是无监督学习。',
learningObjective: '能够把业务目标转成学习任务。',
milestones: [{ title: '提交问题定义' }],
},
},
},
] as never,
};
}
describe('course module output digest', () => {
test('extracts bounded evidence from all four actual scene types', () => {
const digest = buildCourseModuleOutputDigest(classroomFixture());
expect(digest.sceneTypeCounts).toEqual({ slide: 1, quiz: 1, interactive: 1, pbl: 1 });
expect(digest.sceneCount).toBe(4);
expect(digest.coveredConcepts).toContain('监督学习基础');
expect(digest.coveredConcepts).toContain('特征、标签与训练样本');
expect(digest.coveredConcepts).toContain('拖动数据点观察边界变化');
expect(digest.coveredConcepts.join(' ')).not.toContain('ignore()');
expect(digest.assessments).toContain('标签在监督学习中承担什么作用?');
expect(digest.assessments).toContain('提交问题定义');
expect(digest.interactiveExperiences).toEqual([
'分类边界实验室(simulation, interactive-html)',
'识别真实业务问题(PBL)',
]);
expect(digest.semanticHash).toMatch(/^sha256:[a-f0-9]{64}$/);
expect(buildCourseModuleOutputDigest(classroomFixture()).semanticHash).toBe(
digest.semanticHash,
);
});
test('formats actual prior outputs as bounded continuity context', () => {
const digest = buildCourseModuleOutputDigest(classroomFixture());
const context = formatPreviousModuleContext([
{ index: 1, title: '基础模块', outputDigest: digest },
{ index: 2, title: '练习模块', outputDigest: { ...digest, classroomId: 'classroom-2' } },
]);
expect(context).toContain('模块 1《基础模块》');
expect(context).toContain('实际摘要');
expect(context).toContain('实际覆盖');
expect(context).toContain('实际语义哈希');
expect(context).toContain('分类边界实验室(simulation, interactive-html)');
expect(context.length).toBeLessThanOrEqual(12_000);
});
});