Skip to content

Commit ede7f79

Browse files
committed
test(v7-h02): localStorage shim + hydration test un-skip
vbgui/tests/setup.ts: full Storage shim when jsdom omits localStorage or supplies a non-Storage stub, exposed on both globalThis and window. vbgui/tests/useProjects.test.tsx: the hydration test is no longer skipped — with the shim it observes the persisted entry across renderHook calls (waitFor on vbgui_projects_v1 before unmount). vbgui/vite.config.ts: set jsdom URL so localStorage origin is stable across test files (Storage is keyed by origin in jsdom).
1 parent 6668ed6 commit ede7f79

3 files changed

Lines changed: 51 additions & 2 deletions

File tree

vbgui/tests/setup.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,45 @@ if (!("DOMMatrixReadOnly" in globalThis)) {
1818
(globalThis as unknown as { DOMMatrixReadOnly: unknown }).DOMMatrixReadOnly =
1919
DOMMatrixReadOnlyShim;
2020
}
21+
22+
function hasUsableStorage(storage: Storage | undefined): storage is Storage {
23+
return storage != null &&
24+
typeof storage.getItem === "function" &&
25+
typeof storage.setItem === "function" &&
26+
typeof storage.removeItem === "function" &&
27+
typeof storage.clear === "function";
28+
}
29+
30+
if (!hasUsableStorage(globalThis.localStorage)) {
31+
const values = new Map<string, string>();
32+
const storage: Storage = {
33+
get length() {
34+
return values.size;
35+
},
36+
clear() {
37+
values.clear();
38+
},
39+
getItem(key: string) {
40+
return values.get(key) ?? null;
41+
},
42+
key(index: number) {
43+
return Array.from(values.keys())[index] ?? null;
44+
},
45+
removeItem(key: string) {
46+
values.delete(key);
47+
},
48+
setItem(key: string, value: string) {
49+
values.set(key, value);
50+
},
51+
};
52+
Object.defineProperty(globalThis, "localStorage", {
53+
configurable: true,
54+
value: storage,
55+
});
56+
if (typeof window !== "undefined") {
57+
Object.defineProperty(window, "localStorage", {
58+
configurable: true,
59+
value: storage,
60+
});
61+
}
62+
}

vbgui/tests/useProjects.test.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, it, expect, beforeEach } from "vitest";
2-
import { renderHook, act } from "@testing-library/react";
2+
import { renderHook, act, waitFor } from "@testing-library/react";
33
import { useProjects } from "@/hooks/useProjects";
44

55
describe("V7-H02 useProjects", () => {
@@ -76,10 +76,14 @@ describe("V7-H02 useProjects", () => {
7676
expect(aa?.payload).toEqual({ v: 1 });
7777
});
7878

79-
it.skip("hydrates from localStorage on next mount (jsdom stub does not persist across renderHook)", () => {
79+
it("hydrates from localStorage on next mount", async () => {
8080
const { result, unmount } = renderHook(
8181
() => useProjects<{ v: number }>());
8282
act(() => { result.current.create("alpha", { v: 1 }); });
83+
await waitFor(() => {
84+
expect(window.localStorage.getItem("vbgui_projects_v1"))
85+
.not.toBeNull();
86+
});
8387
unmount();
8488
// Fresh mount — should see the persisted project.
8589
const { result: r2 } = renderHook(

vbgui/vite.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ export default defineConfig({
1010
server: { port: 5173, strictPort: false },
1111
test: {
1212
environment: "jsdom",
13+
environmentOptions: {
14+
jsdom: { url: "http://localhost/" },
15+
},
1316
globals: true,
1417
setupFiles: ["tests/setup.ts"],
1518
css: false,

0 commit comments

Comments
 (0)