import { describe, it, expect, afterEach } from 'vitest'; import { cleanup, render } from 'vitest-browser-svelte'; import ChronikRow from './ChronikRow.svelte'; afterEach(cleanup); const baseActor = { id: 'a1', name: 'Anna Schmidt', initials: 'AS', color: '#012851' }; const makeItem = (overrides: Record = {}) => ({ id: 'i1', kind: 'TEXT_SAVED' as string, actor: baseActor as null | typeof baseActor, documentId: 'd1', documentTitle: 'Brief 1923', count: 1, happenedAt: '2026-04-15T10:00:00Z', happenedAtUntil: null as string | null, commentId: null as string | null, commentPreview: null as string | null, annotationId: null as string | null, youMentioned: false, ...overrides }); describe('ChronikRow', () => { it('renders the actor avatar with initials when actor is present', async () => { render(ChronikRow, { props: { item: makeItem() } }); expect(document.body.textContent).toContain('AS'); }); it('renders the question-mark fallback avatar when actor is null', async () => { render(ChronikRow, { props: { item: makeItem({ actor: null }) } }); const fallback = document.querySelector('[data-testid="chronik-avatar-fallback"]'); expect(fallback).not.toBeNull(); }); it('renders the for-you marker when youMentioned is true', async () => { render(ChronikRow, { props: { item: makeItem({ youMentioned: true }) } }); const marker = document.querySelector('[data-testid="chronik-foryou-marker"]'); expect(marker).not.toBeNull(); }); it('renders the for-you data-variant when youMentioned is true', async () => { render(ChronikRow, { props: { item: makeItem({ youMentioned: true }) } }); const link = document.querySelector('a[data-variant]') as HTMLElement; expect(link.getAttribute('data-variant')).toBe('for-you'); }); it('renders the rollup variant when count > 1', async () => { render(ChronikRow, { props: { item: makeItem({ count: 3 }) } }); const link = document.querySelector('a[data-variant]') as HTMLElement; expect(link.getAttribute('data-variant')).toBe('rollup'); const badge = document.querySelector('[data-testid="chronik-count-badge"]'); expect(badge).not.toBeNull(); }); it('renders the comment variant for COMMENT_ADDED kind', async () => { render(ChronikRow, { props: { item: makeItem({ kind: 'COMMENT_ADDED', commentPreview: 'Tolle Geschichte!' }) } }); const link = document.querySelector('a[data-variant]') as HTMLElement; expect(link.getAttribute('data-variant')).toBe('comment'); const preview = document.querySelector('[data-testid="chronik-comment-preview"]'); expect(preview?.textContent).toContain('Tolle Geschichte!'); }); it('falls back to ellipsis comment preview when commentPreview is null', async () => { render(ChronikRow, { props: { item: makeItem({ kind: 'COMMENT_ADDED' }) } }); const preview = document.querySelector('[data-testid="chronik-comment-preview"]'); expect(preview?.textContent).toContain('…'); }); it('renders the document title in a styled span', async () => { render(ChronikRow, { props: { item: makeItem() } }); const title = document.querySelector('[data-testid="chronik-doc-title"]'); expect(title?.textContent).toBe('Brief 1923'); }); it('uses /documents/{id} as default href', async () => { render(ChronikRow, { props: { item: makeItem() } }); const link = document.querySelector('a[data-variant]') as HTMLAnchorElement; expect(link.href).toContain('/documents/d1'); }); it('uses comment-deep-link href when commentId is set', async () => { render(ChronikRow, { props: { item: makeItem({ commentId: 'c1', kind: 'COMMENT_ADDED' }) } }); const link = document.querySelector('a[data-variant]') as HTMLAnchorElement; expect(link.href).toContain('c1'); }); it('renders a time-range label when rollup has happenedAtUntil', async () => { render(ChronikRow, { props: { item: makeItem({ count: 5, happenedAt: '2026-04-15T10:00:00Z', happenedAtUntil: '2026-04-15T14:30:00Z' }) } }); // Time range uses U+2013 between two HH:MM strings — check for any colon-bearing time expect(document.body.textContent).toMatch(/\d{2}:\d{2}/); }); });