test(pdf-renderer): eliminate real pdfjs-dist loading from browser tests — use fake libLoader for all init() calls

Five tests in usePdfRenderer.svelte.test.ts called createPdfRenderer() without
a libLoader, causing init() to dynamically import pdfjs-dist in the browser.
Every dynamic import goes through Playwright's route handler, which calls
resolveManualMock via birpc to check for mocks. If the RPC closes during
teardown while one of these imports is in flight, the birpc race fires —
even though pdfjs-dist was never explicitly vi.mock()-ed.

Replace all bare createPdfRenderer() calls that invoke init() with
createPdfRenderer(makeFakeLibLoader()), identical to the pattern already
used in PdfViewer.svelte.test.ts. No real module loads, no route-handler
calls, no birpc exposure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-12 13:01:50 +02:00
parent 9260866f47
commit 23cbb6be22

View File

@@ -1,6 +1,25 @@
import { describe, it, expect, vi } from 'vitest';
import type { LibLoader } from './usePdfRenderer.svelte';
import { createPdfRenderer } from './usePdfRenderer.svelte';
function makeFakeLibLoader(): LibLoader {
return vi.fn().mockResolvedValue([
{
GlobalWorkerOptions: { workerSrc: '' },
getDocument: vi.fn().mockReturnValue({
promise: Promise.resolve({ numPages: 1, getPage: vi.fn() })
}),
TextLayer: class {
render() {
return Promise.resolve();
}
cancel() {}
}
} as unknown as typeof import('pdfjs-dist'),
{ default: '' }
] as const);
}
// Note: init() and loadDocument() require pdfjsLib (browser module).
// These tests cover pure state logic only — bounds clamping and zoom limits.
@@ -122,39 +141,36 @@ describe('createPdfRenderer', () => {
expect(r.scale).toBe(before);
});
it('init() is callable and resolves without throwing in browser env', async () => {
const r = createPdfRenderer();
it('init() sets pdfjsReady to true when loader resolves', async () => {
const r = createPdfRenderer(makeFakeLibLoader());
await expect(r.init()).resolves.toBeUndefined();
// pdfjsReady is now true
expect(r.pdfjsReady).toBe(true);
});
it('after init, loadDocument with a bogus URL sets error', async () => {
const r = createPdfRenderer();
it('after init, loadDocument completes and loading returns to false', async () => {
const r = createPdfRenderer(makeFakeLibLoader());
await r.init();
await r.loadDocument('about:invalid-pdf');
// Either error is set or loading flips back to false — both are acceptable
await r.loadDocument('/some/path');
expect(r.loading).toBe(false);
});
it('renderCurrentPage is a no-op when canvasEl is null but pdfjsLib is initialized', async () => {
const r = createPdfRenderer();
const r = createPdfRenderer(makeFakeLibLoader());
await r.init();
// Without setElements, canvasEl is null — early return
await expect(r.renderCurrentPage()).resolves.toBeUndefined();
});
it('renderCurrentPage is a no-op when textLayerEl is null', async () => {
const r = createPdfRenderer();
const r = createPdfRenderer(makeFakeLibLoader());
await r.init();
// Set only canvas, leave textLayer unset is not directly testable;
// confirm calling without elements wired returns early.
// Without setElements, textLayerEl is null — early return
await expect(r.renderCurrentPage()).resolves.toBeUndefined();
});
it('init() can be called multiple times safely', async () => {
const r = createPdfRenderer();
const r = createPdfRenderer(makeFakeLibLoader());
await r.init();
await r.init();
expect(r.pdfjsReady).toBe(true);