ec66f22212b6

test: add atomic-persist regression — a slot-B write failure must restore slot A so no phantom entry is left on disk (covers v3.6.137)

time
2026-05-30 07:32 UTC · 5 months ago
machine
koh2
parent
ebb7bd2456e6
1 file src/background/vault-history.test.ts+28 −0
src/background/vault-history.test.ts+28 −0
@@ -98,6 +98,34 @@9898     expect(readHistory().snapshots).toHaveLength(5);9999   });100100 101+  it("atomic persist: a slot-B write failure restores slot A — no phantom entry (v3.6.137)", async () => {102+    const vault = await import("./vault");103+    await vault.createVault("atomic-pass-12345");104+    await vault.addEntry({ title: "A", username: "", password: "p1", url: "" });105+106+    // Slot A as committed by the first, fully-successful save.107+    const slotABefore = JSON.stringify(storage.peach_vault_a);108+    expect(slotABefore).toBeTruthy();109+110+    // Fail ONLY the slot-B write — this mimics the mid-persist storage error111+    // (quota overflow) that left a committed slot A behind and produced112+    // duplicate entries before v3.6.137. beforeEach rebuilds chrome per test,113+    // so this override does not leak.114+    (chrome.storage.local as unknown as { set: (n: Record<string, unknown>) => Promise<void> }).set =115+      async (next) => {116+        if ("peach_vault_b" in next) throw new Error("QUOTA_BYTES quota exceeded");117+        Object.assign(storage, next);118+      };119+120+    await expect(121+      vault.addEntry({ title: "B", username: "", password: "p2", url: "" }),122+    ).rejects.toThrow();123+124+    // Slot A on disk must be byte-identical to before: the failed entry B was125+    // rolled back on disk too, so it can never resurface as a phantom/duplicate.126+    expect(JSON.stringify(storage.peach_vault_a)).toBe(slotABefore);127+  });128+101129   it("entryCount reflects current in-memory active count at snapshot time", async () => {102130     const vault = await import("./vault");103131     await vault.createVault("count-pass-12345");

view file