返回 DeepSeek-Reasonix
clear-session-identity-contract.test.ts
根目录 / desktop / frontend / src / __tests__ / clear-session-identity-contract.test.ts
1 // Run: npx tsx src/__tests__/clear-session-identity-contract.test.ts
2 //
3 // clearSession must fence transcript identity so "clear → immediately switch
4 // mode/layout" cannot re-paint the destroyed session from TranscriptStore or
5 // a hydrate started with stale meta.sessionPath.
6
7 import assert from "node:assert/strict";
8 import { readFileSync } from "node:fs";
9 import { dirname, join } from "node:path";
10 import { fileURLToPath } from "node:url";
11
12 const root = join(dirname(fileURLToPath(import.meta.url)), "..");
13 const controller = readFileSync(join(root, "lib/useController.ts"), "utf8");
14 const store = readFileSync(join(root, "lib/transcriptStore.ts"), "utf8");
15 const types = readFileSync(join(root, "lib/types.ts"), "utf8");
16 const historyTypes = readFileSync(join(root, "lib/historyTypes.ts"), "utf8");
17
18 assert.match(types + historyTypes, /export interface SessionClearResult/, "backend clear result is typed");
19 assert.match(types, /sessionGeneration/, "sessionGeneration is part of identity");
20 assert.match(controller, /ClearSessionForTab/, "clear uses tab-scoped clear API");
21 assert.match(controller, /evictTab\(tabId\)/, "clear evicts TranscriptStore for the tab");
22 assert.match(controller, /sessionGeneration:\s*cleared\.sessionGeneration/, "clear applies returned generation");
23 assert.match(controller, /sessionPath:\s*cleared\.sessionPath/, "clear applies returned path");
24 assert.match(controller, /optimistic_meta[\s\S]*reset/, "meta is updated before reset so identity survives");
25 assert.match(controller, /hydrateIdentityCurrent\(/, "hydrate rejects path/generation identity drift");
26 assert.match(store, /evictTab\(tabId/, "TranscriptStore can drop a tab's resident sessions");
27
28 console.log(" PASS clear-session identity contract");
29
29 lines TYPESCRIPT