test(document): behavioral CCITT/DCT render fixtures prove the wasm path
Render committed synthetic fixtures through PdfViewer with the REAL pdf.js loader and assert the canvas is non-blank (sampled dark-pixel count). The CCITT (G4 fax) fixture exercises the shared jbig2.wasm decode path — the same module pdf.js uses for JBIG2 — so it transitively covers the JBIG2 acceptance criterion (the archive sample found zero true JBIG2 docs and jbig2enc is unavailable to synthesize one). The JPEG/DCTDecode fixture guards against regressing the natively-decoded path. Verified the CCITT case goes red when wasmUrl is removed. Fixtures are hermetic, committed assets (~2-5 KB each), generated with ImageMagick — never fetched from staging at test time. CI browser mode. Refs #708 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
import { describe, it, expect, afterEach, vi } from 'vitest';
|
||||
import { cleanup, render } from 'vitest-browser-svelte';
|
||||
import PdfViewer from './PdfViewer.svelte';
|
||||
import ccittUrl from './fixtures/ccitt-g4.pdf?url';
|
||||
import jpegUrl from './fixtures/jpeg-dct.pdf?url';
|
||||
|
||||
// Behavioral, real-render coverage of the wasm decode path. Unlike the rest of
|
||||
// the viewer tests, these use the REAL pdf.js loader (no libLoader prop) so the
|
||||
// page is actually decoded and painted, and the wasm is fetched from
|
||||
// /pdfjs-wasm/ exactly as in production. CI runs this in a real Chromium.
|
||||
// See issue #708.
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
// A blank page is a uniform white canvas. A rendered page has dark glyph pixels.
|
||||
function countNonBackgroundPixels(canvas: HTMLCanvasElement): number {
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx || canvas.width === 0 || canvas.height === 0) return 0;
|
||||
const { data } = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
let count = 0;
|
||||
for (let i = 0; i < data.length; i += 4) {
|
||||
const r = data[i];
|
||||
const g = data[i + 1];
|
||||
const b = data[i + 2];
|
||||
const a = data[i + 3];
|
||||
if (a > 0 && (r < 250 || g < 250 || b < 250)) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
async function expectNonBlankRender(url: string): Promise<void> {
|
||||
render(PdfViewer, { url, documentId: 'fixture' });
|
||||
await vi.waitFor(
|
||||
() => {
|
||||
const canvas = document.querySelector('canvas');
|
||||
expect(canvas).not.toBeNull();
|
||||
expect((canvas as HTMLCanvasElement).width).toBeGreaterThan(0);
|
||||
expect(countNonBackgroundPixels(canvas as HTMLCanvasElement)).toBeGreaterThan(50);
|
||||
},
|
||||
{ timeout: 20000, interval: 250 }
|
||||
);
|
||||
}
|
||||
|
||||
describe('PdfViewer — real codec fixtures (wasm decode path)', () => {
|
||||
it('renders a CCITT (G4 fax) scan as a non-blank page — same jbig2.wasm path JBIG2 uses', async () => {
|
||||
await expectNonBlankRender(ccittUrl);
|
||||
});
|
||||
|
||||
it('renders a DCTDecode (JPEG) PDF as a non-blank page — no regression', async () => {
|
||||
await expectNonBlankRender(jpegUrl);
|
||||
});
|
||||
});
|
||||
BIN
frontend/src/lib/document/viewer/fixtures/ccitt-g4.pdf
Normal file
BIN
frontend/src/lib/document/viewer/fixtures/ccitt-g4.pdf
Normal file
Binary file not shown.
BIN
frontend/src/lib/document/viewer/fixtures/jpeg-dct.pdf
Normal file
BIN
frontend/src/lib/document/viewer/fixtures/jpeg-dct.pdf
Normal file
Binary file not shown.
Reference in New Issue
Block a user