Files
Jyotisha/frontend/tests/birth-time-choice-question.test.ts
2026-07-19 10:56:09 +08:00

106 lines
4.6 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import {
choiceQuestionGroups,
choiceSelectionIntent,
normalizeUnmatchedNote,
} from "../src/lib/birth-time-choice-question-model.ts";
import type { PublicDynamicChoiceQuestion } from "../src/lib/birth-time-dynamic-choice.ts";
import {
advanceDynamicBirthTimePreview,
dynamicBirthTimePreview,
} from "../src/lib/birth-time-dynamic-preview.ts";
const question: PublicDynamicChoiceQuestion = {
questionId: "education-shift",
prompt: "哪段时间更接近一次明显的学习方向变化?",
options: [
{ optionId: "early", label: "更接近 2007—2009 年", kind: "primary" },
{ optionId: "late", label: "更接近 2010—2012 年", kind: "primary" },
{ optionId: "unknown", label: "不记得", kind: "unknown" },
{ optionId: "unmatched", label: "都不符合", kind: "unmatched" },
],
};
test("click intent submits primary and unknown options immediately", () => {
const groups = choiceQuestionGroups(question);
assert.deepEqual(groups.primary.map((option) => option.optionId), ["early", "late"]);
assert.deepEqual(choiceSelectionIntent(groups.primary[0]), {
kind: "submit", optionId: "early", effective: true,
});
assert.deepEqual(choiceSelectionIntent(groups.unknown), {
kind: "submit", optionId: "unknown", effective: false,
});
});
test("unmatched requests clarification without creating scoring evidence", () => {
const groups = choiceQuestionGroups(question);
assert.deepEqual(choiceSelectionIntent(groups.unmatched), {
kind: "submit", optionId: "unmatched", effective: false,
});
assert.equal(normalizeUnmatchedNote(" 大约是在搬家之后 "), "大约是在搬家之后");
assert.equal(normalizeUnmatchedNote("甲".repeat(260)).length, 240);
});
test("preview choices expose real local interaction states without authentication", () => {
const start = dynamicBirthTimePreview();
const nextQuestion = advanceDynamicBirthTimePreview(start, { kind: "select", optionId: "earlier" });
const result = advanceDynamicBirthTimePreview(nextQuestion, { kind: "select", optionId: "school" });
const clarification = advanceDynamicBirthTimePreview(start, { kind: "select", optionId: "unmatched" });
const reframed = advanceDynamicBirthTimePreview(clarification, { kind: "reframe" });
const terminal = advanceDynamicBirthTimePreview(reframed, { kind: "finish" });
assert.equal(nextQuestion.nextAction.kind, "ask_dynamic_choice");
assert.equal(nextQuestion.progress.effectiveAnswerCount, 1);
assert.equal(result.nextAction.kind, "present_medium_result");
assert.equal(clarification.nextAction.kind, "clarify_unmatched_answer");
assert.equal(reframed.nextAction.kind, "ask_dynamic_choice");
assert.equal(terminal.nextAction.kind, "present_low_result");
});
test("preview unknown answers terminate instead of repeating the same question", () => {
const start = dynamicBirthTimePreview();
const secondQuestion = advanceDynamicBirthTimePreview(start, { kind: "select", optionId: "unknown" });
const terminal = advanceDynamicBirthTimePreview(secondQuestion, { kind: "select", optionId: "unknown-2" });
assert.equal(secondQuestion.nextAction.kind, "ask_dynamic_choice");
assert.equal(terminal.nextAction.kind, "present_low_result");
assert.equal(terminal.progress.answeredCount, 2);
});
test("preview unmatched reframing terminates when no different question remains", () => {
const start = dynamicBirthTimePreview();
const secondQuestion = advanceDynamicBirthTimePreview(start, { kind: "select", optionId: "earlier" });
const secondClarification = advanceDynamicBirthTimePreview(secondQuestion, {
kind: "select",
optionId: "unmatched-2",
});
const terminal = advanceDynamicBirthTimePreview(secondClarification, { kind: "reframe" });
assert.equal(secondClarification.nextAction.kind, "clarify_unmatched_answer");
assert.equal(terminal.nextAction.kind, "present_low_result");
assert.equal(terminal.progress.answeredCount, 2);
});
test("dynamic previews cover every visible result and recovery state", () => {
const expected = new Map([
["generating", "generate_dynamic_question"],
["question-retry", "retry_question_generation"],
["question", "ask_dynamic_choice"],
["clarification", "clarify_unmatched_answer"],
["scoring", "score_pending"],
["scoring-retry", "retry_scoring"],
["low", "present_low_result"],
["medium", "present_medium_result"],
["confirmation", "request_candidate_confirmation"],
["ready", "ready"],
["paused", "paused"],
] as const);
for (const [state, action] of expected) {
assert.equal(dynamicBirthTimePreview(state).nextAction.kind, action);
}
});