UX: PDF viewer has no loading indicator or error state when pdfjs-dist fails to initialise #543

Open
opened 2026-05-12 09:39:53 +02:00 by marcel · 0 comments
Owner

Problem

PdfViewer.svelte calls init() from onMount, which loads pdfjs-dist via a dynamic import. Between mount and pdfjsReady = true, the component is in an indeterminate state:

  • Navigation buttons and zoom controls are visible immediately (confirmed by the browser-mode specs)
  • If the user clicks them before the library loads, nothing happens (no feedback)
  • If init() rejects (network failure, missing bundle), pdfjsReady stays false and the user sees no error message

The libLoader injection added in PR #536 makes both states explicitly testable via the PdfViewer libLoader prop.

Acceptance criteria

  • A loading indicator (spinner or skeleton) is shown while init() is pending
  • An error message is shown when init() rejects (the error state returned by createPdfRenderer can drive this)
  • Browser-mode spec coverage for both states using a slow/rejecting libLoader:
it('shows a loading indicator while the library is initialising', async () => {
    let resolveLoader!: () => void;
    const slowLoader: LibLoader = () =>
        new Promise(resolve => { resolveLoader = () => resolve([fakePdfjs, { default: '' }] as const); });
    render(PdfViewer, { url: '...', libLoader: slowLoader });
    await expect.element(page.getByRole('status')).toBeInTheDocument();
    resolveLoader();
    await expect.element(page.getByText(/1\s*\/\s*2/)).toBeInTheDocument();
});

Raised by Sara Holt and Leonie Voss in PR #536 round-4 review.

## Problem `PdfViewer.svelte` calls `init()` from `onMount`, which loads `pdfjs-dist` via a dynamic import. Between mount and `pdfjsReady = true`, the component is in an indeterminate state: - Navigation buttons and zoom controls are **visible immediately** (confirmed by the browser-mode specs) - If the user clicks them before the library loads, nothing happens (no feedback) - If `init()` rejects (network failure, missing bundle), `pdfjsReady` stays `false` and the user sees no error message The `libLoader` injection added in PR #536 makes both states explicitly testable via the `PdfViewer` `libLoader` prop. ## Acceptance criteria - A loading indicator (spinner or skeleton) is shown while `init()` is pending - An error message is shown when `init()` rejects (the `error` state returned by `createPdfRenderer` can drive this) - Browser-mode spec coverage for both states using a slow/rejecting `libLoader`: ```typescript it('shows a loading indicator while the library is initialising', async () => { let resolveLoader!: () => void; const slowLoader: LibLoader = () => new Promise(resolve => { resolveLoader = () => resolve([fakePdfjs, { default: '' }] as const); }); render(PdfViewer, { url: '...', libLoader: slowLoader }); await expect.element(page.getByRole('status')).toBeInTheDocument(); resolveLoader(); await expect.element(page.getByText(/1\s*\/\s*2/)).toBeInTheDocument(); }); ``` Raised by Sara Holt and Leonie Voss in PR #536 round-4 review.
marcel added the P2-mediumfeatureui labels 2026-05-12 09:40:09 +02:00
Sign in to join this conversation.
No Label P2-medium feature ui
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: marcel/familienarchiv#543