Files
Mangalord/frontend/e2e/error-boundary.spec.ts
MechaCat02 32d0a7e13b feat: root error boundary and network-error normalisation
A load() that rethrew (e.g. the profile overview) fell through to SvelteKit's
bare default error page, and a connection-refused fetch rejected as a raw
TypeError that blanked the view. Wrap fetch network failures in the client as
ApiError(status 0, network_error) so callers handle them uniformly, and add a
root +error.svelte with a friendly message plus Try again / Go home actions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 14:47:41 +02:00

43 lines
1.7 KiB
TypeScript

import { test, expect, type Page } from './fixtures';
// The root +error.svelte catches load() errors that a page rethrows rather than
// capturing in-band (e.g. the profile overview). Without it these fell through
// to SvelteKit's bare default error page — or blanked entirely on a raw
// TypeError. Drive the profile loader into a failure and assert the boundary.
async function authed(page: Page) {
await page.route('**/api/v1/auth/config', (r) =>
r.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ self_register_enabled: true, private_mode: false })
})
);
await page.route('**/api/v1/auth/me', (r) =>
r.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
user: { id: 'u1', username: 'reader', created_at: '2026-01-01T00:00:00Z', is_admin: false }
})
})
);
await page.route('**/api/v1/auth/me/preferences', (r) =>
r.fulfill({ status: 200, contentType: 'application/json', body: '{}' })
);
}
test('profile: a network failure renders the error boundary, not a blank page', async ({
page
}) => {
await authed(page);
// Profile's load rethrows non-401 errors; a raw abort is the TypeError case
// the client now normalises to an ApiError so it reaches the boundary.
await page.route('**/api/v1/me/bookmarks*', (r) => r.abort());
await page.route('**/api/v1/me/collections*', (r) => r.abort());
await page.goto('/profile');
await expect(page.getByTestId('error-boundary')).toBeVisible();
await expect(page.getByRole('button', { name: 'Try again' })).toBeVisible();
});