First frontend unit test framework on Lumotia. Pinned exact versions for
supply-chain hygiene (matches the rust-toolchain.toml discipline from the
27661c8 hygiene pass and the npm audit signatures pre-flight from e4d56b8):
- vitest 4.1.6 (compatible with vite 6, supports vite 6/7/8)
- jsdom 29.1.1
Installed with `npm install --save-dev --save-exact --ignore-scripts` per
the install discipline documented in the README — the --ignore-scripts
flag blocks the postinstall vector that npm worms (Shai-Hulud,
mini-Shai-Hulud) rely on.
vite.config.js:
- Switched defineConfig import to vitest/config (superset of vite/config;
production builds ignore the `test` key).
- test.environment = "jsdom" so storage-shim tests drive real browser APIs.
- test.include scoped to src/**/*.{test,spec}.{ts,js} — colocated with
source, mirrors the Rust #[cfg(test)] sibling pattern.
- test.exclude blocks src-tauri/ (owned by cargo test).
- restoreMocks + clearMocks + unstubAllGlobals on so module-level state
can't leak between tests.
src/lib/utils/localStorageMigration.test.ts — 12 tests:
migrateLocalStorageKey:
- copies value + removes old when only old exists
- removes old + keeps new when both exist (lumotia is authoritative)
- no-op when only new exists
- no-op when neither exists
- idempotent (second call after first migrates nothing)
- preserves the value's exact bytes (no JSON round-trip)
- preserves empty-string values (distinct from null)
- survives DOMException / quota errors without re-raising
- no-op when localStorage is undefined (SSR-safe)
migrateLocalStorageKeys:
- processes pairs in order
- per-pair failure does not strand remaining pairs (resilience)
- empty pairs list is a clean no-op
package.json:
- "test": "vitest run" (one-shot, CI-friendly)
- "test:watch": "vitest" (dev loop)
README: documents `npm run test` alongside `cargo test --workspace` and
`npm run check` in the Testing section.
Verification:
- npm run test: 12/12 pass
- npm run check: 0 errors, 0 warnings (the new .ts test type-checks clean
against jsconfig.json's strict typescript settings)