Files
Jyotisha/frontend/tests/onboarding-journey-data.test.ts
T
jesse-uxandGrok (agent loop) fdd592d3f3 feat: 新账户首问免费,档案可标明关系
只做启程(一):同一笔预扣覆盖已公布的标准档,更贵的只扣差价;引导状态与人物关系只加列。tsc 与 lint 通过。test:db 91 项,失败 14,其中 13 条为 Windows 已知失败;校正遥测单独重跑通过。

Co-Authored-By: Grok (agent loop)
2026-10-23 00:34:28 +08:00

83 lines
3.8 KiB
TypeScript

import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import test from "node:test";
import { parseChartSubjectWrite, libraryProfileFromSubjectRow } from "../src/lib/chart-subject-write.ts";
import { readProfile } from "../src/lib/home-profile.ts";
import { parseOnboardingPatch, parseOnboardingState } from "../src/lib/onboarding-state.ts";
import { parsePersonRelation, personRelationLabel } from "../src/lib/person-relation.ts";
const route = readFileSync(new URL("../src/app/api/onboarding-state/route.ts", import.meta.url), "utf8");
const account = readFileSync(new URL("../src/app/api/account/route.ts", import.meta.url), "utf8");
test("person relation accepts only the five household values", () => {
assert.equal(parsePersonRelation("child"), "child");
assert.equal(parsePersonRelation("family"), null);
assert.equal(parsePersonRelation(null), null);
assert.equal(personRelationLabel(null), "其他");
assert.equal(personRelationLabel("parent"), "父母");
assert.equal(personRelationLabel("other"), "其他");
});
test("a chart write omits relation unless the client sent the key", () => {
const omitted = parseChartSubjectWrite({ name: "示例乙", date: "1992-03-12" });
assert.equal(omitted.ok, true);
if (!omitted.ok) return;
assert.equal("relation" in omitted.write.columns, false);
const child = parseChartSubjectWrite({ name: "示例乙", date: "1992-03-12", relation: "child" });
assert.equal(child.ok, true);
if (!child.ok) return;
assert.equal(child.write.columns.relation, "child");
const cleared = parseChartSubjectWrite({ name: "示例乙", date: "1992-03-12", relation: null });
assert.equal(cleared.ok, true);
if (!cleared.ok) return;
assert.equal(cleared.write.columns.relation, null);
const illegal = parseChartSubjectWrite({ name: "示例乙", date: "1992-03-12", relation: "client" });
assert.equal(illegal.ok, false);
});
test("an old chart row with a null relation still reads", () => {
const profile = libraryProfileFromSubjectRow({ name: "示例乙", relation: null, profile: {} });
assert.equal(profile.relation, null);
assert.equal(readProfile(profile).relation, null);
assert.equal("relation" in readProfile({ name: "示例乙" }), false);
});
test("onboarding state keeps only the three keys and the hint list", () => {
const saved = parseOnboardingPatch({
chartVisitedAt: "2026-10-22T00:00:00Z",
hintsSeen: ["follow-up", "tab-chart"],
});
assert.equal(saved.ok, true);
assert.equal(parseOnboardingPatch({ userId: "someone-else" }).ok, false);
assert.equal(parseOnboardingPatch({ hintsSeen: ["not-a-hint"] }).ok, false);
assert.equal(parseOnboardingPatch({ checklistDismissedAt: "tomorrow" }).ok, false);
assert.deepEqual(parseOnboardingState({
chartVisitedAt: "2026-10-22T00:00:00Z",
hintsSeen: ["follow-up"],
extra: true,
}), {
chartVisitedAt: "2026-10-22T00:00:00Z",
hintsSeen: ["follow-up"],
});
});
test("the onboarding route is login-only and writes the session user", () => {
assert.match(route, /请先登录/);
assert.match(route, /status: 401/);
assert.match(route, /p_user_id: user\.id/);
assert.doesNotMatch(route, /userId|body\.id|p_user_id: parsed/);
});
test("account GET exposes firstConsultFree from the column, and a missing column is not free", () => {
assert.match(account, /first_consult_free_used_at/);
assert.match(account, /firstConsultFree: firstConsultFreeFromProfile\(profile\)/);
assert.match(account, /hasOwnProperty\.call\(profile, "first_consult_free_used_at"\)/);
const getSource = account.slice(account.indexOf("export async function GET"), account.indexOf("export async function PATCH"));
const fallbacks = getSource.slice(getSource.indexOf("isMissingProfileColumn"));
assert.equal(fallbacks.includes("first_consult_free_used_at"), false);
});