import { test } from 'node:test'; import assert from 'node:assert/strict'; import { foldEdits, filterGroupsByDateRange, filterGroupsByMsgType, filterGroupsByPinned, ResultGroup, } from './useMessageSearch'; // Minimal ResultGroup/ResultItem fixtures — only the fields the filters read // (event.content.msgtype, event.event_id, group.roomId). const item = (msgtype: string | undefined, eventId: string) => ({ rank: 1, event: { event_id: eventId, content: msgtype === undefined ? {} : { msgtype } }, context: {}, }); const tsItem = (eventId: string, ts: number) => ({ rank: 1, event: { event_id: eventId, origin_server_ts: ts, content: {} }, context: {}, }); const mkGroups = ( ...groups: { roomId: string; items: ReturnType[] }[] ): ResultGroup[] => groups as unknown as ResultGroup[]; test('filterGroupsByMsgType: empty filter returns groups unchanged', () => { const groups = mkGroups({ roomId: '!r1', items: [item('m.text', '$1'), item('m.image', '$2')] }); assert.equal(filterGroupsByMsgType(groups, []), groups); }); test('filterGroupsByMsgType: keeps only matching msgtypes (union)', () => { const groups = mkGroups({ roomId: '!r1', items: [item('m.text', '$1'), item('m.image', '$2'), item('m.file', '$3')], }); const out = filterGroupsByMsgType(groups, ['m.image', 'm.file']); assert.equal(out.length, 1); assert.deepEqual( out[0].items.map((i) => i.event.event_id), ['$2', '$3'], ); }); test('filterGroupsByMsgType: drops groups left empty', () => { const groups = mkGroups( { roomId: '!r1', items: [item('m.text', '$1')] }, { roomId: '!r2', items: [item('m.image', '$2')] }, ); const out = filterGroupsByMsgType(groups, ['m.image']); assert.equal(out.length, 1); assert.equal(out[0].roomId, '!r2'); }); test('filterGroupsByMsgType: ignores items with a non-string msgtype', () => { const groups = mkGroups({ roomId: '!r1', items: [item(undefined, '$1'), item('m.video', '$2')] }); const out = filterGroupsByMsgType(groups, ['m.video']); assert.equal(out[0].items.length, 1); assert.equal(out[0].items[0].event.event_id, '$2'); }); test('filterGroupsByDateRange: no bounds returns groups unchanged', () => { const groups = mkGroups({ roomId: '!r1', items: [tsItem('$1', 100)] }); assert.equal(filterGroupsByDateRange(groups, undefined, undefined), groups); }); test('filterGroupsByDateRange: keeps only items within an inclusive range', () => { const groups = mkGroups({ roomId: '!r1', items: [tsItem('$1', 50), tsItem('$2', 100), tsItem('$3', 150), tsItem('$4', 200)], }); const out = filterGroupsByDateRange(groups, 100, 150); assert.deepEqual( out[0].items.map((i) => i.event.event_id), ['$2', '$3'], ); }); test('filterGroupsByDateRange: drops groups left empty and supports one-sided bounds', () => { const groups = mkGroups( { roomId: '!r1', items: [tsItem('$1', 50)] }, { roomId: '!r2', items: [tsItem('$2', 500)] }, ); const out = filterGroupsByDateRange(groups, 100, undefined); assert.equal(out.length, 1); assert.equal(out[0].roomId, '!r2'); }); test('filterGroupsByPinned: disabled returns groups unchanged', () => { const groups = mkGroups({ roomId: '!r1', items: [item('m.text', '$1')] }); assert.equal( filterGroupsByPinned(groups, false, () => false), groups, ); }); test('filterGroupsByPinned: keeps pinned items and drops empty groups', () => { const groups = mkGroups( { roomId: '!r1', items: [item('m.text', '$1'), item('m.text', '$2')] }, { roomId: '!r2', items: [item('m.text', '$3')] }, ); const pinned = new Set(['!r1/$2']); const out = filterGroupsByPinned(groups, true, (roomId, eventId) => pinned.has(`${roomId}/${eventId}`), ); assert.equal(out.length, 1); assert.equal(out[0].roomId, '!r1'); assert.deepEqual( out[0].items.map((i) => i.event.event_id), ['$2'], ); }); const sr = (eventId: string, ts: number, content: Record) => ({ rank: 1, result: { event_id: eventId, room_id: '!r:x', origin_server_ts: ts, type: 'm.room.message', content, }, }) as unknown as Parameters[0][number]; test('foldEdits: one row per message, showing the latest edit (#288)', () => { const edit = (id: string, ts: number, body: string) => sr(id, ts, { body: `* ${body}`, 'm.new_content': { body }, 'm.relates_to': { rel_type: 'm.replace', event_id: '$orig' }, }); const out = foldEdits([ edit('$e2', 30, 'Tuesday 11am room B'), sr('$orig', 10, { body: 'Monday 10am room A' }), edit('$e1', 20, 'Tuesday 10am room A'), sr('$other', 5, { body: 'meeting notes' }), ]); assert.deepEqual( out.map((r) => r.result.event_id), ['$orig', '$other'], ); assert.deepEqual(out[0].result.content['m.new_content'], { body: 'Tuesday 11am room B' }); assert.equal(out[0].result.content.body, 'Monday 10am room A'); }); test('foldEdits: an edit whose original did not match stands in for it', () => { const out = foldEdits([ sr('$e1', 20, { 'm.new_content': { body: 'x' }, 'm.relates_to': { rel_type: 'm.replace', event_id: '$orig' }, }), ]); assert.equal(out.length, 1); assert.equal(out[0].result.event_id, '$orig'); });