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">
|
<script lang="ts">
|
||||||
import { onMount, setContext } from 'svelte';
|
import { onMount, setContext, untrack } from 'svelte';
|
||||||
import { createPdfRenderer } from '$lib/document/viewer/usePdfRenderer.svelte';
|
import { createPdfRenderer } from '$lib/document/viewer/usePdfRenderer.svelte';
|
||||||
import PdfControls from './PdfControls.svelte';
|
import PdfControls from './PdfControls.svelte';
|
||||||
import AnnotationLayer from '$lib/document/annotation/AnnotationLayer.svelte';
|
import AnnotationLayer from '$lib/document/annotation/AnnotationLayer.svelte';
|
||||||
@@ -21,7 +21,8 @@ let {
|
|||||||
onDeleteAnnotationRequest,
|
onDeleteAnnotationRequest,
|
||||||
documentFileHash,
|
documentFileHash,
|
||||||
annotationsDimmed = false,
|
annotationsDimmed = false,
|
||||||
flashAnnotationId = null
|
flashAnnotationId = null,
|
||||||
|
libLoader = undefined
|
||||||
}: {
|
}: {
|
||||||
url: string;
|
url: string;
|
||||||
documentId?: string;
|
documentId?: string;
|
||||||
@@ -35,9 +36,10 @@ let {
|
|||||||
documentFileHash?: string | null;
|
documentFileHash?: string | null;
|
||||||
annotationsDimmed?: boolean;
|
annotationsDimmed?: boolean;
|
||||||
flashAnnotationId?: string | null;
|
flashAnnotationId?: string | null;
|
||||||
|
libLoader?: Parameters<typeof createPdfRenderer>[0];
|
||||||
} = $props();
|
} = $props();
|
||||||
|
|
||||||
const renderer = createPdfRenderer();
|
const renderer = untrack(() => createPdfRenderer(libLoader));
|
||||||
|
|
||||||
// Canvas and text layer container refs — bound via bind:this
|
// Canvas and text layer container refs — bound via bind:this
|
||||||
let canvasEl = $state<HTMLCanvasElement | null>(null);
|
let canvasEl = $state<HTMLCanvasElement | null>(null);
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { vi, describe, it, expect, afterEach } from 'vitest';
|
import { vi, describe, it, expect, afterEach } from 'vitest';
|
||||||
import { cleanup, render } from 'vitest-browser-svelte';
|
import { cleanup, render } from 'vitest-browser-svelte';
|
||||||
import { page } from 'vitest/browser';
|
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
|
afterEach(cleanup);
|
||||||
// a real browser PDF engine. The interesting behaviour under test here is the
|
|
||||||
// component's own UI logic (controls, page counter), not pdfjs internals.
|
function makeFakePdfjsLib() {
|
||||||
vi.mock('pdfjs-dist', () => {
|
|
||||||
function TextLayerMock() {}
|
function TextLayerMock() {}
|
||||||
TextLayerMock.prototype.render = () => Promise.resolve();
|
TextLayerMock.prototype.render = () => Promise.resolve();
|
||||||
TextLayerMock.prototype.cancel = () => {};
|
TextLayerMock.prototype.cancel = () => {};
|
||||||
@@ -23,31 +23,32 @@ vi.mock('pdfjs-dist', () => {
|
|||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
TextLayer: TextLayerMock
|
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';
|
import PdfViewer from './PdfViewer.svelte';
|
||||||
|
|
||||||
afterEach(cleanup);
|
|
||||||
|
|
||||||
describe('PdfViewer', () => {
|
describe('PdfViewer', () => {
|
||||||
it('shows previous and next page navigation buttons', async () => {
|
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: /zurück/i })).toBeInTheDocument();
|
||||||
await expect.element(page.getByRole('button', { name: /weiter/i })).toBeInTheDocument();
|
await expect.element(page.getByRole('button', { name: /weiter/i })).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows zoom controls', async () => {
|
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: /vergrößern/i })).toBeInTheDocument();
|
||||||
await expect.element(page.getByRole('button', { name: /verkleinern/i })).toBeInTheDocument();
|
await expect.element(page.getByRole('button', { name: /verkleinern/i })).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays the page counter once the PDF has loaded', async () => {
|
it('displays the page counter once the PDF has loaded', async () => {
|
||||||
render(PdfViewer, { url: '/api/documents/test-id/file' });
|
render(PdfViewer, { url: '/api/documents/test-id/file', libLoader: makeFakeLibLoader() });
|
||||||
// Mock resolves synchronously, so "1 / 2" should appear quickly
|
// Fake loader resolves synchronously, so "1 / 2" should appear quickly
|
||||||
await expect.element(page.getByText(/1\s*\/\s*2/)).toBeInTheDocument();
|
await expect.element(page.getByText(/1\s*\/\s*2/)).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user