diff --git a/mateclaw-ui/src/test/setup.ts b/mateclaw-ui/src/test/setup.ts new file mode 100644 index 00000000..8338702a --- /dev/null +++ b/mateclaw-ui/src/test/setup.ts @@ -0,0 +1,12 @@ +import { Storage } from 'happy-dom' + +// Node 25 exposes its own localStorage even without a backing file. Vitest +// preserves existing Node globals, so it can shadow happy-dom's browser API. +// Give each test file browser storage independent of the host Node version. +for (const name of ['localStorage', 'sessionStorage'] as const) { + Object.defineProperty(globalThis, name, { + configurable: true, + writable: true, + value: new Storage(), + }) +} diff --git a/mateclaw-ui/src/utils/__tests__/browserStorage.test.ts b/mateclaw-ui/src/utils/__tests__/browserStorage.test.ts new file mode 100644 index 00000000..f1f485b5 --- /dev/null +++ b/mateclaw-ui/src/utils/__tests__/browserStorage.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, it } from 'vitest' + +describe('browser storage in the DOM test environment', () => { + it.each(['localStorage', 'sessionStorage'] as const)('%s provides the browser Storage API', name => { + const storage = globalThis[name] + expect(typeof storage.getItem, `${process.version}: ${name}.getItem`).toBe('function') + expect(typeof storage.clear, `${process.version}: ${name}.clear`).toBe('function') + storage.clear() + storage.setItem('token', 'test-token') + expect(storage.getItem('token')).toBe('test-token') + expect(storage.length).toBe(1) + expect(storage.key(0)).toBe('token') + storage.removeItem('token') + expect(storage.getItem('token')).toBeNull() + expect(storage.length).toBe(0) + }) +}) diff --git a/mateclaw-ui/vitest.config.ts b/mateclaw-ui/vitest.config.ts index a8da42b5..dac61b89 100644 --- a/mateclaw-ui/vitest.config.ts +++ b/mateclaw-ui/vitest.config.ts @@ -14,6 +14,7 @@ export default defineConfig({ test: { include: ['src/**/*.{test,spec}.{ts,tsx}'], environment: 'happy-dom', + setupFiles: ['./src/test/setup.ts'], }, resolve: { alias: {