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, //); assert.equal(layout.match(//g)?.length, 1); assert.match(layout, //); assert.equal(layout.match(/ { 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, /\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, /\s*\{children\}/); });