atagen

malice

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