Files
Jyotisha/frontend/tests/birth-time-journey-service.test.ts
2026-07-19 14:48:02 +08:00

217 lines
7.4 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import { createBirthTimeJourneyService } from "../src/lib/birth-time-journey-service.ts";
import type { LegacyBirthTimeJourneyEngine, StoredRectificationCase } from "../src/lib/birth-time-journey-service.ts";
import {
approximateAssessment,
hospitalAssessment,
journeyCaseId,
memoryStore,
scanWithSigns,
unusedJourneyEngine,
} from "./birth-time-journey-test-support.ts";
test("journey service activates a stable hospital record and persists its scan", async () => {
const memory = memoryStore();
let receivedUncertainty = 0;
const engine: LegacyBirthTimeJourneyEngine = {
...unusedJourneyEngine,
async scan(input) {
receivedUncertainty = input.uncertaintyMinutes;
return scanWithSigns(["Cancer", "Cancer", "Cancer"]);
},
};
const service = createBirthTimeJourneyService({ store: memory.store, engine });
const result = await service.assess("user-1", hospitalAssessment);
assert.equal(receivedUncertainty, 2);
assert.equal(result.snapshot.route, "direct_chart");
assert.equal(result.snapshot.activeTime, "08:16");
assert.equal(result.caseId, journeyCaseId);
assert.deepEqual(memory.savedAssessment()?.candidateScan, result.questionnaire);
});
test("journey service fails a scanner error closed without activating the time", async () => {
const memory = memoryStore();
const engine: LegacyBirthTimeJourneyEngine = {
...unusedJourneyEngine,
async scan() {
throw new TypeError("scanner offline");
},
};
const service = createBirthTimeJourneyService({ store: memory.store, engine });
const result = await service.assess("user-1", hospitalAssessment);
assert.equal(result.snapshot.route, "rectification");
assert.equal(result.snapshot.canApply, false);
assert.equal(result.questionnaire, null);
assert.equal(memory.savedAssessment()?.snapshot.activeTime, null);
});
test("journey service projects a fresh active rectification into one baseline ask", async () => {
const service = createBirthTimeJourneyService({
store: memoryStore().store,
engine: {
...unusedJourneyEngine,
async scan() { return scanWithSigns(["Cancer", "Leo", "Virgo"]); },
},
});
const result = await service.assess("user-1", approximateAssessment);
assert.equal(result.nextAction.kind, "ask_baseline_evidence");
assert.equal(result.progress.phase, "baseline");
});
test("journey service accumulates legacy answers while preserving the application gate", async () => {
const questionnaire = scanWithSigns(["Cancer", "Leo", "Leo"]).questionnaire;
const assessmentService = createBirthTimeJourneyService({
store: memoryStore().store,
engine: {
...unusedJourneyEngine,
async scan() { return { questionnaire }; },
},
});
const assessed = await assessmentService.assess("user-1", approximateAssessment);
const storedCase: StoredRectificationCase = {
id: journeyCaseId,
userId: "user-1",
journeyProtocol: "legacy-guided-v1",
snapshot: assessed.snapshot,
questionnaire,
answers: { education_environment_shift: "A" },
};
const memory = memoryStore(storedCase);
let scoredAnswers: Readonly<Record<string, "A" | "B" | "C" | "D">> = {};
const service = createBirthTimeJourneyService({
store: memory.store,
engine: {
...unusedJourneyEngine,
async score(input) {
scoredAnswers = input.answers;
return {
answeredCount: 3,
candidateClusterRankings: [{ cluster: "middle_candidate_cluster", score: 5 }],
nextRound: 2,
nextRoundQuestions: [],
raw: { next_round: 2 },
};
},
},
});
const result = await service.answerQuestion(
"user-1",
journeyCaseId,
"career_responsibility_pressure",
"B",
);
assert.deepEqual(scoredAnswers, {
education_environment_shift: "A",
career_responsibility_pressure: "B",
});
assert.equal(result.snapshot.state, "candidate");
assert.equal(result.snapshot.canApply, false);
assert.deepEqual(memory.savedCase()?.answers, scoredAnswers);
});
test("journey service upgrades an owner-scoped unfinished legacy case on resume", async () => {
const storedCase: StoredRectificationCase = {
id: journeyCaseId,
userId: "user-1",
journeyProtocol: "legacy-guided-v1",
snapshot: {
state: "rectifying",
assistantIntent: "continue_rectification_questions",
input: "rectification_questions",
route: "rectification",
confidence: null,
canApply: false,
activeTime: null,
reportedRange: { label: "14:00—15:00", startTime: "14:00", endTime: "15:00" },
},
questionnaire: scanWithSigns(["Cancer", "Leo"]).questionnaire,
answers: { education_environment_shift: "A" },
};
const memory = memoryStore(storedCase);
const service = createBirthTimeJourneyService({
store: memory.store,
engine: unusedJourneyEngine,
});
const result = await service.resume("user-1", journeyCaseId);
assert.equal(result.caseId, journeyCaseId);
assert.equal(result.journeyProtocol, "dynamic-choice-v2");
assert.deepEqual(result.answers, {});
assert.deepEqual(memory.savedCase()?.answers, { education_environment_shift: "A" });
assert.equal(result.snapshot.canApply, false);
});
test("journey service heals a completed legacy questionnaire into life-event collection", async () => {
const storedCase: StoredRectificationCase = {
id: journeyCaseId,
userId: "user-1",
journeyProtocol: "legacy-guided-v1",
snapshot: {
state: "candidate",
assistantIntent: "present_saved_candidate_range",
input: "rectification_questions",
route: "rectification",
confidence: null,
canApply: false,
activeTime: null,
reportedRange: { label: "04:00—07:59", startTime: "04:00", endTime: "07:59" },
},
questionnaire: scanWithSigns(["Cancer", "Leo"]).questionnaire,
answers: { education_environment_shift: "A" },
scoring: {
answeredCount: 8,
candidateClusterRankings: [{ cluster: "middle_candidate_cluster", score: 5 }],
nextRound: null,
nextRoundQuestions: [],
raw: { answered_count: 8, next_round: null, next_round_questions: [] },
},
};
const memory = memoryStore(storedCase);
const service = createBirthTimeJourneyService({ store: memory.store, engine: unusedJourneyEngine });
const result = await service.resume("user-1", journeyCaseId);
assert.equal(result.snapshot.state, "rectifying");
assert.equal(result.snapshot.input, "life_events");
assert.equal(memory.savedCase()?.snapshot.input, "life_events");
});
test("journey service resumes a fail-closed case without a questionnaire", async () => {
const storedCase: StoredRectificationCase = {
id: journeyCaseId,
userId: "user-1",
journeyProtocol: "legacy-guided-v1",
snapshot: {
state: "rectifying",
assistantIntent: "explain_assessment_unavailable",
input: "rectification_questions",
route: "rectification",
confidence: null,
canApply: false,
activeTime: null,
reportedRange: { label: "08:14—08:18", startTime: "08:14", endTime: "08:18" },
},
questionnaire: null,
answers: {},
};
const service = createBirthTimeJourneyService({
store: memoryStore(storedCase).store,
engine: unusedJourneyEngine,
});
const result = await service.resume("user-1", journeyCaseId);
assert.equal(result.questionnaire, null);
assert.equal(result.snapshot.canApply, false);
});