test(pdf-renderer): eliminate real pdfjs-dist loading from browser tests — use fake libLoader for all init() calls
Some checks failed
CI / Backend Unit Tests (push) Successful in 4m19s
CI / fail2ban Regex (push) Successful in 39s
CI / Compose Bucket Idempotency (push) Failing after 11s
CI / Unit & Component Tests (pull_request) Failing after 2m3s
CI / OCR Service Tests (pull_request) Successful in 16s
CI / Backend Unit Tests (pull_request) Successful in 4m11s
CI / fail2ban Regex (pull_request) Successful in 39s
CI / Compose Bucket Idempotency (pull_request) Failing after 11s
CI / Unit & Component Tests (push) Failing after 1m47s
CI / OCR Service Tests (push) Successful in 17s

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 f938971292
commit f39f16d96c

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);