diff --git a/frontend/src/routes/DropZone.svelte.spec.ts b/frontend/src/routes/DropZone.svelte.spec.ts index 514f1b74..440c2f0c 100644 --- a/frontend/src/routes/DropZone.svelte.spec.ts +++ b/frontend/src/routes/DropZone.svelte.spec.ts @@ -4,7 +4,10 @@ import { page } from 'vitest/browser'; import DropZone from './DropZone.svelte'; -vi.mock('$app/navigation', () => ({ invalidateAll: vi.fn(async () => {}) })); +// vi.hoisted lets the mock fn reference survive vi.mock's hoisting so tests +// can assert on it from below while the factory remains self-contained. +const { invalidateAllMock } = vi.hoisted(() => ({ invalidateAllMock: vi.fn(async () => {}) })); +vi.mock('$app/navigation', () => ({ invalidateAll: invalidateAllMock })); afterEach(() => { cleanup(); @@ -62,8 +65,11 @@ describe('DropZone onUploadComplete', () => { input.files = dt.files; input.dispatchEvent(new Event('change', { bubbles: true })); - // Wait a tick to let the microtask flush - await new Promise((r) => setTimeout(r, 50)); + // invalidateAll is the last async step of the upload handler — once it + // has been called, the callback decision has already been made. + await vi.waitFor(() => { + expect(invalidateAllMock).toHaveBeenCalled(); + }); expect(onUploadComplete).not.toHaveBeenCalled(); }); @@ -75,10 +81,9 @@ describe('DropZone onUploadComplete', () => { const file = new File(['%PDF-1.4'], 'x.pdf', { type: 'application/pdf' }); const dt = new DataTransfer(); dt.items.add(file); + // Should not throw when the optional callback is absent. input.files = dt.files; - // Should not throw input.dispatchEvent(new Event('change', { bubbles: true })); - await new Promise((r) => setTimeout(r, 50)); await expect.element(page.getByText(/1 Dokument/)).toBeInTheDocument(); }); });