48af82777108 | atagen | 2026-10-26 10:41 UTC | 1 | import assert from 'node:assert/strict'; |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 2 | import { test } from 'node:test'; |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 3 | import { contextWithProfiles, roomsLackingProfiles, withProfiles } from '../src/lib/mention-profiles.ts'; |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 4 | import type { MemberSummary, Sender, TimelineItem } from '../src/lib/types.ts'; |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 5 | |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 6 | const bare = (user_id: string): Sender => ({ user_id, display_name: null, avatar: null, name_ambiguous: false }); |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 7 | |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 8 | function message(sender: Sender, replySender: Sender | null = null): TimelineItem { |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 9 | return { |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 10 | kind: 'event', |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 11 | event: { |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 12 | item_id: `i-${sender.user_id}`, |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 13 | event_id: `$e-${sender.user_id}`, |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 14 | transaction_id: null, |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 15 | sender, |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 16 | timestamp_ms: 1, |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 17 | own: false, |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 18 | send_state: { kind: 'Sent' }, |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 19 | content: { kind: 'Redacted' }, |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 20 | reply_to: replySender ? { event_id: '$target', details: { kind: 'Ready', sender: replySender, content: { kind: 'Redacted' }, timestamp_ms: 0 } } : null, |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 21 | thread_root: null, |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 22 | thread_summary: null, |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 23 | reactions: [], |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 24 | read_by: [], |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 25 | editable: false |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 26 | } |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 27 | }; |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 28 | } |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 29 | |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 30 | function member(user_id: string, display_name: string | null, avatar: string | null = null): MemberSummary { |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 31 | return { user_id, name: display_name ?? user_id, display_name, avatar, membership: 'Join', own: false, name_ambiguous: false, ignored: false, service: false }; |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 32 | } |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 33 | |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 34 | const members = { '@carol:x': member('@carol:x', 'Carol', 'mxc://x/c'), '@dave:x': member('@dave:x', 'Dave') }; |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 35 | |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 36 | test('lists only rooms with a sender or reply sender missing both name and avatar', () => { |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 37 | const named = { ...bare('@carol:x'), display_name: 'Carol' }; |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 38 | const rooms = roomsLackingProfiles([ |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 39 | { roomId: '!a:x', item: message(named) }, |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 40 | { roomId: '!b:x', item: message(bare('@carol:x')) }, |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 41 | { roomId: '!c:x', item: message(named, bare('@dave:x')) }, |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 42 | { roomId: '!d:x', item: { kind: 'readMarker' } } |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 43 | ]); |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 44 | assert.deepEqual([...rooms].sort(), ['!b:x', '!c:x']); |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 45 | }); |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 46 | |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 47 | test('fills the sender and reply sender from the room members', () => { |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 48 | const filled = withProfiles(message(bare('@carol:x'), bare('@dave:x')), members); |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 49 | assert.equal(filled.kind, 'event'); |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 50 | if (filled.kind !== 'event') return; |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 51 | assert.equal(filled.event.sender.display_name, 'Carol'); |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 52 | assert.equal(filled.event.sender.avatar, 'mxc://x/c'); |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 53 | assert.equal(filled.event.reply_to?.details.kind === 'Ready' && filled.event.reply_to.details.sender.display_name, 'Dave'); |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 54 | }); |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 55 | |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 56 | test('keeps an engine profile and the same item when nothing changes', () => { |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 57 | const named = message({ ...bare('@carol:x'), display_name: 'Carol from the engine' }); |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 58 | assert.equal(withProfiles(named, members), named); |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 59 | const unknown = message(bare('@erin:x')); |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 60 | assert.equal(withProfiles(unknown, members), unknown); |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 61 | const context = { events_before: [unknown], event: named, events_after: [], start_token: null, end_token: null }; |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 62 | assert.equal(contextWithProfiles(context, undefined), context); |
48af82777108 | atagen | 2026-10-26 10:41 UTC | 63 | }); |