import { test } from 'node:test'; import assert from 'node:assert/strict'; import { createStore } from 'jotai'; import { enableMapSet } from 'immer'; import { makeClosedLobbyCategoriesAtom, makeLobbyCategoryId } from './closedLobbyCategories'; // makeClosedLobbyCategoriesAtom(userId) builds a Set atom whose reducer uses // immer produce (PUT add / DELETE delete) and persists to a per-user localStorage // key `closedLobbyCategories`. The reducers produce over a Set, so enable // immer's Map/Set plugin (the app does this once at startup). // makeLobbyCategoryId joins args with '|'. (Mirrors closedNavCategories.test.ts.) enableMapSet(); type Store = Record; const installLocalStorage = (): Store => { const data: Store = {}; const ls = { getItem: (k: string) => (k in data ? data[k] : null), setItem: (k: string, v: string) => { data[k] = String(v); }, removeItem: (k: string) => { delete data[k]; }, }; (globalThis as { localStorage?: unknown }).localStorage = ls; (globalThis as { window?: unknown }).window = { addEventListener: () => undefined, removeEventListener: () => undefined, }; return data; }; test('makeLobbyCategoryId joins args with "|"', () => { assert.equal(makeLobbyCategoryId('space', 'catA'), 'space|catA'); assert.equal(makeLobbyCategoryId('only'), 'only'); assert.equal(makeLobbyCategoryId(), ''); }); test('starts empty when nothing is stored', () => { installLocalStorage(); const store = createStore(); const lobbyAtom = makeClosedLobbyCategoriesAtom('@u:server'); assert.equal(store.get(lobbyAtom).size, 0); }); test('hydrates the Set from the per-user localStorage key', () => { const data = installLocalStorage(); data['closedLobbyCategories@u:server'] = JSON.stringify(['x', 'y']); const store = createStore(); const lobbyAtom = makeClosedLobbyCategoriesAtom('@u:server'); assert.deepEqual(Array.from(store.get(lobbyAtom)).sort(), ['x', 'y']); }); test('PUT adds a category and DELETE removes it', () => { installLocalStorage(); const store = createStore(); const lobbyAtom = makeClosedLobbyCategoriesAtom('@u:server'); store.set(lobbyAtom, { type: 'PUT', categoryId: 'cat1' }); assert.deepEqual(Array.from(store.get(lobbyAtom)), ['cat1']); store.set(lobbyAtom, { type: 'DELETE', categoryId: 'cat1' }); assert.equal(store.get(lobbyAtom).has('cat1'), false); }); test('PUT of an existing category is idempotent', () => { installLocalStorage(); const store = createStore(); const lobbyAtom = makeClosedLobbyCategoriesAtom('@u:server'); store.set(lobbyAtom, { type: 'PUT', categoryId: 'cat1' }); store.set(lobbyAtom, { type: 'PUT', categoryId: 'cat1' }); assert.equal(store.get(lobbyAtom).size, 1); }); test('DELETE of an absent category is a no-op', () => { installLocalStorage(); const store = createStore(); const lobbyAtom = makeClosedLobbyCategoriesAtom('@u:server'); store.set(lobbyAtom, { type: 'DELETE', categoryId: 'missing' }); assert.equal(store.get(lobbyAtom).size, 0); }); test('writes persist to localStorage as an array', () => { const data = installLocalStorage(); const store = createStore(); const lobbyAtom = makeClosedLobbyCategoriesAtom('@u:server'); store.set(lobbyAtom, { type: 'PUT', categoryId: 'cat1' }); assert.deepEqual(JSON.parse(data['closedLobbyCategories@u:server']), ['cat1']); }); test('the storage key is namespaced per user', () => { const data = installLocalStorage(); const store = createStore(); const aAtom = makeClosedLobbyCategoriesAtom('@a:server'); const bAtom = makeClosedLobbyCategoriesAtom('@b:server'); store.set(aAtom, { type: 'PUT', categoryId: 'only-a' }); assert.deepEqual(JSON.parse(data['closedLobbyCategories@a:server']), ['only-a']); assert.equal(data['closedLobbyCategories@b:server'], undefined); assert.equal(store.get(bAtom).size, 0); });