import { describe, it, expect, afterEach } from 'vitest'; import { cleanup, render } from 'vitest-browser-svelte'; import { page } from 'vitest/browser'; import TrainingHistory from './TrainingHistory.svelte'; afterEach(cleanup); const makeRun = (overrides: Record = {}) => ({ id: 'r1', createdAt: '2026-04-15T10:00:00Z', status: 'DONE' as 'DONE' | 'FAILED' | 'QUEUED' | 'RUNNING', blockCount: 100, documentCount: 5, personId: null as string | null, cer: 0.05, errorMessage: null as string | null, ...overrides }); describe('TrainingHistory', () => { it('renders the empty placeholder when runs is empty', async () => { render(TrainingHistory, { props: { runs: [] } }); await expect.element(page.getByText('Noch keine Trainings-Läufe.')).toBeVisible(); }); it('renders the QUEUED status pill', async () => { render(TrainingHistory, { props: { runs: [makeRun({ status: 'QUEUED' })] } }); await expect.element(page.getByText('Warteschlange')).toBeVisible(); }); it('renders the DONE status pill', async () => { render(TrainingHistory, { props: { runs: [makeRun({ status: 'DONE' })] } }); await expect.element(page.getByText('Fertig')).toBeVisible(); }); it('renders the FAILED status pill', async () => { render(TrainingHistory, { props: { runs: [makeRun({ status: 'FAILED' })] } }); // "Fehler" might match multiple things — check for the pill specifically const pill = Array.from(document.querySelectorAll('span')).find( (el) => el.textContent?.trim() === 'Fehler' ); expect(pill).toBeDefined(); }); it('renders the RUNNING status pill for unknown statuses', async () => { render(TrainingHistory, { props: { runs: [makeRun({ status: 'RUNNING' as const })] } }); await expect.element(page.getByText('Läuft…')).toBeVisible(); }); it('shows the error-detail disclosure when a FAILED run has errorMessage', async () => { render(TrainingHistory, { props: { runs: [makeRun({ status: 'FAILED', errorMessage: 'Network timeout' })] } }); await expect.element(page.getByText('Network timeout')).toBeInTheDocument(); }); it('renders Personalisiert label when personId is set', async () => { render(TrainingHistory, { props: { runs: [makeRun({ personId: 'p-1' })], personNames: { 'p-1': 'Anna Schmidt' } } }); await expect.element(page.getByText('Personalisiert')).toBeVisible(); }); it('renders Basis label when personId is null', async () => { render(TrainingHistory, { props: { runs: [makeRun()] } }); await expect.element(page.getByText('Basis')).toBeVisible(); }); it('limits visible runs to COLLAPSED_COUNT (3) by default', async () => { const runs = Array.from({ length: 7 }, (_, i) => makeRun({ id: `r${i}` })); render(TrainingHistory, { props: { runs } }); const rows = document.querySelectorAll('#training-history-rows > tr'); expect(rows.length).toBeLessThanOrEqual(4); // 3 visible + maybe expand row }); it('hides person columns when showPersonColumns is false', async () => { render(TrainingHistory, { props: { runs: [makeRun({ personId: 'p1' })], showPersonColumns: false } }); await expect.element(page.getByText('Personalisiert')).not.toBeInTheDocument(); }); it('renders em-dash CER for runs without cer', async () => { render(TrainingHistory, { props: { runs: [makeRun({ cer: null })] } }); expect(document.body.textContent).toContain('—'); }); });