Files
Jyotisha/frontend/tests/synastry-report-surface.test.ts
T
jesse-uxandGrok (agent loop) 352d45b2ef
Independent Staging Quality Gate / validate (push) Failing after 9m12s
Independent Staging Quality Gate / publish (push) Skipped
外壳换成组件库:侧栏可拖宽,会话可排序(#105)。
桌面侧栏可在 200 到 360 像素之间拖宽,拖到最左收起,宽度记在本机。手机从左边滑出。会话在同一组里拖动排序,顺序写入可空的 sidebar_order,收藏仍置顶。账户菜单、设置、反馈和退出确认改用组件库。顶栏点数只显示图标和数字。启程清单还在。菜单、拖宽、拖动排序和翻页在首屏之后再载入。

自测:tsc 退出码 0;npm run lint 0 error、121 warning;改到的前端测试 205 项全过;npm run build 后首页仍是 static;首屏 gzip 630350,相对 8f7c0f7d 的 621226 为 +1.47%。test:db 92 项里 79 过、13 败,失败名与 Windows 已知清单一致,排序列在通过的 ok 37。没有跑全量 npm test,没有跑 Python 快速门。没有登录态,没有在浏览器里拖侧栏。

Co-Authored-By: Grok (agent loop)
2026-10-25 01:41:19 +08:00

94 lines
4.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from "node:assert/strict";
import test from "node:test";
import { readFileSync } from "node:fs";
import { createElement } from "react";
import { renderToStaticMarkup } from "react-dom/server";
import { PathnameContext } from "next/dist/shared/lib/hooks-client-context.shared-runtime";
import { AppSidebar } from "../src/components/app-sidebar.tsx";
import { SidebarProvider } from "../src/components/ui/sidebar.tsx";
import { reportSurfaceRedirect } from "../src/lib/synastry-report-href.ts";
function renderSidebar(pathname: string) {
return renderToStaticMarkup(
createElement(
PathnameContext.Provider,
{ value: pathname },
createElement(
SidebarProvider,
null,
createElement(AppSidebar, {
sessions: [],
activeSessionId: null,
compatibilityEnabled: true,
account: {
name: "示例甲",
email: "fictional@example.invalid",
credits: 12,
initial: "示",
avatar: null,
},
}),
),
),
);
}
function navAnchor(markup: string, label: string) {
// 原值:锚点类名 `report-nav-button`
// 新值:锚点类名 `sidebar-nav-link`
// 原因:K1 侧栏导航共用一个类,合盘入口仍是这个链接
const anchors = markup.match(/<a\b[^>]*\bsidebar-nav-link\b[^>]*>[\s\S]*?<\/a>/g) ?? [];
const hit = anchors.find((anchor) => anchor.includes(`>${label}<`));
assert.ok(hit, `sidebar nav link missing: ${label}`);
return hit;
}
const read = (path: string) => readFileSync(new URL(path, import.meta.url), "utf8");
test("an old synastry url moves to the synastry route and keeps the language", () => {
assert.equal(
reportSurfaceRedirect({ surface: "personal", reportType: "synastry_full", reportId: "abc", language: "en" }),
"/synastry/abc?lang=en",
);
assert.equal(
reportSurfaceRedirect({ surface: "synastry", reportType: "personal_full", reportId: "abc", language: "zh" }),
"/reports/abc",
);
assert.equal(
reportSurfaceRedirect({ surface: "synastry", reportType: "synastry_full", reportId: "abc", language: "zh" }),
null,
);
assert.equal(
reportSurfaceRedirect({ surface: "personal", reportType: "personal_full", reportId: "abc", language: "en" }),
null,
);
});
test("the synastry route reuses the reader and the sidebar stays on 婚恋合盘", () => {
const page = read("../src/app/(app)/synastry/[reportId]/page.tsx");
const reader = read("../src/components/personal-report/personal-report-page.tsx");
const sidebar = read("../src/components/app-sidebar.tsx");
const picker = read("../src/components/synastry/synastry-picker.tsx");
const center = read("../src/components/personal-report/personal-report-center.tsx");
assert.match(page, /title: "婚恋合盘 · Jyotisha"/);
assert.match(page, /readReportLanguage\(lang\)/);
assert.match(page, /surface="synastry"/);
assert.match(reader, /window\.location\.replace\(redirectTo\)/);
assert.match(sidebar, /\{ href: "\/synastry", label: "婚恋合盘"/);
assert.match(sidebar, /pathname === href \|\| pathname\.startsWith\(`\$\{href\}\/`\)/);
// 原值: assert.equal("/synastry/abc".startsWith("/synastry/"), true)
// 新值: pathname 为 /synastry/<id> 时渲染侧栏,当前项(data-active="true")是「婚恋合盘」,不是「我的报告」
// 原因: 原断言永远成立,没有渲染侧栏(issue #85 G3)
const markup = renderSidebar("/synastry/abc");
const synastry = navAnchor(markup, "婚恋合盘");
const reports = navAnchor(markup, "我的报告");
assert.match(synastry, /\bdata-active="true"/);
assert.doesNotMatch(reports, /\bdata-active="true"/);
assert.doesNotMatch(reports, /aria-current="page"/);
assert.match(picker, /window\.location\.assign\(`\/synastry\/\$\{payload\.report\.id\}`\)/);
assert.match(picker, /href=\{`\/synastry\/\$\{report\.id\}`\}/);
assert.doesNotMatch(picker, /\/reports\/\$\{/);
assert.match(center, /reportType === "synastry_full" \? `\/synastry\/\$\{id\}` : `\/reports\/\$\{id\}`/);
});