import * as Schema from "effect/Schema"; import { afterEach, describe, expect, it, vi } from "vite-plus/test"; function createStorage(overrides: Partial = {}): Storage { const store = new Map(); return { clear: () => store.clear(), getItem: (key) => store.get(key) ?? null, key: (index) => [...store.keys()][index] ?? null, get length() { return store.size; }, removeItem: (key) => { store.delete(key); }, setItem: (key, value) => { store.set(key, value); }, ...overrides, }; } async function loadWithStorage(storage: Storage) { vi.stubGlobal("window", { localStorage: storage }); vi.stubGlobal("localStorage", storage); return import("./useLocalStorage"); } afterEach(() => { vi.resetModules(); vi.unstubAllGlobals(); }); describe("local storage errors", () => { it("preserves read failure context", async () => { const cause = new Error("storage unavailable"); const { getLocalStorageItem, LocalStorageOperationError } = await loadWithStorage( createStorage({ getItem: () => { throw cause; }, }), ); try { getLocalStorageItem("read-key", Schema.String); expect.unreachable("expected the read to fail"); } catch (error) { expect(error).toBeInstanceOf(LocalStorageOperationError); expect(error).toMatchObject({ operation: "read", storageKey: "read-key", cause, }); } }); it("preserves decode failure context", async () => { const { getLocalStorageItem, LocalStorageOperationError } = await loadWithStorage( createStorage({ getItem: () => "not-json" }), ); try { getLocalStorageItem("decode-key", Schema.String); expect.unreachable("expected decoding to fail"); } catch (error) { expect(error).toBeInstanceOf(LocalStorageOperationError); expect(error).toMatchObject({ operation: "decode", storageKey: "decode-key", cause: expect.anything(), }); } }); it("preserves write failure context", async () => { const cause = new Error("storage quota exceeded"); const { LocalStorageOperationError, setLocalStorageItem } = await loadWithStorage( createStorage({ setItem: () => { throw cause; }, }), ); try { setLocalStorageItem("write-key", "value", Schema.String); expect.unreachable("expected the write to fail"); } catch (error) { expect(error).toBeInstanceOf(LocalStorageOperationError); expect(error).toMatchObject({ operation: "write", storageKey: "write-key", cause, }); } }); it("preserves removal failure context", async () => { const cause = new Error("storage unavailable"); const { LocalStorageOperationError, removeLocalStorageItem } = await loadWithStorage( createStorage({ removeItem: () => { throw cause; }, }), ); try { removeLocalStorageItem("remove-key"); expect.unreachable("expected the removal to fail"); } catch (error) { expect(error).toBeInstanceOf(LocalStorageOperationError); expect(error).toMatchObject({ operation: "remove", storageKey: "remove-key", cause, }); } }); });