123import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";45import { flushView, renderView } from "./view-test-utils";67const sendMessageMock = vi.fn<(msg: unknown) => Promise<unknown>>();89vi.mock("../../shared/bridge", () => ({10 sendMessage: (msg: unknown) => sendMessageMock(msg),11}));1213vi.mock("../components/RecoveryRuneBackground", () => ({14 RecoveryRuneBackground: () => null,15}));1617vi.mock("../codex/generate", () => {18 throw new Error("blocked heavy Codex module");19});2021vi.mock("../codex/rs-loader", () => ({22 getReedSolomon: vi.fn(async () => ({})),23}));2425describe("CodexGenerateView", () => {26 let dispose: (() => void) | undefined;2728 beforeEach(() => {29 document.body.innerHTML = "";30 sendMessageMock.mockReset();31 sendMessageMock.mockResolvedValue({32 ok: true,33 data: {34 slotA: JSON.stringify({ slot: "a" }),35 slotB: null,36 lastModified: null,37 entryCount: 3,38 recoveryWords: [39 "abandon", "ability", "able", "about", "above", "absent",40 "absorb", "abstract", "absurd", "abuse", "access", "accident",41 ],42 verifyCode: "PX-TEST-CODE",43 vaultUnlocked: true,44 },45 });4647 vi.stubGlobal("chrome", {48 storage: {49 local: {50 set: vi.fn(),51 },52 },53 } as unknown as typeof chrome);54 });5556 afterEach(() => {57 dispose?.();58 dispose = undefined;59 vi.unstubAllGlobals();60 });6162 it("shows the recovery-word gate even if the heavy Codex module fails to load", async () => {63 const { CodexGenerateView } = await import("./CodexGenerateView");64 const mounted = renderView(65 <CodexGenerateView66 isPro={true}67 onBack={vi.fn()}68 onUpgradePro={vi.fn()}69 onOpenSecurity={vi.fn()}70 onVaultLocked={vi.fn()}71 />,72 );73 dispose = mounted.dispose;7475 await flushView();76 await flushView();7778 expect(mounted.container.textContent).toContain("your recovery words.");79 expect(mounted.container.textContent).toContain("abandon");80 expect(mounted.container.textContent).toContain("Failed to load Codex library");81 });8283 it("PB-26-607: never renders a raw background error string", async () => {84 const RAW = "Error: ENOENT /vaults/slot-b.json at readSlot (vault.ts:884)";85 sendMessageMock.mockResolvedValue({ ok: false, error: RAW });8687 const { CodexGenerateView } = await import("./CodexGenerateView");88 const mounted = renderView(89 <CodexGenerateView90 isPro={true}91 onBack={vi.fn()}92 onUpgradePro={vi.fn()}93 onOpenSecurity={vi.fn()}94 onVaultLocked={vi.fn()}95 />,96 );97 dispose = mounted.dispose;9899 await flushView();100 await flushView();101102 expect(mounted.container.textContent).toContain("could not load vault data");103 expect(mounted.container.textContent).not.toContain(RAW);104 expect(mounted.container.textContent).not.toContain("vault.ts");105 });106});