import { describe, it, expect, vi, afterEach } from 'vitest'; import { cleanup, render } from 'vitest-browser-svelte'; import { page } from 'vitest/browser'; vi.mock('$app/navigation', () => ({ beforeNavigate: () => {}, afterNavigate: () => {}, goto: vi.fn(), invalidate: vi.fn(), invalidateAll: vi.fn(), preloadCode: vi.fn(), preloadData: vi.fn(), pushState: vi.fn(), replaceState: vi.fn(), disableScrollHandling: vi.fn(), onNavigate: () => () => {} })); const { default: DocumentRow } = await import('./DocumentRow.svelte'); afterEach(cleanup); const sender = { id: 's1', displayName: 'Anna Schmidt' }; const receiver = { id: 'r1', displayName: 'Bert Meier' }; const makeDoc = (overrides: Record = {}) => ({ id: 'd1', title: 'Brief 1923', originalFilename: 'b.pdf', documentDate: '1923-04-15', sender, receivers: [receiver], tags: [], thumbnailUrl: null, contentType: 'application/pdf', summary: null, archiveBox: null, archiveFolder: null, location: null, ...overrides }); const baseItem = (docOverrides: Record = {}) => ({ document: makeDoc(docOverrides), matchData: null, completionPercentage: 0, contributors: [] }); describe('DocumentRow', () => { it('renders the title', async () => { render(DocumentRow, { props: { item: baseItem() } }); await expect .element(page.getByRole('heading', { level: 3, name: /brief 1923/i })) .toBeVisible(); }); it('falls back to originalFilename when title is null', async () => { render(DocumentRow, { props: { item: baseItem({ title: null }) } }); await expect.element(page.getByRole('heading', { level: 3, name: /b\.pdf/i })).toBeVisible(); }); it('renders the sender name in the metadata column', async () => { render(DocumentRow, { props: { item: baseItem() } }); await expect.element(page.getByText('Anna Schmidt')).toBeVisible(); }); it('renders the unknown placeholder when sender is null', async () => { render(DocumentRow, { props: { item: baseItem({ sender: null }) } }); const unknownTexts = document.querySelectorAll('.italic'); const hasUnknown = Array.from(unknownTexts).some((el) => el.textContent?.includes('Unbekannt')); expect(hasUnknown).toBe(true); }); it('renders one tag button per document tag', async () => { render(DocumentRow, { props: { item: baseItem({ tags: [ { id: 't1', name: 'Familie', color: null }, { id: 't2', name: 'Reise', color: '#ffaabb' } ] }) } }); await expect.element(page.getByRole('button', { name: 'Familie' })).toBeVisible(); await expect.element(page.getByRole('button', { name: 'Reise' })).toBeVisible(); }); it('renders the bulk-select checkbox when canWrite is true', async () => { render(DocumentRow, { props: { item: baseItem(), canWrite: true } }); const checkbox = document.querySelector('input[type="checkbox"]'); expect(checkbox).not.toBeNull(); }); it('hides the bulk-select checkbox when canWrite is false', async () => { render(DocumentRow, { props: { item: baseItem(), canWrite: false } }); const checkbox = document.querySelector('input[type="checkbox"]'); expect(checkbox).toBeNull(); }); it('renders archive chips when archive metadata is present', async () => { render(DocumentRow, { props: { item: baseItem({ archiveBox: 'Box 1', archiveFolder: 'Mappe A', location: 'Berlin' }) } }); await expect.element(page.getByText('Box 1')).toBeVisible(); await expect.element(page.getByText('Mappe A')).toBeVisible(); await expect.element(page.getByText('Berlin')).toBeVisible(); }); it('renders the snippet when matchData provides a transcriptionSnippet', async () => { render(DocumentRow, { props: { item: { document: makeDoc(), matchData: { transcriptionSnippet: 'Hello world snippet' }, completionPercentage: 50, contributors: [] } } }); await expect.element(page.getByTestId('search-snippet')).toBeVisible(); }); it('renders the summary when present', async () => { render(DocumentRow, { props: { item: baseItem({ summary: 'Brief über die Reise nach Berlin' }) } }); await expect.element(page.getByTestId('doc-summary')).toBeVisible(); }); it('renders an em-dash for missing documentDate', async () => { render(DocumentRow, { props: { item: baseItem({ documentDate: null }) } }); // Multiple em-dashes possible; just ensure at least one is rendered expect(document.body.textContent).toContain('—'); }); });