feat(observability): add handleError hook with errorId and redesigned error page #608

Merged
marcel merged 11 commits from feat/issue-462-handle-error-hook into main 2026-05-17 12:38:10 +02:00
2 changed files with 44 additions and 4 deletions
Showing only changes of commit c779ec59f9 - Show all commits

View File

@@ -7,10 +7,16 @@ let copied = $state(false);
function copyId() {
const id = page.error?.errorId;
if (!id) return;
navigator.clipboard.writeText(id).then(() => {
copied = true;
setTimeout(() => (copied = false), 2000);
});
if (!navigator.clipboard) return;
navigator.clipboard.writeText(id).then(
() => {
copied = true;
setTimeout(() => (copied = false), 2000);
},
() => {
/* clipboard denied or unavailable — select-all on the <code> element remains */
}
);
}
</script>

View File

@@ -94,4 +94,38 @@ describe('+error.svelte', () => {
await expect.element(browserPage.getByText('Fehler-ID')).not.toBeInTheDocument();
});
it('shows "Kopiert!" after clicking the copy button', async () => {
mockPage.status = 500;
mockPage.error = { message: 'Something broke', errorId: 'abc-123-def' };
Object.defineProperty(navigator, 'clipboard', {
value: { writeText: vi.fn().mockResolvedValue(undefined) },
configurable: true,
writable: true
});
const ErrorPage = await loadComponent();
render(ErrorPage);
await browserPage.getByRole('button', { name: 'ID kopieren' }).click();
await expect.element(browserPage.getByText('Kopiert!')).toBeVisible();
});
it('does not show "Kopiert!" when clipboard write is rejected', async () => {
mockPage.status = 500;
mockPage.error = { message: 'Something broke', errorId: 'abc-123-def' };
Object.defineProperty(navigator, 'clipboard', {
value: { writeText: vi.fn().mockRejectedValue(new Error('denied')) },
configurable: true,
writable: true
});
const ErrorPage = await loadComponent();
render(ErrorPage);
await browserPage.getByRole('button', { name: 'ID kopieren' }).click();
await expect.element(browserPage.getByText('Kopiert!')).not.toBeInTheDocument();
});
});