import { afterEach, expect, it, vi } from "vitest"; import { 候选浏览器缓冲, 候选缓冲键, 旧候选缓冲键, type 候选范围, type 改稿缓冲, } from "../../src/功能/正文写作/候选缓冲"; const scope: 候选范围 = { author_id: "author", work_id: "work", chapter_id: "chapter", branch_id: "A", candidate_id: "new", }; const draft: 改稿缓冲 = { document: { format_version: 1, paragraphs: [ { paragraph_id: "p", content: [{ type: "text", text: "A稿", marks: [] }], }, ], }, base_revision: 7, base_hash: "hash", mode: "edit", selected: [], }; afterEach(() => { sessionStorage.clear(); vi.restoreAllMocks(); }); // @muse-case {"case_id": "O01-candidate-branch-scope", "environment": "离线前端单元", "when": "同版本的两分支草稿互不读取或覆盖,分隔符无歧义", "contract": "docs/系统架构/新版设计/工作台设计.md"} it("O01-candidate-branch-scope:同版本的两分支草稿互不读取或覆盖,分隔符无歧义", () => { const a = 候选浏览器缓冲(scope), bScope = { ...scope, branch_id: "B" }, b = 候选浏览器缓冲(bScope); a.read(); b.read(); a.write(draft); expect(b.read()).toBeUndefined(); b.write({ ...draft, base_hash: "B" }); expect(a.read()).toEqual(draft); expect(候选缓冲键({ ...scope, author_id: "a:b", work_id: "c" })).not.toEqual( 候选缓冲键({ ...scope, author_id: "a", work_id: "b:c" }), ); }); // @muse-case {"case_id": "O01-candidate-original-pending", "environment": "离线前端单元", "when": "刷新保持原请求,跨分支pending拒绝且字节不变", "contract": "docs/系统架构/新版设计/工作台设计.md"} it("O01-candidate-original-pending:刷新保持原请求,跨分支pending拒绝且字节不变", () => { const pending = { kind: "create" as const, body: { command_id: "original", chapter_id: "chapter", branch_id: "A", expected_revision: 7, document: draft.document, }, }; const a = 候选浏览器缓冲(scope); a.read(); a.write({ ...draft, pending }); expect(候选浏览器缓冲(scope).read()?.pending).toEqual(pending); const other = { ...scope, branch_id: "B" }, key = 候选缓冲键(other); const raw = JSON.stringify({ schema_version: 2, scope: other, draft: { ...draft, pending }, }); sessionStorage.setItem(key, raw); expect(() => 候选浏览器缓冲(other).read()).toThrow("分支 A"); expect(sessionStorage.getItem(key)).toBe(raw); }); // @muse-case {"case_id": "O01-candidate-owner-quota", "environment": "离线前端单元", "when": "迟到clear不删新owner,配额失败保留旧字节", "contract": "docs/系统架构/新版设计/工作台设计.md"} it("O01-candidate-owner-quota:迟到clear不删新owner,配额失败保留旧字节", () => { const a = 候选浏览器缓冲(scope); a.read(); a.write(draft); const b = 候选浏览器缓冲(scope); b.read(); b.write({ ...draft, base_hash: "new" }); const raw = sessionStorage.getItem(候选缓冲键(scope)); expect(() => a.write(draft)).toThrow("其他会话"); a.clear(); expect(sessionStorage.getItem(候选缓冲键(scope))).toBe(raw); vi.spyOn(Storage.prototype, "setItem").mockImplementation(() => { throw new Error("quota"); }); expect(() => b.write(draft)).toThrow("quota"); expect(sessionStorage.getItem(候选缓冲键(scope))).toBe(raw); }); // @muse-case {"case_id": "O01-candidate-legacy-corrupt", "environment": "离线前端单元", "when": "旧键只读保留且损坏新记录不允许覆盖", "contract": "docs/系统架构/新版设计/工作台设计.md"} it("O01-candidate-legacy-corrupt:旧键只读保留且损坏新记录不允许覆盖", () => { const key = 旧候选缓冲键(scope), raw = JSON.stringify(draft); sessionStorage.setItem(key, raw); const a = 候选浏览器缓冲(scope); expect(a.legacy()?.value).toEqual(draft); a.read(); a.write(draft); a.clear(); expect(sessionStorage.getItem(key)).toBe(raw); sessionStorage.setItem(候选缓冲键(scope), "{broken"); expect(() => a.read()).toThrow(); expect(() => a.write(draft)).toThrow("不能覆盖"); expect(sessionStorage.getItem(候选缓冲键(scope))).toBe("{broken"); });