import { test } from 'node:test'; import assert from 'node:assert/strict'; import type { MatrixClient } from 'matrix-js-sdk'; import { memberChangeStore } from './useRoomMemberChange'; // Minimal fake client: records registered handlers and can emit a member change. // The store registers exactly one RoomStateEvent.Members handler; we invoke it // with the same (event, state, member) shape the SDK uses. const makeFakeMx = () => { const handlers: Array<(e: unknown, s: unknown, m: unknown) => void> = []; const mx = { on: (_event: unknown, h: (e: unknown, s: unknown, m: unknown) => void) => { handlers.push(h); }, removeListener: (_event: unknown, h: (e: unknown, s: unknown, m: unknown) => void) => { const i = handlers.indexOf(h); if (i >= 0) handlers.splice(i, 1); }, }; return { mx: mx as unknown as MatrixClient, listenerCount: () => handlers.length, emit: (roomId: string, userId: string) => handlers.forEach((h) => h({ getRoomId: () => roomId }, undefined, { userId })), }; }; test('fans out only to the matching roomId|userId', () => { const { mx, emit } = makeFakeMx(); let a = 0; let b = 0; memberChangeStore.subscribe(mx, '!fanout', '@a', () => { a += 1; }); memberChangeStore.subscribe(mx, '!fanout', '@b', () => { b += 1; }); emit('!fanout', '@a'); assert.equal(a, 1); assert.equal(b, 0); emit('!other', '@a'); // different room, same user -> no fire assert.equal(a, 1); }); test('registers exactly one client listener regardless of subscriber count', () => { const { mx, listenerCount } = makeFakeMx(); memberChangeStore.subscribe(mx, '!one', '@a', () => {}); memberChangeStore.subscribe(mx, '!one', '@b', () => {}); memberChangeStore.subscribe(mx, '!one2', '@c', () => {}); assert.equal(listenerCount(), 1); }); test('idempotent unsubscribe does not evict a re-subscribed key', () => { const { mx, emit } = makeFakeMx(); const unsubA = memberChangeStore.subscribe(mx, '!idem', '@a', () => {}); unsubA(); let count = 0; memberChangeStore.subscribe(mx, '!idem', '@a', () => { count += 1; }); unsubA(); // double-invoke of the first unsub must not drop the new subscriber emit('!idem', '@a'); assert.equal(count, 1); });