import { describe, expect, it } from 'vitest'; import { groupChatTimeline, type ChatBoundaryEntry, type ChatMessageEntry } from '../../src/lib/ui/chat-timeline.js'; const boundary = (event: ChatBoundaryEntry['event'], time: string | null): ChatBoundaryEntry => ({ type: 'boundary', event, time, context: { realTime: null, matchElapsedMs: null, round: null } }); const message = (text: string, round: number | null = 7): ChatMessageEntry => ({ type: 'message', message: { time: '12:08', guid: 'abc', slot: 0, player: 'Player', message: text }, context: { realTime: '2026-10-02T12:16:04Z', matchElapsedMs: 728000, round } }); describe('chat timeline display groups', () => { it('retains every lifecycle event in log order, including repeated starts, resets and unknown times', () => { const entries = Object.freeze([ boundary('end', '80:00'), boundary('start', null), boundary('start', '0:00'), boundary('reset', '0:00'), boundary('end', null) ]); const timeline = groupChatTimeline(entries); expect(timeline).toEqual([{ type: 'boundaries', entries }]); if (timeline[0].type !== 'boundaries') throw new Error('Expected lifecycle group'); timeline[0].entries.forEach((entry, index) => expect(entry).toBe(entries[index])); }); it('never combines lifecycle runs separated by messages, including leading and trailing runs', () => { const first = [boundary('start', null), boundary('reset', '0:00')]; const middle = [boundary('end', '12:08'), boundary('start', '0:00')]; const last = [boundary('end', null)]; const hello = message('hello'); const goodbye = message('goodbye'); expect(groupChatTimeline([...first, hello, ...middle, goodbye, ...last])).toEqual([ { type: 'boundaries', entries: first }, { type: 'message', entry: hello }, { type: 'boundaries', entries: middle }, { type: 'message', entry: goodbye }, { type: 'boundaries', entries: last } ]); }); it('preserves consecutive and repeated messages with their individual contexts', () => { const entries = Object.freeze([ message('hello', 7), message('hello', 8), message('later', null) ]); const timeline = groupChatTimeline(entries); expect(timeline).toEqual(entries.map((entry) => ({ type: 'message', entry }))); timeline.forEach((item, index) => { if (item.type !== 'message') throw new Error('Expected message'); expect(item.entry).toBe(entries[index]); expect(item.entry.context).toBe(entries[index].context); }); }); });