import { describe, it, expect, vi } from 'vitest'; import { render } from 'vitest-browser-svelte'; import { page } from 'vitest/browser'; import TranscriptionReadView from './TranscriptionReadView.svelte'; import type { TranscriptionBlockData } from '$lib/types'; const blocks: TranscriptionBlockData[] = [ { id: 'b1', annotationId: 'ann-1', documentId: 'doc-1', text: 'First paragraph text.', label: null, sortOrder: 1, version: 1 }, { id: 'b2', annotationId: 'ann-2', documentId: 'doc-1', text: 'Second paragraph text.', label: null, sortOrder: 2, version: 1 } ]; describe('TranscriptionReadView', () => { it('should render one paragraph per block', async () => { render(TranscriptionReadView, { blocks, onParagraphClick: () => {} }); await expect.element(page.getByText('First paragraph text.')).toBeInTheDocument(); await expect.element(page.getByText('Second paragraph text.')).toBeInTheDocument(); const paragraphs = document.querySelectorAll('[data-block-id]'); expect(paragraphs.length).toBe(2); }); it('should render [unleserlich] as italic muted text', async () => { render(TranscriptionReadView, { blocks: [ { id: 'b1', annotationId: 'ann-1', documentId: 'doc-1', text: 'Text before [unleserlich] text after', label: null, sortOrder: 1, version: 1 } ], onParagraphClick: () => {} }); const marker = document.querySelector('[data-marker]'); expect(marker).not.toBeNull(); expect(marker!.textContent).toBe('[unleserlich]'); expect(marker!.tagName.toLowerCase()).toBe('em'); }); it('should render [...] as italic muted text', async () => { render(TranscriptionReadView, { blocks: [ { id: 'b1', annotationId: 'ann-1', documentId: 'doc-1', text: 'Some [...] text', label: null, sortOrder: 1, version: 1 } ], onParagraphClick: () => {} }); const marker = document.querySelector('[data-marker]'); expect(marker).not.toBeNull(); expect(marker!.textContent).toBe('[...]'); }); it('should call onParagraphClick with annotationId when paragraph is clicked', async () => { const onParagraphClick = vi.fn(); render(TranscriptionReadView, { blocks, onParagraphClick }); const paragraph = document.querySelector('[data-block-id="b1"]')!; paragraph.dispatchEvent(new MouseEvent('click', { bubbles: true })); expect(onParagraphClick).toHaveBeenCalledWith('ann-1'); }); it('should render blocks sorted by sortOrder', async () => { render(TranscriptionReadView, { blocks: [ { ...blocks[1], sortOrder: 1 }, { ...blocks[0], sortOrder: 2 } ], onParagraphClick: () => {} }); const paragraphs = document.querySelectorAll('[data-block-id]'); expect(paragraphs[0].getAttribute('data-block-id')).toBe('b2'); expect(paragraphs[1].getAttribute('data-block-id')).toBe('b1'); }); it('should apply flash-highlight class when highlightBlockId matches', async () => { render(TranscriptionReadView, { blocks: [blocks[0]], onParagraphClick: () => {}, highlightBlockId: 'b1' }); const el = document.querySelector('[data-block-id="b1"]')!; expect(el.classList.contains('flash-highlight')).toBe(true); }); it('should not apply flash-highlight class when highlightBlockId does not match', async () => { render(TranscriptionReadView, { blocks: [blocks[0]], onParagraphClick: () => {}, highlightBlockId: 'other-id' }); const el = document.querySelector('[data-block-id="b1"]')!; expect(el.classList.contains('flash-highlight')).toBe(false); }); it('should render empty state when no blocks', async () => { render(TranscriptionReadView, { blocks: [], onParagraphClick: () => {} }); const paragraphs = document.querySelectorAll('[data-block-id]'); expect(paragraphs.length).toBe(0); }); });