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', lastName: 'Schmidt', displayName: 'Anna Schmidt', personType: 'PERSON' as const, familyMember: false }; const receiver = { id: 'r1', lastName: 'Meier', displayName: 'Bert Meier', personType: 'PERSON' as const, familyMember: false }; const emptyMatchData = { titleOffsets: [], senderMatched: false, matchedReceiverIds: [], matchedTagIds: [], snippetOffsets: [], summaryOffsets: [] }; const baseItem = (overrides: Record = {}) => ({ id: 'd1', title: 'Brief 1923', originalFilename: 'b.pdf', documentDate: '1923-04-15', sender, receivers: [receiver], tags: [], summary: undefined, archiveBox: undefined, archiveFolder: undefined, location: undefined, matchData: emptyMatchData, completionPercentage: 0, contributors: [], ...overrides }); 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: baseItem({ matchData: { ...emptyMatchData, transcriptionSnippet: 'Hello world snippet' } }) } }); 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('—'); }); });