feat: add student lecture slides and server-graded quizzes

This commit is contained in:
2026-11-02 13:08:38 +09:00
parent 8c5ccc99e9
commit eab95c51fb
8 changed files with 487 additions and 5 deletions
+33
View File
@@ -0,0 +1,33 @@
const { test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const vm = require('node:vm');
const ts = require('typescript');
const React = require('react');
const { renderToStaticMarkup } = require('react-dom/server');
test('course detail opens a pinned lecture without a platform connection', () => {
const source = fs.readFileSync(require.resolve('../src/renderer/src/features/curriculum/CurriculumDetailPanel.tsx'), 'utf8');
const exports = {};
const output = ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022, jsx: ts.JsxEmit.ReactJSX, esModuleInterop: true } }).outputText;
vm.runInNewContext(output, { exports, require: name => name === '../../i18n' ? { t: value => value, useLocaleRender() {} } : require(name) });
const props = { week: { week: 1, title: '제어', topics: ['속도'], detail: { overview: '개요', topicDetails: ['설명'], deliverable: '확인', learningSteps: [{ lectureVersionId: 'pinned-v1' }] } }, selected: true, activeLearningStep: '속도' };
const html = renderToStaticMarkup(React.createElement(exports.default, { ...props, onOpenLecture() {} }));
assert.match(html, /슬라이드·퀴즈 열기/);
assert.doesNotMatch(renderToStaticMarkup(React.createElement(exports.default, props)), /슬라이드·퀴즈 열기/);
});
test('quiz sends answers only and maintains a stable request ID for retry', () => {
const source = fs.readFileSync(require.resolve('../src/renderer/src/features/curriculum/LectureViewerModal.tsx'), 'utf8');
assert.match(source, /\/quiz/);
assert.match(source, /questionId: q.id/);
assert.match(source, /optionIndex: answers\[q.id\]/);
assert.match(source, /requestId.current \?\?= crypto.randomUUID/);
assert.match(source, /signal: controller.current.signal/);
assert.doesNotMatch(source, /score:.*answers/);
});
test('lecture controls have English translations', () => {
const en = require('../src/renderer/src/i18n/en.json');
for (const key of ['슬라이드·퀴즈 열기', '강의 닫기', '슬라이드', '퀴즈', '답안 제출', '다시 풀기']) assert.ok(en[key], key);
});