Request signs out everywhere and freezes paid routes (423 + DB triggers); signing in within 7 days shows the pending gate with 撤销注销. A periodic idempotent worker purges personal content afterwards and keeps finance rows against a tombstoned identity. Read-only admin list. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
53 lines
3.1 KiB
TypeScript
53 lines
3.1 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import test from "node:test";
|
|
|
|
import { homeSurface as page } from "./home-surface.ts";
|
|
const sidebar = readFileSync(new URL("../src/components/app-sidebar.tsx", import.meta.url), "utf8");
|
|
const overlay = readFileSync(new URL("../src/components/account-dialog-overlay.tsx", import.meta.url), "utf8");
|
|
|
|
test("account menu exposes the four MVP settings sections", () => {
|
|
assert.match(sidebar, /<span>个人资料<\/span>/);
|
|
assert.match(sidebar, /href: "\/people", label: "星盘档案"/);
|
|
assert.doesNotMatch(sidebar, /<span>星盘资料<\/span>/);
|
|
assert.match(sidebar, /<span>通用设置<\/span>/);
|
|
assert.match(sidebar, /<span>账户与点数<\/span>/);
|
|
assert.match(sidebar, /onOpenGeneral/);
|
|
});
|
|
|
|
test("personal profile is limited to account basics and links to chart settings", () => {
|
|
const profile = readFileSync(new URL("../src/components/profile-panel.tsx", import.meta.url), "utf8");
|
|
assert.match(profile, /账户信息/);
|
|
assert.match(profile, /登录邮箱/);
|
|
assert.doesNotMatch(profile, /管理星盘资料/);
|
|
assert.doesNotMatch(profile, /<ProfileFields/);
|
|
assert.doesNotMatch(profile, /出生资料/);
|
|
});
|
|
|
|
test("the chart library owns self-profile editing and keeps other-chart save separate", () => {
|
|
const charts = readFileSync(new URL("../src/components/people/people-page.tsx", import.meta.url), "utf8");
|
|
const form = readFileSync(new URL("../src/components/chart-profile-form.tsx", import.meta.url), "utf8");
|
|
const personalProfile = readFileSync(new URL("../src/components/profile-panel.tsx", import.meta.url), "utf8");
|
|
// 原值 / 新值 / 原因:已退役面板编辑本人 / 本人账户来源、独立他人保存 / /people 是唯一入口,不伪造已移除的本人编辑。
|
|
assert.match(charts, /readProfile\(account\.profile\)/);
|
|
assert.match(charts, /selectedId && selected\?\.role === "other"/);
|
|
// 原值: /onSubmit=\{\(event\) => void saveOther\(event\)\}/
|
|
// 新值: 同一张表按 editingSelf 分给 saveSelf / saveOther
|
|
// 原因: BUG-1081——本人在星盘档案可编辑,保存走 PATCH /api/account,他人仍走 chart-profiles
|
|
assert.match(charts, /onSubmit=\{\(event\) => void \(editingSelf \? saveSelf\(event\) : saveOther\(event\)\)\}/);
|
|
assert.match(charts, /await saveSelfProfile\(draft\)/);
|
|
assert.doesNotMatch(charts, /setEditingSelfChart/);
|
|
assert.match(form, /AyanamsaPreferenceField/);
|
|
assert.doesNotMatch(personalProfile, /AyanamsaPreferenceField/);
|
|
});
|
|
|
|
test("the general dialog renders the shared theme preference panel", () => {
|
|
assert.match(overlay, /dialog: "profile" \| "chart-library" \| "billing" \| "general"/);
|
|
assert.match(overlay, /renderGeneral: \(\) => ReactNode/);
|
|
assert.match(overlay, /return model\.renderGeneral\(\)/);
|
|
// 原值: /renderGeneral\(\) \{\s*return <ThemePreferencePanel \/>;/
|
|
// 新值: 主题面板仍是第一项,其后挂注销账号区
|
|
// 原因: 2026-09-30 自助注销入口放在通用设置底部,头像菜单不加入口
|
|
assert.match(page, /renderGeneral\(\) \{\s*return <><ThemePreferencePanel \/><AccountDeletionSection \/><\/>;/);
|
|
});
|