test(coverage): drive browser tests to 80% on all metrics (#496) #505

Merged
marcel merged 189 commits from feat/issue-496-browser-coverage-tests into main 2026-05-11 21:50:39 +02:00
2 changed files with 116 additions and 0 deletions
Showing only changes of commit cd14f9cd6c - Show all commits

View File

@@ -0,0 +1,80 @@
import { describe, it, expect, vi, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
const gotoSpy = vi.fn();
vi.mock('$app/navigation', () => ({
beforeNavigate: () => {},
afterNavigate: () => {},
goto: gotoSpy,
invalidate: vi.fn(),
invalidateAll: vi.fn(),
preloadCode: vi.fn(),
preloadData: vi.fn(),
pushState: vi.fn(),
replaceState: vi.fn(),
disableScrollHandling: vi.fn(),
onNavigate: () => () => {}
}));
const { bulkSelectionStore } = await import('$lib/document/bulkSelection.svelte');
const { default: BulkEditPage } = await import('./+page.svelte');
afterEach(() => {
cleanup();
bulkSelectionStore.clear();
gotoSpy.mockClear();
});
describe('documents/bulk-edit page', () => {
it('redirects to /documents when no documents are selected', async () => {
render(BulkEditPage, { props: {} });
// onMount runs immediately — give it a tick
await new Promise((r) => setTimeout(r, 50));
expect(gotoSpy).toHaveBeenCalledWith('/documents');
});
it('shows the loading spinner while fetching batch metadata', async () => {
bulkSelectionStore.toggle('d1');
const fetchSpy = vi.spyOn(globalThis, 'fetch').mockImplementation(() => new Promise(() => {}));
try {
render(BulkEditPage, { props: {} });
await expect.element(page.getByRole('status')).toBeVisible();
await expect.element(page.getByText('Dokumente werden geladen…')).toBeVisible();
} finally {
fetchSpy.mockRestore();
}
});
it('shows the error banner when the fetch fails with a backend error code', async () => {
bulkSelectionStore.toggle('d1');
const fetchSpy = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
new Response(JSON.stringify({ code: 'INTERNAL_ERROR' }), {
status: 500,
headers: { 'Content-Type': 'application/json' }
})
);
try {
render(BulkEditPage, { props: {} });
await expect.element(page.getByRole('alert')).toBeVisible();
} finally {
fetchSpy.mockRestore();
}
});
it('shows the error banner when fetch throws an unexpected error', async () => {
bulkSelectionStore.toggle('d1');
const fetchSpy = vi.spyOn(globalThis, 'fetch').mockRejectedValue(new Error('Network down'));
try {
render(BulkEditPage, { props: {} });
await expect.element(page.getByRole('alert')).toBeVisible();
} finally {
fetchSpy.mockRestore();
}
});
});

View File

@@ -0,0 +1,36 @@
import { describe, it, expect, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
import EnrichDonePage from './+page.svelte';
afterEach(cleanup);
describe('enrich/done page', () => {
it('renders the success heading', async () => {
render(EnrichDonePage, { props: {} });
await expect.element(page.getByRole('heading', { name: /alles erledigt/i })).toBeVisible();
});
it('renders the body message', async () => {
render(EnrichDonePage, { props: {} });
await expect.element(page.getByText('Alle Dokumente wurden bearbeitet.')).toBeVisible();
});
it('links the primary CTA to the home page', async () => {
render(EnrichDonePage, { props: {} });
await expect
.element(page.getByRole('link', { name: /zurück zur übersicht/i }))
.toHaveAttribute('href', '/');
});
it('links the secondary CTA back to /enrich', async () => {
render(EnrichDonePage, { props: {} });
await expect
.element(page.getByRole('link', { name: /zurück zur liste/i }))
.toHaveAttribute('href', '/enrich');
});
});