test: cover enrich/done and documents/bulk-edit page branches
enrich/done: heading, body, both CTA links. documents/bulk-edit: empty-store onMount redirect to /documents, loading spinner during in-flight fetch, error banner on backend error code, error banner on fetch rejection. Mocks fetch via vi.spyOn so the async branches are exercised without a real backend. Refs #496. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
80
frontend/src/routes/documents/bulk-edit/page.svelte.test.ts
Normal file
80
frontend/src/routes/documents/bulk-edit/page.svelte.test.ts
Normal 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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
36
frontend/src/routes/enrich/done/page.svelte.test.ts
Normal file
36
frontend/src/routes/enrich/done/page.svelte.test.ts
Normal 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');
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user