fix(pdf-viewer): replace vi.mock(pdfjs-dist) with injected libLoader prop
Removes both vi.mock('pdfjs-dist', factory) and
vi.mock('pdfjs-dist/build/pdf.worker.min.mjs?url', factory) from
PdfViewer.svelte.spec.ts — the ManualMockedModule registrations that were
racing with vitest-browser-playwright's birpc teardown channel.
PdfViewer.svelte now accepts an optional libLoader prop (typed as
Parameters<typeof createPdfRenderer>[0]) that is passed untracked to
createPdfRenderer(). Tests supply a vi.fn() fake loader directly as a prop;
production code uses the default loader that imports the real pdfjs-dist.
The birpc route handler for pdfjs-dist is never registered, so no teardown
race is possible. Fixes #535.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { onMount, setContext } from 'svelte';
|
||||
import { onMount, setContext, untrack } from 'svelte';
|
||||
import { createPdfRenderer } from '$lib/document/viewer/usePdfRenderer.svelte';
|
||||
import PdfControls from './PdfControls.svelte';
|
||||
import AnnotationLayer from '$lib/document/annotation/AnnotationLayer.svelte';
|
||||
@@ -21,7 +21,8 @@ let {
|
||||
onDeleteAnnotationRequest,
|
||||
documentFileHash,
|
||||
annotationsDimmed = false,
|
||||
flashAnnotationId = null
|
||||
flashAnnotationId = null,
|
||||
libLoader = undefined
|
||||
}: {
|
||||
url: string;
|
||||
documentId?: string;
|
||||
@@ -35,9 +36,10 @@ let {
|
||||
documentFileHash?: string | null;
|
||||
annotationsDimmed?: boolean;
|
||||
flashAnnotationId?: string | null;
|
||||
libLoader?: Parameters<typeof createPdfRenderer>[0];
|
||||
} = $props();
|
||||
|
||||
const renderer = createPdfRenderer();
|
||||
const renderer = untrack(() => createPdfRenderer(libLoader));
|
||||
|
||||
// Canvas and text layer container refs — bound via bind:this
|
||||
let canvasEl = $state<HTMLCanvasElement | null>(null);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { vi, describe, it, expect, afterEach } from 'vitest';
|
||||
import { cleanup, render } from 'vitest-browser-svelte';
|
||||
import { page } from 'vitest/browser';
|
||||
import type { createPdfRenderer } from '$lib/document/viewer/usePdfRenderer.svelte';
|
||||
|
||||
// pdfjs-dist is a rendering dependency — we mock it so unit tests don't need
|
||||
// a real browser PDF engine. The interesting behaviour under test here is the
|
||||
// component's own UI logic (controls, page counter), not pdfjs internals.
|
||||
vi.mock('pdfjs-dist', () => {
|
||||
afterEach(cleanup);
|
||||
|
||||
function makeFakePdfjsLib() {
|
||||
function TextLayerMock() {}
|
||||
TextLayerMock.prototype.render = () => Promise.resolve();
|
||||
TextLayerMock.prototype.cancel = () => {};
|
||||
@@ -23,31 +23,32 @@ vi.mock('pdfjs-dist', () => {
|
||||
})
|
||||
}),
|
||||
TextLayer: TextLayerMock
|
||||
};
|
||||
});
|
||||
} as unknown as typeof import('pdfjs-dist');
|
||||
}
|
||||
|
||||
vi.mock('pdfjs-dist/build/pdf.worker.min.mjs?url', () => ({ default: '' }));
|
||||
function makeFakeLibLoader(): Parameters<typeof createPdfRenderer>[0] {
|
||||
const fakePdfjs = makeFakePdfjsLib();
|
||||
return vi.fn().mockResolvedValue([fakePdfjs, { default: '' }] as const);
|
||||
}
|
||||
|
||||
import PdfViewer from './PdfViewer.svelte';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
describe('PdfViewer', () => {
|
||||
it('shows previous and next page navigation buttons', async () => {
|
||||
render(PdfViewer, { url: '/api/documents/test-id/file' });
|
||||
render(PdfViewer, { url: '/api/documents/test-id/file', libLoader: makeFakeLibLoader() });
|
||||
await expect.element(page.getByRole('button', { name: /zurück/i })).toBeInTheDocument();
|
||||
await expect.element(page.getByRole('button', { name: /weiter/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows zoom controls', async () => {
|
||||
render(PdfViewer, { url: '/api/documents/test-id/file' });
|
||||
render(PdfViewer, { url: '/api/documents/test-id/file', libLoader: makeFakeLibLoader() });
|
||||
await expect.element(page.getByRole('button', { name: /vergrößern/i })).toBeInTheDocument();
|
||||
await expect.element(page.getByRole('button', { name: /verkleinern/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('displays the page counter once the PDF has loaded', async () => {
|
||||
render(PdfViewer, { url: '/api/documents/test-id/file' });
|
||||
// Mock resolves synchronously, so "1 / 2" should appear quickly
|
||||
render(PdfViewer, { url: '/api/documents/test-id/file', libLoader: makeFakeLibLoader() });
|
||||
// Fake loader resolves synchronously, so "1 / 2" should appear quickly
|
||||
await expect.element(page.getByText(/1\s*\/\s*2/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user