import { describe, it, expect, vi, afterEach } from 'vitest'; import { cleanup, render } from 'vitest-browser-svelte'; import { page } from 'vitest/browser'; import UploadZone from './UploadZone.svelte'; afterEach(cleanup); describe('UploadZone', () => { describe('idle state', () => { it('shows the filename in the upload zone', async () => { render(UploadZone, { props: { filename: 'brief_1920.pdf', isUploading: false, isDragging: false, error: null } }); await expect.element(page.getByText('brief_1920.pdf')).toBeVisible(); }); it('shows "Datei auswählen" button', async () => { render(UploadZone, { props: { filename: 'scan.pdf', isUploading: false, isDragging: false, error: null } }); await expect.element(page.getByText('Datei auswählen')).toBeVisible(); }); it('does not show the uploading animation', async () => { render(UploadZone, { props: { filename: 'scan.pdf', isUploading: false, isDragging: false, error: null } }); expect(document.querySelector('[role="status"]')).toBeNull(); }); }); describe('uploading state', () => { it('shows the uploading progress region', async () => { render(UploadZone, { props: { filename: 'scan.pdf', isUploading: true, isDragging: false, error: null } }); await expect.element(page.getByRole('status')).toBeVisible(); }); it('shows Abbrechen button during upload', async () => { render(UploadZone, { props: { filename: 'scan.pdf', isUploading: true, isDragging: false, error: null } }); await expect.element(page.getByText('Abbrechen')).toBeVisible(); }); it('calls onCancel when Abbrechen is clicked', async () => { const onCancel = vi.fn(); render(UploadZone, { props: { filename: 'scan.pdf', isUploading: true, isDragging: false, error: null, onCancel } }); // Click the button inside [role="status"] — more specific than querySelector('button') const btn = document.querySelector('[role="status"] button') as HTMLButtonElement; btn.dispatchEvent(new MouseEvent('click', { bubbles: true })); expect(onCancel).toHaveBeenCalledOnce(); }); }); describe('error state', () => { it('shows the error message', async () => { render(UploadZone, { props: { filename: 'scan.pdf', isUploading: false, isDragging: false, error: 'Dateityp nicht unterstützt' } }); await expect.element(page.getByText('Dateityp nicht unterstützt')).toBeVisible(); }); }); describe('file selection', () => { it('calls onFile for a valid PDF', () => { const onFile = vi.fn(); render(UploadZone, { props: { filename: 'scan.pdf', isUploading: false, isDragging: false, error: null, onFile } }); const input = document.querySelector('input[type="file"]') as HTMLInputElement; const pdf = new File(['%PDF-1.4'], 'brief.pdf', { type: 'application/pdf' }); Object.defineProperty(input, 'files', { value: [pdf], writable: false }); input.dispatchEvent(new Event('change', { bubbles: true })); expect(onFile).toHaveBeenCalledWith(pdf); }); it('does not call onFile for an unsupported MIME type', async () => { const onFile = vi.fn(); render(UploadZone, { props: { filename: 'scan.pdf', isUploading: false, isDragging: false, error: null, onFile } }); const input = document.querySelector('input[type="file"]') as HTMLInputElement; const docxFile = new File(['x'], 'test.docx', { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }); Object.defineProperty(input, 'files', { value: [docxFile], writable: false }); input.dispatchEvent(new Event('change', { bubbles: true })); expect(onFile).not.toHaveBeenCalled(); await expect .element(page.getByText('Dieser Dateityp wird nicht unterstützt (PDF, JPG, PNG, TIFF).')) .toBeVisible(); }); it('does not call onFile when file exceeds 50 MB', async () => { const onFile = vi.fn(); render(UploadZone, { props: { filename: 'scan.pdf', isUploading: false, isDragging: false, error: null, onFile } }); const input = document.querySelector('input[type="file"]') as HTMLInputElement; const bigFile = new File(['x'.repeat(1)], 'huge.pdf', { type: 'application/pdf' }); Object.defineProperty(bigFile, 'size', { value: 51 * 1024 * 1024 }); Object.defineProperty(input, 'files', { value: [bigFile], writable: false }); input.dispatchEvent(new Event('change', { bubbles: true })); expect(onFile).not.toHaveBeenCalled(); await expect.element(page.getByText('Die Datei ist zu groß (max. 50 MB).')).toBeVisible(); }); }); });