feat: add mock exam reports

This commit is contained in:
Codex
2026-06-28 23:34:31 +08:00
parent 6a7294224d
commit e55942dcec
8 changed files with 817 additions and 5 deletions

View File

@@ -663,6 +663,83 @@ async function testCatalogAndLearning() {
assert.equal(Number(mockSession.item?.totalScore), 100, 'mock session should inherit total score');
assert.ok(mockSession.item?.questionIds?.includes(ids.question), 'mock session should snapshot assembled questions');
await request('/api/learning/answers', {
userId: TENANT_ADMIN_USER_ID,
method: 'POST',
body: {
userId: TENANT_ADMIN_USER_ID,
questionId: ids.question,
selectedOptions: ['1'],
practiceSessionId: mockSession.item.id,
},
});
await request('/api/learning/answers', {
userId: TENANT_ADMIN_USER_ID,
method: 'POST',
body: {
userId: TENANT_ADMIN_USER_ID,
questionId: ids.questionTwo,
selectedOptions: ['0'],
practiceSessionId: mockSession.item.id,
},
});
const mockReport = await request('/api/learning/practice-sessions/submit', {
userId: TENANT_ADMIN_USER_ID,
method: 'POST',
body: {
userId: TENANT_ADMIN_USER_ID,
practiceSessionId: mockSession.item.id,
},
});
assert.equal(mockReport.item?.practiceSessionId, mockSession.item.id, 'mock submit should create a report for the session');
assert.equal(mockReport.item?.totalQuestions, 3, 'mock report should count session snapshot questions');
assert.equal(mockReport.item?.answeredCount, 2, 'mock report should count latest submitted answers');
assert.equal(mockReport.item?.correctCount, 1, 'mock report should count correct answers');
assert.equal(mockReport.item?.wrongCount, 1, 'mock report should count wrong answers');
assert.equal(mockReport.item?.unansweredCount, 1, 'mock report should count unanswered questions');
assert.equal(mockReport.item?.score, 2, 'mock report should use backend scoring only');
assert.equal(mockReport.item?.totalScore, 100, 'mock report should keep configured paper total score');
assert.ok(mockReport.item?.wrongQuestionIds?.includes(ids.questionTwo), 'mock report should include wrong question ids');
assert.ok(mockReport.item?.questionResults?.some(item => item.questionId === ids.question && item.isCorrect === true), 'mock report should include per-question result');
const idempotentReport = await request('/api/learning/practice-sessions/submit', {
userId: TENANT_ADMIN_USER_ID,
method: 'POST',
body: {
userId: TENANT_ADMIN_USER_ID,
practiceSessionId: mockSession.item.id,
},
});
assert.equal(idempotentReport.item?.id, mockReport.item.id, 'mock submit should be idempotent');
const fetchedReport = await request('/api/learning/practice-sessions/report', {
userId: TENANT_ADMIN_USER_ID,
query: { practiceSessionId: mockSession.item.id },
});
assert.equal(fetchedReport.item?.id, mockReport.item.id, 'mock report should be queryable');
const reportList = await request('/api/learning/practice-reports', {
userId: TENANT_ADMIN_USER_ID,
query: { blueprintId: ids.practiceBlueprintMock },
});
assert.ok(reportList.items?.some(item => item.id === mockReport.item.id), 'mock report list should include submitted report');
const crossUserReport = await request('/api/learning/practice-sessions/report', {
query: { practiceSessionId: mockSession.item.id },
expectStatus: 404,
});
assert.equal(crossUserReport.code, 'PRACTICE_REPORT_NOT_FOUND', 'student should not query another user report');
const crossUserSubmit = await request('/api/learning/practice-sessions/submit', {
method: 'POST',
body: {
practiceSessionId: mockSession.item.id,
},
expectStatus: 404,
});
assert.equal(crossUserSubmit.code, 'PRACTICE_SESSION_NOT_FOUND', 'student should not submit another user session');
const wrong = await request('/api/learning/wrong-questions', {
userId: false,
headers: { authorization: `Bearer ${freeLogin.session.token}` },