atagen

malice

public
Star0
Watch0
0e50e0d137af14cdba678cdda9af6a579f894938
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git

Blame: web/test/timeline-groups.test.ts

f93c7e88ea05atagen2026-10-25 10:54 UTC1
import assert from 'node:assert/strict';
f93c7e88ea05atagen2026-10-25 10:54 UTC2
import { test } from 'node:test';
f93c7e88ea05atagen2026-10-25 10:54 UTC3
import { buildGroups, lastOwnSent, lastSenderIs } from '../src/lib/timeline-groups.ts';
f93c7e88ea05atagen2026-10-25 10:54 UTC4
import type { TimelineEvent, TimelineItem } from '../src/lib/types.ts';
f93c7e88ea05atagen2026-10-25 10:54 UTC5
f93c7e88ea05atagen2026-10-25 10:54 UTC6
const MINUTE = 60 * 1000;
f93c7e88ea05atagen2026-10-25 10:54 UTC7
f93c7e88ea05atagen2026-10-25 10:54 UTC8
function event(id: string, sender: string, timestamp_ms: number, extra: Partial<TimelineEvent> = {}): TimelineItem {
f93c7e88ea05atagen2026-10-25 10:54 UTC9
  return {
f93c7e88ea05atagen2026-10-25 10:54 UTC10
    kind: 'event',
f93c7e88ea05atagen2026-10-25 10:54 UTC11
    event: { item_id: id, event_id: id, timestamp_ms, own: false, send_state: { kind: 'Sent' }, sender: { user_id: sender }, ...extra } as TimelineEvent
f93c7e88ea05atagen2026-10-25 10:54 UTC12
  };
f93c7e88ea05atagen2026-10-25 10:54 UTC13
}
f93c7e88ea05atagen2026-10-25 10:54 UTC14
f93c7e88ea05atagen2026-10-25 10:54 UTC15
test('a sender run shares one header until a gap or another sender', () => {
f93c7e88ea05atagen2026-10-25 10:54 UTC16
  const groups = buildGroups([
f93c7e88ea05atagen2026-10-25 10:54 UTC17
    event('a', '@x', 0),
f93c7e88ea05atagen2026-10-25 10:54 UTC18
    event('b', '@x', MINUTE),
f93c7e88ea05atagen2026-10-25 10:54 UTC19
    event('c', '@x', 10 * MINUTE),
f93c7e88ea05atagen2026-10-25 10:54 UTC20
    event('d', '@y', 11 * MINUTE),
f93c7e88ea05atagen2026-10-25 10:54 UTC21
    { kind: 'day', timestamp_ms: 12 * MINUTE },
f93c7e88ea05atagen2026-10-25 10:54 UTC22
    event('e', '@y', 12 * MINUTE)
f93c7e88ea05atagen2026-10-25 10:54 UTC23
  ]);
f93c7e88ea05atagen2026-10-25 10:54 UTC24
  assert.deepEqual(groups.map((g) => g.showSender), [true, false, true, true, true, true]);
f93c7e88ea05atagen2026-10-25 10:54 UTC25
});
f93c7e88ea05atagen2026-10-25 10:54 UTC26
f93c7e88ea05atagen2026-10-25 10:54 UTC27
test('gap rows are keyed by their id so pagination keeps them mounted', () => {
f93c7e88ea05atagen2026-10-25 10:54 UTC28
  const gap = { kind: 'historyGap', gap: { id: 'g1', older_boundary: null, newer_boundary: null, lifecycle: 'Idle', continuity: 'Unresolved', failure: null } } as TimelineItem;
f93c7e88ea05atagen2026-10-25 10:54 UTC29
  assert.equal(buildGroups([event('a', '@x', 0), gap])[1].key, 'gap-g1');
f93c7e88ea05atagen2026-10-25 10:54 UTC30
});
f93c7e88ea05atagen2026-10-25 10:54 UTC31
f93c7e88ea05atagen2026-10-25 10:54 UTC32
test('the latest own sent event and the latest sender are found from the end', () => {
f93c7e88ea05atagen2026-10-25 10:54 UTC33
  const list = [event('a', '@me', 0, { own: true }), event('b', '@x', 1), event('c', '@me', 2, { own: true, send_state: { kind: 'Sending' } })];
f93c7e88ea05atagen2026-10-25 10:54 UTC34
  assert.equal(lastOwnSent(list), 'a');
f93c7e88ea05atagen2026-10-25 10:54 UTC35
  assert.equal(lastSenderIs(list, '@me'), true);
f93c7e88ea05atagen2026-10-25 10:54 UTC36
  assert.equal(lastSenderIs([], '@me'), false);
f93c7e88ea05atagen2026-10-25 10:54 UTC37
});