Files
cinny/src/app/state/navToActivePath.test.ts
T
nathan 17322cc955
CI / Build & Quality Checks (pull_request) Canceled after 5m40s
CI / Trigger Desktop Build (pull_request) Canceled after 0s
removed deprecated react-router-dom, as all falls within react-router now
2026-08-02 19:33:13 -04:00

124 lines
4.3 KiB
TypeScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { createStore } from 'jotai';
import { enableMapSet } from 'immer';
import type { Path } from 'react-router';
// `makeNavToActivePathAtom(userId)` is a factory: localStorage is read when the
// returned atom is first created/accessed (not at module load), but we still
// install the mock up front. The reducers `produce` over an immer-managed Map,
// so immer's Map/Set plugin must be enabled.
const NAV_TO_ACTIVE_PATH = 'navToActivePath';
const storeKeyFor = (userId: string): string => `${NAV_TO_ACTIVE_PATH}${userId}`;
const installStorage = (): Map<string, string> => {
const map = new Map<string, string>();
(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();
// eslint-disable-next-line import/first
import { makeNavToActivePathAtom } from './navToActivePath';
const USER = '@user:server';
const path = (pathname: string): Path => ({ pathname, search: '', hash: '' });
test('starts as an empty Map', () => {
installStorage();
const navAtom = makeNavToActivePathAtom(USER);
const store = createStore();
const map = store.get(navAtom);
assert.ok(map instanceof Map);
assert.equal(map.size, 0);
});
test('PUT stores a path under its navId', () => {
installStorage();
const navAtom = makeNavToActivePathAtom(USER);
const store = createStore();
store.set(navAtom, { type: 'PUT', navId: 'home', path: path('/home') });
assert.deepEqual(store.get(navAtom).get('home'), path('/home'));
});
test('PUT overwrites the path for an existing navId', () => {
installStorage();
const navAtom = makeNavToActivePathAtom(USER);
const store = createStore();
store.set(navAtom, { type: 'PUT', navId: 'home', path: path('/old') });
store.set(navAtom, { type: 'PUT', navId: 'home', path: path('/new') });
const map = store.get(navAtom);
assert.equal(map.size, 1);
assert.deepEqual(map.get('home'), path('/new'));
});
test('DELETE removes a navId', () => {
installStorage();
const navAtom = makeNavToActivePathAtom(USER);
const store = createStore();
store.set(navAtom, { type: 'PUT', navId: 'home', path: path('/home') });
store.set(navAtom, { type: 'PUT', navId: 'dms', path: path('/dms') });
store.set(navAtom, { type: 'DELETE', navId: 'home' });
const map = store.get(navAtom);
assert.equal(map.has('home'), false);
assert.deepEqual(map.get('dms'), path('/dms'));
});
test('DELETE of an absent navId is a no-op', () => {
installStorage();
const navAtom = makeNavToActivePathAtom(USER);
const store = createStore();
store.set(navAtom, { type: 'PUT', navId: 'home', path: path('/home') });
store.set(navAtom, { type: 'DELETE', navId: 'ghost' });
assert.deepEqual([...store.get(navAtom).keys()], ['home']);
});
test('persists to localStorage as an Object keyed per user', () => {
const backing = installStorage();
const navAtom = makeNavToActivePathAtom(USER);
const store = createStore();
store.set(navAtom, { type: 'PUT', navId: 'home', path: path('/home') });
const raw = backing.get(storeKeyFor(USER));
assert.ok(raw);
const obj = JSON.parse(raw!) as Record<string, Path>;
assert.deepEqual(obj, { home: path('/home') });
});
test('hydrates the Map from a stored Object', () => {
const backing = installStorage();
backing.set(storeKeyFor(USER), JSON.stringify({ home: path('/home') }));
const navAtom = makeNavToActivePathAtom(USER);
const store = createStore();
assert.deepEqual(store.get(navAtom).get('home'), path('/home'));
});
test('storage is scoped per userId', () => {
const backing = installStorage();
const userA = '@a:s';
const userB = '@b:s';
const atomA = makeNavToActivePathAtom(userA);
const atomB = makeNavToActivePathAtom(userB);
const store = createStore();
store.set(atomA, { type: 'PUT', navId: 'home', path: path('/a-home') });
store.set(atomB, { type: 'PUT', navId: 'home', path: path('/b-home') });
assert.ok(backing.has(storeKeyFor(userA)));
assert.ok(backing.has(storeKeyFor(userB)));
assert.deepEqual(store.get(atomA).get('home'), path('/a-home'));
assert.deepEqual(store.get(atomB).get('home'), path('/b-home'));
});