import { test } from 'node:test'; import assert from 'node:assert/strict'; import { createStore } from 'jotai'; import { createListAtom } from './list'; // `createListAtom` produces a write atom whose reducer handles PUT (append a // single item or an array of items), DELETE (identity-based removal of a single // item or array of items) and REPLACE (identity match -> replacement). We drive // the pure reducer through a real jotai store. The exported `TListAtom` type is // a type alias only, nothing to test at runtime. test('starts as an empty array', () => { const store = createStore(); const listAtom = createListAtom(); assert.deepEqual(store.get(listAtom), []); }); test('PUT appends a single item', () => { const store = createStore(); const listAtom = createListAtom(); store.set(listAtom, { type: 'PUT', item: 'a' }); store.set(listAtom, { type: 'PUT', item: 'b' }); assert.deepEqual(store.get(listAtom), ['a', 'b']); }); test('PUT appends an array of items in order', () => { const store = createStore(); const listAtom = createListAtom(); store.set(listAtom, { type: 'PUT', item: 'a' }); store.set(listAtom, { type: 'PUT', item: ['b', 'c'] }); assert.deepEqual(store.get(listAtom), ['a', 'b', 'c']); }); test('PUT does not deduplicate', () => { const store = createStore(); const listAtom = createListAtom(); store.set(listAtom, { type: 'PUT', item: 'a' }); store.set(listAtom, { type: 'PUT', item: 'a' }); assert.deepEqual(store.get(listAtom), ['a', 'a']); }); test('DELETE removes a single item by identity', () => { const store = createStore(); const listAtom = createListAtom(); store.set(listAtom, { type: 'PUT', item: ['a', 'b', 'c'] }); store.set(listAtom, { type: 'DELETE', item: 'b' }); assert.deepEqual(store.get(listAtom), ['a', 'c']); }); test('DELETE removes an array of items', () => { const store = createStore(); const listAtom = createListAtom(); store.set(listAtom, { type: 'PUT', item: ['a', 'b', 'c', 'd'] }); store.set(listAtom, { type: 'DELETE', item: ['a', 'c'] }); assert.deepEqual(store.get(listAtom), ['b', 'd']); }); test('DELETE of an absent item is a no-op', () => { const store = createStore(); const listAtom = createListAtom(); store.set(listAtom, { type: 'PUT', item: ['a', 'b'] }); store.set(listAtom, { type: 'DELETE', item: 'z' }); assert.deepEqual(store.get(listAtom), ['a', 'b']); }); test('DELETE uses reference identity for object items', () => { const store = createStore(); const listAtom = createListAtom<{ id: number }>(); const a = { id: 1 }; const b = { id: 2 }; store.set(listAtom, { type: 'PUT', item: [a, b] }); // A structurally-equal but distinct object is not removed. store.set(listAtom, { type: 'DELETE', item: { id: 1 } }); assert.deepEqual(store.get(listAtom), [a, b]); // The same reference is removed. store.set(listAtom, { type: 'DELETE', item: a }); assert.deepEqual(store.get(listAtom), [b]); }); test('REPLACE swaps the matching item, preserving position', () => { const store = createStore(); const listAtom = createListAtom(); store.set(listAtom, { type: 'PUT', item: ['a', 'b', 'c'] }); store.set(listAtom, { type: 'REPLACE', item: 'b', replacement: 'B' }); assert.deepEqual(store.get(listAtom), ['a', 'B', 'c']); }); test('REPLACE matches by identity and replaces every match', () => { const store = createStore(); const listAtom = createListAtom(); store.set(listAtom, { type: 'PUT', item: ['a', 'b', 'a'] }); store.set(listAtom, { type: 'REPLACE', item: 'a', replacement: 'X' }); assert.deepEqual(store.get(listAtom), ['X', 'b', 'X']); }); test('REPLACE with no match leaves the list unchanged', () => { const store = createStore(); const listAtom = createListAtom(); store.set(listAtom, { type: 'PUT', item: ['a', 'b'] }); store.set(listAtom, { type: 'REPLACE', item: 'z', replacement: 'Z' }); assert.deepEqual(store.get(listAtom), ['a', 'b']); });