You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
63 lines
4.5 KiB
JavaScript
63 lines
4.5 KiB
JavaScript
const assert = require("assert");
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
|
|
const root = path.resolve(__dirname, "..");
|
|
const api = fs.readFileSync(path.join(root, "src/api/aiTrainingEvaluation.js"), "utf8");
|
|
const component = fs.readFileSync(path.join(root, "src/views/components/TrainingAiEvaluation.vue"), "utf8");
|
|
const sidebar = fs.readFileSync(path.join(root, "src/views/components/TrainingAiSidebar.vue"), "utf8");
|
|
const page = fs.readFileSync(path.join(root, "src/views/training/GenericTrainingPage.vue"), "utf8");
|
|
const { normalizeEvaluationReports } = require(path.join(root, "src/views/components/trainingAiEvaluationReport.cjs"));
|
|
|
|
assert(/`\/api\/student\/training-tasks\/\$\{taskKey\}\/ai-evaluation`/.test(api), "evaluation API should use the student task endpoint");
|
|
assert(/\/help/.test(api) && /\/assessment/.test(api), "evaluation API should expose help and assessment operations");
|
|
assert(/TrainingAiSidebar/.test(page) && /:has-saved-answer="hasSavedAnswer"/.test(page), "generic training page should pass persisted answer state to the AI sidebar");
|
|
assert(/form\.value/.test(page) && /workRows\.value/.test(page) && /processRows\.value/.test(page), "hasAnyAnswer should inspect all supported answer shapes");
|
|
|
|
assert(/onMounted\(/.test(component) && /watch\(\s*\(\)\s*=>\s*props\.taskKey/.test(component), "AI evaluation should load on mount and task changes");
|
|
assert(/AI助学/.test(component) && /AI助评/.test(component), "AI evaluation should offer separate help and assessment controls");
|
|
assert(/PROCESSING/.test(component) && /SUCCEEDED/.test(component), "AI evaluation should surface backend statuses");
|
|
assert(/!props\.hasAnyAnswer/.test(component), "AI actions should disable when no answer is available");
|
|
assert(/proxy\?\.\$modal\?\.confirm/.test(component), "assessment should request confirmation through the modal proxy");
|
|
assert(!/v-html/.test(component), "AI reports must be rendered as interpolated text, never v-html");
|
|
assert(/scoreCriteria/.test(component), "assessment should display score criteria");
|
|
assert(/normalizeEvaluationReports/.test(component), "the component should use the executable report normalizer");
|
|
|
|
const normalizedFlatPayload = normalizeEvaluationReports({
|
|
helpStatus: "succeeded",
|
|
helpReportJson: JSON.stringify({ summary: "Add supporting data", suggestions: ["Cite the source"] }),
|
|
assessmentStatus: "succeeded",
|
|
assessmentScore: 92,
|
|
assessmentReportJson: JSON.stringify({
|
|
summary: "Clear analysis",
|
|
criteria: [
|
|
{ criterion: "Evidence", weight: 40, detail: "Uses relevant data" },
|
|
"Structure",
|
|
],
|
|
}),
|
|
});
|
|
|
|
assert.strictEqual(normalizedFlatPayload.help.status, "SUCCEEDED", "flat help status should be normalized");
|
|
assert.match(normalizedFlatPayload.helpReport, /Add supporting data/, "flat help JSON should be formatted for text display");
|
|
assert.strictEqual(normalizedFlatPayload.assessment.status, "SUCCEEDED", "flat assessment status should be normalized");
|
|
assert.strictEqual(normalizedFlatPayload.score, 92, "assessmentScore should take precedence for the displayed score");
|
|
assert.deepStrictEqual(normalizedFlatPayload.scoreCriteria, [
|
|
{ name: "Evidence", score: 40, description: "Uses relevant data" },
|
|
{ name: "Structure", score: "", description: "" },
|
|
], "assessment criteria should be mapped from the flat assessment JSON");
|
|
|
|
const malformedPayload = normalizeEvaluationReports({
|
|
helpReportJson: "{not valid JSON",
|
|
assessmentReportJson: "{also not valid JSON",
|
|
});
|
|
|
|
assert.strictEqual(malformedPayload.helpReport, "{not valid JSON", "malformed help JSON should remain safe text");
|
|
assert.strictEqual(malformedPayload.assessmentReport, "{also not valid JSON", "malformed assessment JSON should remain safe text");
|
|
assert.strictEqual(malformedPayload.score, null, "malformed assessment JSON should not produce a score");
|
|
assert.deepStrictEqual(malformedPayload.scoreCriteria, [], "malformed assessment JSON should not produce criteria");
|
|
assert(/retry/.test(component) || /重试/.test(component), "failed AI operations should expose a retry action");
|
|
assert(/hasSavedAnswer/.test(page) && /:has-saved-answer="hasSavedAnswer"/.test(page), "generic training page should distinguish persisted answers before enabling AI assessment");
|
|
assert(/hasSavedAnswer/.test(sidebar), "AI sidebar should accept persisted-answer state");
|
|
assert(/!props\.hasSavedAnswer/.test(sidebar), "AI assessment should be disabled until a saved answer exists");
|
|
assert(/catch \(error\)/.test(sidebar), "AI sidebar should handle assessment failures without an unhandled rejection");
|