test: add suites for time, matrix, mimeTypes, and search filters (+47 tests)

Expands pure-logic coverage (harness: tsx + node:test):
- utils/time (21): date/time formatters — exact values where timezone-independent,
  structure/regex where locale/tz-sensitive (written via subagent).
- utils/matrix (13): pure id/mxc helpers (isUserId/isRoomId/isRoomAlias/
  getMxIdLocalPart/getMxIdServer/isServerName + room-version gates). (subagent)
- utils/mimeTypes (7): getBlobSafeMimeType allowlist+remap, safeFile rewrap,
  mimeTypeToExt, getFileNameExt/WithoutExt edge cases.
- message-search filters (6): filterGroupsByMsgType (union, empty-group drop,
  non-string msgtype) + filterGroupsByPinned (disabled passthrough, pinned-only).

All assertions verified against actual runtime behavior. Suite now 74 tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-30 10:27:57 -04:00
parent a7d145aa70
commit ae1d30bc5a
4 changed files with 437 additions and 0 deletions
@@ -0,0 +1,74 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { 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 mkGroups = (
...groups: { roomId: string; items: ReturnType<typeof item>[] }[]
): 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('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'],
);
});