Files
Jyotisha/frontend/tests/session-list-provider.test.ts
T
jesse-ux d08ffdc0a6
Independent Staging Quality Gate / validate (push) Failing after 6m46s
Independent Staging Quality Gate / publish (push) Skipped
fix: keep western labels near their planets and chats on the current person
Cap planet captions at 30 degrees with a third ring, fall back only within the current person's sessions, and load self when the people catalog fails.
2026-09-25 23:02:17 +08:00

67 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 { readFileSync } from "node:fs";
import test from "node:test";
const provider = readFileSync(new URL("../src/lib/session-list-context.tsx", import.meta.url), "utf8");
const accountRead = readFileSync(new URL("../src/lib/current-subject.ts", import.meta.url), "utf8");
const layout = readFileSync(new URL("../src/app/(app)/layout.tsx", import.meta.url), "utf8");
const page = readFileSync(new URL("../src/app/(app)/page.tsx", import.meta.url), "utf8");
const sessionHook = readFileSync(new URL("../src/hooks/use-session-management.ts", import.meta.url), "utf8");
test("the app layout owns one SessionListProvider and one SidebarProvider", () => {
assert.match(layout, /<SessionListProvider>/);
assert.equal(layout.match(/<SessionListProvider>/g)?.length, 1);
assert.match(layout, /<SidebarProvider escapeBlocked=\{registration\?\.escapeBlocked \?\? false\}>/);
assert.equal(layout.match(/<SidebarProvider/g)?.length, 1);
assert.match(layout, /<AppSidebar/);
assert.doesNotMatch(page, /<SidebarProvider/);
assert.doesNotMatch(page, /<AppSidebar/);
});
test("the provider fetches the session list once and home does not fetch it again", () => {
assert.match(provider, /fetch\(`\/api\/sessions\?limit=\$\{SESSION_PAGE_SIZE\}&subject=\$\{encodeURIComponent\(subjectId\)\}`/);
// 原值:provider 自己 fetch("/api/account")。
// 新值:provider 调用 readBootAccount,fetch 在 current-subject.ts,同一次加载只打一次。
// 原因:人物目录和会话列表要共享账户结果。
assert.match(provider, /readBootAccount\(\)/);
assert.match(accountRead, /fetch\("\/api\/account"/);
// 原值: page.tsx 里 `await sessionListReady;`
// 新值: page.tsx 把 sessionListReady 交给 runHomeBootstrap,函数里 `await deps.sessionListReady`。
// 原因: 启动流程搬出首页后,会话列表仍只由 provider 拉一次。
const bootstrapRun = readFileSync(new URL("../src/lib/home-bootstrap-run.ts", import.meta.url), "utf8");
assert.match(page, /sessionListReady,/);
// 原值 / 新值 / 原因:固定 ready promise / 当前 reload gate / 切人期间回 Home 必须等新绑定,不能读空 boot 误登出。
assert.match(bootstrapRun, /await \(deps\.waitForSessionList\?\.\(\) \?\? deps\.sessionListReady\);/);
assert.match(page, /waitForSessionList,/);
assert.doesNotMatch(page, /fetchSessions\(/);
assert.doesNotMatch(page, /fetchAccount\(/);
assert.match(page, /useHomeShellRegistration\(/);
});
test("a 401 clears the list and marks signedOut", () => {
// 原值:provider 里 accountResponse.status === 401。
// 新值:readBootAccount 返回 status 401,provider 写成 accountResult.status === 401,仍 signedOut。
// 原因:账户读取挪到共享函数后,401 仍先于会话请求结束,不串第二次账户请求。
assert.match(provider, /accountResult\.status === 401/);
assert.match(accountRead, /response\.status === 401/);
assert.match(provider, /sessionResponse\.status === 401/);
assert.match(provider, /signedOut: true/);
assert.doesNotMatch(provider, /localStorage|sessionStorage|document\.cookie|indexedDB/i);
});
test("session writes no longer invalidate a second cache", () => {
assert.doesNotMatch(sessionHook, /invalidateSidebarCache/);
});
test("only the shell consumes registration and it passes Home children through unchanged", () => {
assert.match(layout, /const registration = useShellRegistration\(\)/);
assert.match(layout, /sessionListSidebarModel\(list, registration\)/);
assert.doesNotMatch(layout, /list\.registration|cloneElement/);
assert.match(layout, /<SidebarInset[\s\S]*>\s*\{children\}\s*<\/SidebarInset>/);
assert.doesNotMatch(page, /useShellRegistration/);
const dataValue = provider.slice(provider.indexOf("const value = useMemo"), provider.indexOf("return (", provider.indexOf("const value = useMemo")));
assert.doesNotMatch(dataValue, /\bregistration\b/);
assert.match(dataValue, /registerShellControls/);
assert.match(provider, /<ShellRegistrationContext\.Provider value=\{registration\}>\s*\{children\}/);
});