test: add suites for 8 simple state reducers + msgContent (+50)
Via subagent, all verified, no bugs: - state/toast (7), room-list/roomList (6), inviteList (6), room-list/utils compareRoomsEqual (6), backupRestore (6), callEmbed dispose-on-replace (6), closedNavCategories factory + makeNavCategoryId (8). - features/room/msgContent (5): getAudioMsgContent/getFileMsgContent incl. encrypted (content.file) vs plain (content.url) branch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { createStore } from 'jotai';
|
||||
import { allInvitesAtom } from './inviteList';
|
||||
|
||||
// allInvitesAtom shares the roomList reducer shape over an unexported string[]
|
||||
// baseRoomsAtom: INITIALIZE replace, PUT move-to-end dedupe, DELETE filter-out.
|
||||
// The React binding hook (useBindAllInvitesAtom) is not covered.
|
||||
|
||||
const R1 = '!r1:server';
|
||||
const R2 = '!r2:server';
|
||||
const R3 = '!r3:server';
|
||||
|
||||
test('starts empty', () => {
|
||||
const store = createStore();
|
||||
assert.deepEqual(store.get(allInvitesAtom), []);
|
||||
});
|
||||
|
||||
test('INITIALIZE replaces the whole list', () => {
|
||||
const store = createStore();
|
||||
store.set(allInvitesAtom, { type: 'PUT', roomId: R1 });
|
||||
store.set(allInvitesAtom, { type: 'INITIALIZE', rooms: [R2, R3] });
|
||||
assert.deepEqual(store.get(allInvitesAtom), [R2, R3]);
|
||||
});
|
||||
|
||||
test('PUT appends a new invite', () => {
|
||||
const store = createStore();
|
||||
store.set(allInvitesAtom, { type: 'PUT', roomId: R1 });
|
||||
store.set(allInvitesAtom, { type: 'PUT', roomId: R2 });
|
||||
assert.deepEqual(store.get(allInvitesAtom), [R1, R2]);
|
||||
});
|
||||
|
||||
test('PUT of an existing invite moves it to the end (dedupe)', () => {
|
||||
const store = createStore();
|
||||
store.set(allInvitesAtom, { type: 'INITIALIZE', rooms: [R1, R2, R3] });
|
||||
store.set(allInvitesAtom, { type: 'PUT', roomId: R1 });
|
||||
assert.deepEqual(store.get(allInvitesAtom), [R2, R3, R1]);
|
||||
});
|
||||
|
||||
test('DELETE removes an invite', () => {
|
||||
const store = createStore();
|
||||
store.set(allInvitesAtom, { type: 'INITIALIZE', rooms: [R1, R2, R3] });
|
||||
store.set(allInvitesAtom, { type: 'DELETE', roomId: R2 });
|
||||
assert.deepEqual(store.get(allInvitesAtom), [R1, R3]);
|
||||
});
|
||||
|
||||
test('DELETE of an absent invite is a no-op', () => {
|
||||
const store = createStore();
|
||||
store.set(allInvitesAtom, { type: 'INITIALIZE', rooms: [R1] });
|
||||
store.set(allInvitesAtom, { type: 'DELETE', roomId: R2 });
|
||||
assert.deepEqual(store.get(allInvitesAtom), [R1]);
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { createStore } from 'jotai';
|
||||
import { allRoomsAtom } from './roomList';
|
||||
|
||||
// allRoomsAtom wraps an unexported baseRoomsAtom string[] reducer:
|
||||
// INITIALIZE -> replace wholesale
|
||||
// PUT -> filter-out-then-push (move-to-end dedupe)
|
||||
// DELETE -> filter-out
|
||||
// We drive the reducer through a jotai store. The React binding hook
|
||||
// (useBindAllRoomsAtom) wires this to MatrixClient events and is not covered.
|
||||
|
||||
const R1 = '!r1:server';
|
||||
const R2 = '!r2:server';
|
||||
const R3 = '!r3:server';
|
||||
|
||||
test('starts empty', () => {
|
||||
const store = createStore();
|
||||
assert.deepEqual(store.get(allRoomsAtom), []);
|
||||
});
|
||||
|
||||
test('INITIALIZE replaces the whole list', () => {
|
||||
const store = createStore();
|
||||
store.set(allRoomsAtom, { type: 'PUT', roomId: R1 });
|
||||
store.set(allRoomsAtom, { type: 'INITIALIZE', rooms: [R2, R3] });
|
||||
assert.deepEqual(store.get(allRoomsAtom), [R2, R3]);
|
||||
});
|
||||
|
||||
test('PUT appends a new room', () => {
|
||||
const store = createStore();
|
||||
store.set(allRoomsAtom, { type: 'PUT', roomId: R1 });
|
||||
store.set(allRoomsAtom, { type: 'PUT', roomId: R2 });
|
||||
assert.deepEqual(store.get(allRoomsAtom), [R1, R2]);
|
||||
});
|
||||
|
||||
test('PUT of an existing room moves it to the end (dedupe)', () => {
|
||||
const store = createStore();
|
||||
store.set(allRoomsAtom, { type: 'INITIALIZE', rooms: [R1, R2, R3] });
|
||||
store.set(allRoomsAtom, { type: 'PUT', roomId: R1 });
|
||||
assert.deepEqual(store.get(allRoomsAtom), [R2, R3, R1]);
|
||||
});
|
||||
|
||||
test('DELETE removes a room', () => {
|
||||
const store = createStore();
|
||||
store.set(allRoomsAtom, { type: 'INITIALIZE', rooms: [R1, R2, R3] });
|
||||
store.set(allRoomsAtom, { type: 'DELETE', roomId: R2 });
|
||||
assert.deepEqual(store.get(allRoomsAtom), [R1, R3]);
|
||||
});
|
||||
|
||||
test('DELETE of an absent room is a no-op', () => {
|
||||
const store = createStore();
|
||||
store.set(allRoomsAtom, { type: 'INITIALIZE', rooms: [R1] });
|
||||
store.set(allRoomsAtom, { type: 'DELETE', roomId: R2 });
|
||||
assert.deepEqual(store.get(allRoomsAtom), [R1]);
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { compareRoomsEqual } from './utils';
|
||||
|
||||
// compareRoomsEqual(a, b): length mismatch short-circuits to false, otherwise an
|
||||
// order-sensitive element-by-element equality. The React hook in the same file
|
||||
// (useBindRoomsWithMembershipsAtom) is not covered.
|
||||
|
||||
test('two empty arrays are equal', () => {
|
||||
assert.equal(compareRoomsEqual([], []), true);
|
||||
});
|
||||
|
||||
test('identical arrays are equal', () => {
|
||||
assert.equal(compareRoomsEqual(['a', 'b', 'c'], ['a', 'b', 'c']), true);
|
||||
});
|
||||
|
||||
test('different lengths are not equal', () => {
|
||||
assert.equal(compareRoomsEqual(['a', 'b'], ['a', 'b', 'c']), false);
|
||||
assert.equal(compareRoomsEqual(['a'], []), false);
|
||||
});
|
||||
|
||||
test('same elements in a different order are not equal (order-sensitive)', () => {
|
||||
assert.equal(compareRoomsEqual(['a', 'b'], ['b', 'a']), false);
|
||||
});
|
||||
|
||||
test('a single differing element makes them unequal', () => {
|
||||
assert.equal(compareRoomsEqual(['a', 'b', 'c'], ['a', 'x', 'c']), false);
|
||||
});
|
||||
|
||||
test('reference equality is not required, only value equality', () => {
|
||||
const a = ['a', 'b'];
|
||||
const b = ['a', 'b'];
|
||||
assert.notEqual(a, b);
|
||||
assert.equal(compareRoomsEqual(a, b), true);
|
||||
});
|
||||
Reference in New Issue
Block a user