Files
Jyotisha/frontend/tests/session-list-provider.test.ts
T
Jesse_ChenandClaude Opus 5.5 2fd1e2b05d perf(home): the HTML sends the cold-boot reads before the bundle runs (BUG-1127)
An inline classic script on / starts account, people list, sessions and
models; the boot takes each once from one global, falls back to the normal
request on failure, drops another person's or another account's list, and
trusts nothing older than 30s. Paths and init come from one shared module.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
2026-10-01 00:19:56 +08:00

76 lines
5.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 bootReads = readFileSync(new URL("../src/lib/boot-early-reads.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", () => {
// 原值:provider 里内联 fetch(`/api/sessions?limit=${SESSION_PAGE_SIZE}&subject=${encodeURIComponent(subjectId)}`)。
// 新值:provider 用 fetchSessionPage → fetch(bootSessionsPath(subjectId), …),路径由 boot-early-reads.ts 生成。
// 原因:首页 HTML 的早发请求(TASK-home-first-load T8)与正常请求必须同一路径,共用一个常量防漂移。
assert.match(provider, /fetch\(bootSessionsPath\(subjectId\), \{ \.\.\.BOOT_READ_INIT, signal \}\)/);
assert.match(bootReads, /`\/api\/sessions\?limit=\$\{SESSION_PAGE_SIZE\}&subject=\$\{encodeURIComponent\(subjectId\)\}`/);
// 原值:provider 自己 fetch("/api/account")。
// 新值:provider 调用 readBootAccount,fetch 在 current-subject.ts,同一次加载只打一次。
// 原因:人物目录和会话列表要共享账户结果。
assert.match(provider, /readBootAccount\(\)/);
// 原值:accountRead 里 fetch("/api/account"。
// 新值:fetch(BOOT_ACCOUNT_PATH, BOOT_READ_INIT),常量 BOOT_ACCOUNT_PATH = "/api/account" 在 boot-early-reads.ts。
// 原因:同上,早发请求与正常请求共用常量;仍只在 readBootAccount 一处发。
assert.match(accountRead, /fetch\(BOOT_ACCOUNT_PATH, BOOT_READ_INIT\)/);
assert.match(bootReads, /BOOT_ACCOUNT_PATH = "\/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\}/);
});