const ADDRESS = "0x66133E8ea0f5D1d612D2502a968757D1048c214a"; function oneWallet() { return [{ name: "Wallet 1", type: "hd", addresses: [ADDRESS] }]; } // state.js resolves the storage API at require time, so the stub has to exist // before the module is loaded, and the module registry has to be reset between // cases because `state` is a module-level singleton. function loadModuleWith(persisted) { jest.resetModules(); const set = jest.fn(async () => {}); global.chrome = { storage: { local: { get: jest.fn(async () => persisted ? { autistmask: persisted } : {}, ), set, }, }, }; return { mod: require("../src/shared/state"), set }; } afterEach(() => { delete global.chrome; }); describe("loadState hasWallet reconciliation", () => { // A profile that deleted its last wallet on a build predating the write // path fix keeps hasWallet: true forever. It must load as no wallet, which // is what sends the popup to the welcome view. test("stored hasWallet true with zero wallets loads as no wallet", async () => { const { mod } = loadModuleWith({ hasWallet: true, wallets: [] }); await mod.loadState(); expect(mod.state.hasWallet).toBe(false); }); test("stored hasWallet true with a missing wallets key loads as no wallet", async () => { const { mod } = loadModuleWith({ hasWallet: true }); await mod.loadState(); expect(mod.state.wallets).toEqual([]); expect(mod.state.hasWallet).toBe(false); }); test("stored hasWallet false with one wallet loads as having a wallet", async () => { const { mod } = loadModuleWith({ hasWallet: false, wallets: oneWallet(), }); await mod.loadState(); expect(mod.state.hasWallet).toBe(true); }); test("absent hasWallet with wallets present loads as having a wallet", async () => { const { mod } = loadModuleWith({ wallets: oneWallet() }); await mod.loadState(); expect(mod.state.hasWallet).toBe(true); }); test("consistent stored states are preserved", async () => { const withWallet = loadModuleWith({ hasWallet: true, wallets: oneWallet(), }); await withWallet.mod.loadState(); expect(withWallet.mod.state.hasWallet).toBe(true); const without = loadModuleWith({ hasWallet: false, wallets: [] }); await without.mod.loadState(); expect(without.mod.state.hasWallet).toBe(false); }); test("empty storage leaves the default no-wallet state", async () => { const { mod } = loadModuleWith(null); await mod.loadState(); expect(mod.state.hasWallet).toBe(false); expect(mod.state.wallets).toEqual([]); }); // The correction is derived on every load rather than written back, so a // load never has a storage side effect. test("loadState does not write to storage", async () => { const { mod, set } = loadModuleWith({ hasWallet: true, wallets: [] }); await mod.loadState(); expect(set).not.toHaveBeenCalled(); }); // Deriving must not disturb the rest of the load. test("other persisted fields still load", async () => { const { mod } = loadModuleWith({ hasWallet: false, wallets: oneWallet(), networkId: "sepolia", theme: "dark", activeAddress: ADDRESS, }); await mod.loadState(); expect(mod.state.networkId).toBe("sepolia"); expect(mod.state.theme).toBe("dark"); expect(mod.state.activeAddress).toBe(ADDRESS); }); }); // The known-symbol spoof filter is a safety filter, so an existing profile // stored before the setting existed must load with it on rather than with // undefined, which would read as off. describe("hideSpoofedSymbols persistence", () => { test("defaults to on with empty storage", async () => { const { mod } = loadModuleWith(null); await mod.loadState(); expect(mod.state.hideSpoofedSymbols).toBe(true); }); test("a profile stored without the key loads with it on", async () => { const { mod } = loadModuleWith({ wallets: oneWallet() }); await mod.loadState(); expect(mod.state.hideSpoofedSymbols).toBe(true); }); test("an explicit false survives the load", async () => { const { mod } = loadModuleWith({ wallets: oneWallet(), hideSpoofedSymbols: false, }); await mod.loadState(); expect(mod.state.hideSpoofedSymbols).toBe(false); }); test("saveState persists the flag", async () => { const { mod, set } = loadModuleWith(null); mod.state.hideSpoofedSymbols = false; await mod.saveState(); expect(set).toHaveBeenCalledWith({ autistmask: expect.objectContaining({ hideSpoofedSymbols: false }), }); }); test("the flag round-trips off through save and load", async () => { const first = loadModuleWith(null); first.mod.state.hideSpoofedSymbols = false; await first.mod.saveState(); const persisted = first.set.mock.calls[0][0].autistmask; const second = loadModuleWith(persisted); await second.mod.loadState(); expect(second.mod.state.hideSpoofedSymbols).toBe(false); }); test("the flag round-trips back on through save and load", async () => { const first = loadModuleWith(null); first.mod.state.hideSpoofedSymbols = true; await first.mod.saveState(); const persisted = first.set.mock.calls[0][0].autistmask; const second = loadModuleWith(persisted); await second.mod.loadState(); expect(second.mod.state.hideSpoofedSymbols).toBe(true); }); });