142 lines
4.2 KiB
TypeScript
142 lines
4.2 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
import { parseJourneyResponse } from "../src/lib/birth-time-journey-client.ts";
|
|
import {
|
|
highConfirmationTurn,
|
|
snapshot,
|
|
} from "./birth-time-journey-client-test-support.ts";
|
|
|
|
test("journey client parses the sanitized API response", () => {
|
|
const parsed = parseJourneyResponse({
|
|
caseId: highConfirmationTurn.caseId,
|
|
snapshot,
|
|
questionnaire: {
|
|
questions: [{
|
|
id: "education_environment_shift",
|
|
prompt: "是否有明显学业变化?",
|
|
options: [{ key: "A", label: "明确有" }],
|
|
}],
|
|
samples: [],
|
|
raw: {},
|
|
},
|
|
scoring: null,
|
|
});
|
|
|
|
assert.equal(parsed.snapshot.route, "rectification");
|
|
assert.equal(parsed.questionnaire?.questions[0]?.id, "education_environment_shift");
|
|
});
|
|
|
|
test("journey client preserves deterministic next rectification questions", () => {
|
|
const parsed = parseJourneyResponse({
|
|
caseId: highConfirmationTurn.caseId,
|
|
snapshot: {
|
|
...snapshot,
|
|
state: "candidate",
|
|
assistantIntent: "present_saved_candidate_range",
|
|
},
|
|
questionnaire: {
|
|
questions: [
|
|
{ id: "education_environment_shift", prompt: "是否有明显学业变化?" },
|
|
{ id: "residence_relocation_shift", prompt: "是否有明显居住变化?" },
|
|
{ id: "relationship_or_partner_entry", prompt: "是否有明显关系变化?" },
|
|
],
|
|
samples: [],
|
|
raw: {},
|
|
},
|
|
scoring: {
|
|
answeredCount: 3,
|
|
candidateClusterRankings: [{ cluster: "middle_candidate_cluster", score: 5 }],
|
|
nextRound: 2,
|
|
nextRoundQuestions: [{
|
|
id: "health_crisis_or_low_period",
|
|
prompt: "是否有明显健康或低谷阶段?",
|
|
options: [{ key: "A", label: "明确有" }],
|
|
}],
|
|
raw: {},
|
|
},
|
|
answers: {
|
|
education_environment_shift: "A",
|
|
residence_relocation_shift: "A",
|
|
relationship_or_partner_entry: "B",
|
|
},
|
|
});
|
|
|
|
assert.equal(parsed.scoring?.nextRound, 2);
|
|
assert.equal(
|
|
parsed.scoring?.nextRoundQuestions[0]?.id,
|
|
"health_crisis_or_low_period",
|
|
);
|
|
});
|
|
|
|
test("journey client rejects an applied rectification result", () => {
|
|
assert.throws(() => parseJourneyResponse({
|
|
caseId: highConfirmationTurn.caseId,
|
|
snapshot: { ...snapshot, canApply: true, activeTime: "14:24" },
|
|
questionnaire: null,
|
|
scoring: null,
|
|
}));
|
|
});
|
|
|
|
test("journey client accepts only a guarded high-confidence confirmation", () => {
|
|
const parsed = parseJourneyResponse({
|
|
...highConfirmationTurn,
|
|
turnVersion: undefined,
|
|
});
|
|
|
|
assert.equal(parsed.snapshot.state, "confirming");
|
|
assert.equal(
|
|
parsed.candidateResult?.winningSegment?.representativeTime,
|
|
"14:24",
|
|
);
|
|
assert.throws(() => parseJourneyResponse({
|
|
...parsed,
|
|
turnVersion: undefined,
|
|
snapshot: { ...parsed.snapshot, state: "candidate", input: "candidate_actions" },
|
|
}));
|
|
});
|
|
|
|
test("client rejects a nonterminal turn without nextAction", () => {
|
|
assert.throws(() => parseJourneyResponse({
|
|
...highConfirmationTurn,
|
|
nextAction: undefined,
|
|
}));
|
|
});
|
|
|
|
test("client derives Agent permission without exposing legacy canApply", () => {
|
|
const parsed = parseJourneyResponse(highConfirmationTurn);
|
|
|
|
assert.equal(parsed.permissions.canConfirmCandidate, true);
|
|
assert.equal("canApply" in parsed.permissions, false);
|
|
});
|
|
|
|
test("versioned client responses require every response field", () => {
|
|
assert.throws(() => parseJourneyResponse({
|
|
...highConfirmationTurn,
|
|
answers: undefined,
|
|
}));
|
|
});
|
|
|
|
test("client preserves every candidate varga sign", () => {
|
|
const sample = {
|
|
ascendantSign: "Aries",
|
|
d4Sign: "Taurus",
|
|
d9Sign: "Gemini",
|
|
d10Sign: "Cancer",
|
|
d24Sign: "Leo",
|
|
d30Sign: "Virgo",
|
|
};
|
|
const parsed = parseJourneyResponse({
|
|
...highConfirmationTurn,
|
|
questionnaire: { questions: [], samples: [sample], raw: {} },
|
|
});
|
|
|
|
assert.deepEqual(parsed.questionnaire?.samples[0], sample);
|
|
});
|
|
|
|
test("versioned response parsing returns a readonly public boundary", () => {
|
|
const parsed = parseJourneyResponse(highConfirmationTurn);
|
|
|
|
assert.equal(Object.isFrozen(parsed), true);
|
|
assert.equal(Object.isFrozen(parsed.candidateResult), true);
|
|
});
|