import { test } from 'node:test'; import assert from 'node:assert/strict'; import { createStore } from 'jotai'; import { enableMapSet } from 'immer'; // `spaceRoomsAtom` is backed by `atomWithLocalStorage`, which reads // `localStorage` AT MODULE LOAD to seed the atom (absent in node). We install an // in-memory mock first. The reducers also `produce` over an immer-managed Set, // so immer's Map/Set plugin must be enabled (the app does this at startup). const SPACE_ROOMS = 'spaceRooms'; const installStorage = (seed?: string[]): Map => { const map = new Map(); if (seed) map.set(SPACE_ROOMS, JSON.stringify(seed)); (globalThis as { localStorage?: unknown }).localStorage = { getItem: (k: string) => (map.has(k) ? map.get(k)! : null), setItem: (k: string, v: string) => { map.set(k, v); }, removeItem: (k: string) => { map.delete(k); }, }; return map; }; enableMapSet(); installStorage(); const { spaceRoomsAtom } = await import('./spaceRooms'); // `atomWithLocalStorage` seeds the atom from storage exactly once, when the // module is evaluated. To exercise hydration we install seeded storage and then // import a *fresh* copy of the module (cache-busted) so the seed is read. let freshCounter = 0; const importWithStorage = async ( seed?: string[], ): Promise => { installStorage(seed); freshCounter += 1; const mod = await import(`./spaceRooms?fresh=${freshCounter}`); return mod.spaceRoomsAtom; }; const sorted = (s: Set): string[] => [...s].sort(); test('starts empty when nothing is stored', () => { installStorage(); const store = createStore(); assert.equal(store.get(spaceRoomsAtom).size, 0); }); test('PUT adds new room ids to the Set', () => { installStorage(); const store = createStore(); store.set(spaceRoomsAtom, { type: 'PUT', roomIds: ['!a:s', '!b:s'] }); assert.deepEqual(sorted(store.get(spaceRoomsAtom)), ['!a:s', '!b:s']); }); test('PUT dedupes against existing entries', () => { installStorage(); const store = createStore(); store.set(spaceRoomsAtom, { type: 'PUT', roomIds: ['!a:s'] }); store.set(spaceRoomsAtom, { type: 'PUT', roomIds: ['!a:s', '!b:s'] }); assert.deepEqual(sorted(store.get(spaceRoomsAtom)), ['!a:s', '!b:s']); }); test('PUT with only already-present ids does not write (Set identity unchanged)', () => { installStorage(); const store = createStore(); store.set(spaceRoomsAtom, { type: 'PUT', roomIds: ['!a:s'] }); const before = store.get(spaceRoomsAtom); store.set(spaceRoomsAtom, { type: 'PUT', roomIds: ['!a:s'] }); const after = store.get(spaceRoomsAtom); // No new entries -> the reducer skips set(), so the Set reference is the same. assert.equal(before, after); }); test('DELETE removes present members', () => { installStorage(); const store = createStore(); store.set(spaceRoomsAtom, { type: 'PUT', roomIds: ['!a:s', '!b:s'] }); store.set(spaceRoomsAtom, { type: 'DELETE', roomIds: ['!a:s'] }); assert.deepEqual(sorted(store.get(spaceRoomsAtom)), ['!b:s']); }); test('DELETE of an absent member does not write (Set identity unchanged)', () => { installStorage(); const store = createStore(); store.set(spaceRoomsAtom, { type: 'PUT', roomIds: ['!a:s'] }); const before = store.get(spaceRoomsAtom); store.set(spaceRoomsAtom, { type: 'DELETE', roomIds: ['!nope:s'] }); const after = store.get(spaceRoomsAtom); assert.equal(before, after); assert.deepEqual(sorted(after), ['!a:s']); }); test('DELETE acts when at least one of the ids is present', () => { installStorage(); const store = createStore(); store.set(spaceRoomsAtom, { type: 'PUT', roomIds: ['!a:s', '!b:s'] }); store.set(spaceRoomsAtom, { type: 'DELETE', roomIds: ['!a:s', '!nope:s'] }); assert.deepEqual(sorted(store.get(spaceRoomsAtom)), ['!b:s']); }); test('hydrates the Set from a stored array', async () => { const freshAtom = await importWithStorage(['!x:s', '!y:s']); const store = createStore(); assert.deepEqual(sorted(store.get(freshAtom)), ['!x:s', '!y:s']); }); test('persists the Set to localStorage as an array', () => { const backing = installStorage(); const store = createStore(); store.set(spaceRoomsAtom, { type: 'PUT', roomIds: ['!a:s', '!b:s'] }); const raw = backing.get(SPACE_ROOMS); assert.ok(raw); const arr = JSON.parse(raw!) as string[]; assert.deepEqual([...arr].sort(), ['!a:s', '!b:s']); });