Homepage no longer waits on /api/onboarding for six starter questions. Natal answers show the spoken layer first; the Level 2 skeleton sits in a collapsed 完整分析 block. Wide tables scroll sideways on a phone. Form inputs are 16px so iOS does not zoom on focus.
106 lines
6.3 KiB
TypeScript
106 lines
6.3 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import test from "node:test";
|
|
import {
|
|
consultationDomainIds,
|
|
consultationDomainRegistry,
|
|
normalizeConsultationDomain,
|
|
validateConsultationDomainPlan,
|
|
} from "../src/lib/consultation-domain-registry.ts";
|
|
import { consultationInputSchema } from "../src/mastra/consultation-workflow.ts";
|
|
import { chatSessionWriteSchema } from "../src/lib/chat-session-write-contract.ts";
|
|
import {
|
|
defaultGuidedJyotishTopics,
|
|
generalGuidedJyotishTopics,
|
|
} from "../src/lib/guided-jyotish-topics.ts";
|
|
|
|
const expected = ["career", "marriage", "wealth", "health", "education", "migration", "family", "annual", "timing", "general"];
|
|
|
|
test("domain registry is the complete allowlist used by UI and workflow input", () => {
|
|
assert.deepEqual([...consultationDomainIds], expected);
|
|
assert.deepEqual(consultationDomainRegistry.map((domain) => domain.id), expected);
|
|
assert.deepEqual(defaultGuidedJyotishTopics.map((topic) => topic.id), expected);
|
|
for (const theme of expected) {
|
|
assert.equal(consultationInputSchema.safeParse({ year: 2000, month: 1, day: 1, hour: 0, minute: 0, lat: 0, lon: 0, tz: 0, city: "Test", question: "test", theme }).success, true);
|
|
}
|
|
});
|
|
|
|
test("aliases normalize to stable persisted domain ids", () => {
|
|
assert.equal(normalizeConsultationDomain("relationship"), "marriage");
|
|
assert.equal(normalizeConsultationDomain("finance"), "wealth");
|
|
assert.equal(normalizeConsultationDomain("health-pressure"), "health");
|
|
assert.equal(normalizeConsultationDomain("home"), "migration");
|
|
assert.equal(normalizeConsultationDomain("unknown"), null);
|
|
});
|
|
|
|
test("server domain plans are allowlisted, ordered and deduplicated", () => {
|
|
assert.deepEqual(validateConsultationDomainPlan(["career", "finance", "career", "home"]), ["career", "wealth", "migration"]);
|
|
assert.throws(() => validateConsultationDomainPlan([]), /invalid_consultation_domain_plan/);
|
|
assert.throws(() => validateConsultationDomainPlan(["career", "prashna"]), /unsupported_consultation_domain/);
|
|
});
|
|
|
|
test("default guided topics derive every canonical domain with evidence and claim boundaries", () => {
|
|
// Moved from starter-questions.test.ts when homepage theme cards were removed.
|
|
const guidedTopicsSource = readFileSync(new URL("../src/lib/guided-jyotish-topics.ts", import.meta.url), "utf8");
|
|
assert.equal(consultationDomainIds.length, 10);
|
|
assert.deepEqual(consultationDomainRegistry.map((domain) => domain.id), [...consultationDomainIds]);
|
|
assert.match(guidedTopicsSource, /consultationDomainRegistry\.map/);
|
|
assert.deepEqual(defaultGuidedJyotishTopics.map((topic) => topic.id), [...consultationDomainIds]);
|
|
assert.equal(defaultGuidedJyotishTopics.length, consultationDomainRegistry.length);
|
|
|
|
for (const [index, topic] of defaultGuidedJyotishTopics.entries()) {
|
|
const domain = consultationDomainRegistry[index];
|
|
assert.equal(topic.id, domain.id);
|
|
assert.equal(topic.label, domain.label);
|
|
assert.equal(topic.prompt, domain.prompt);
|
|
assert.equal(topic.strictWorkflowRoute, domain.strictWorkflowRoute);
|
|
assert.deepEqual(topic.evidencePreview, [...domain.evidencePreview]);
|
|
assert.equal(topic.confidenceCap, domain.confidenceCap);
|
|
assert.equal(topic.claimBoundary, domain.claimBoundary);
|
|
}
|
|
|
|
const domainById = new Map(consultationDomainRegistry.map((domain) => [domain.id, domain]));
|
|
assert.match(domainById.get("career")?.requiredLayers.join(" ") ?? "", /D10/);
|
|
assert.match(domainById.get("marriage")?.requiredLayers.join(" ") ?? "", /D9/);
|
|
assert.match(domainById.get("wealth")?.requiredLayers.join(" ") ?? "", /Ashtakavarga/);
|
|
assert.match(domainById.get("timing")?.requiredLayers.join(" ") ?? "", /negative holdout gate/);
|
|
});
|
|
|
|
test("general guided topics keep user-centered prompts and the same claim boundaries", () => {
|
|
// Moved from starter-questions.test.ts. Homepage no longer renders these cards;
|
|
// the registry remains the contract for personal-report and no-minute copy.
|
|
assert.deepEqual(generalGuidedJyotishTopics.map((topic) => topic.id), [...consultationDomainIds]);
|
|
assert.deepEqual(generalGuidedJyotishTopics.map((topic) => topic.prompt), [
|
|
"请帮我梳理目前的事业方向和下一步重点。",
|
|
"请帮我看看我在关系中容易重复什么模式。",
|
|
"请帮我分析目前的财富重点、风险和更稳妥的选择。",
|
|
"请从非医疗诊断的角度,帮我看看近期的身心压力和调整重点。",
|
|
"请帮我看看我更适合怎样学习,以及如何安排下一步。",
|
|
"请帮我分析现阶段是否适合迁居、置业或考虑海外发展。",
|
|
"请帮我看看家庭关系中最需要处理的问题和责任边界。",
|
|
"请帮我看看未来一年的主要趋势、机会和需要留意的阶段。",
|
|
"请帮我看看目前适合推进什么,哪些事情需要再等等。",
|
|
"请结合我的情况,帮我找出现在最值得优先处理的三个问题。",
|
|
]);
|
|
for (const topic of generalGuidedJyotishTopics) {
|
|
const personalTopic = defaultGuidedJyotishTopics.find((candidate) => candidate.id === topic.id);
|
|
assert.ok(personalTopic);
|
|
assert.equal(topic.label, personalTopic.label);
|
|
assert.equal(topic.strictWorkflowRoute, personalTopic.strictWorkflowRoute);
|
|
assert.deepEqual(topic.evidencePreview, personalTopic.evidencePreview);
|
|
assert.equal(topic.confidenceCap, personalTopic.confidenceCap);
|
|
assert.equal(topic.claimBoundary, personalTopic.claimBoundary);
|
|
assert.notEqual(topic.prompt, personalTopic.prompt);
|
|
}
|
|
assert.ok(generalGuidedJyotishTopics.every((topic) => /我/.test(topic.prompt)));
|
|
assert.ok(generalGuidedJyotishTopics.every((topic) => !/印度占星|一般如何|通常|哪些因素|证据层/.test(topic.prompt)));
|
|
});
|
|
|
|
test("session persistence accepts every canonical domain and rejects product routes", () => {
|
|
for (const theme of expected) {
|
|
const parsed = chatSessionWriteSchema.safeParse({ title: "Test", theme, model_id: "test", messages: [], session_type: "consultation", rectification_case_id: null, updated_at: "2026-08-14T00:00:00.000Z" });
|
|
assert.equal(parsed.success, true, theme);
|
|
}
|
|
assert.equal(chatSessionWriteSchema.safeParse({ title: "Test", theme: "muhurta", model_id: "test", messages: [], session_type: "consultation", rectification_case_id: null, updated_at: "2026-08-14T00:00:00.000Z" }).success, false);
|
|
});
|