From bb15572b571e3da66e414e1163707a4c6317c8ed Mon Sep 17 00:00:00 2001 From: Steffen Becker Date: Sat, 15 Aug 2026 23:18:55 +0200 Subject: [PATCH] test: smoke-check the raster-PDF export exportPdf gains a test seam: a window.__edentextPdfSink takes the bytes instead of doc.save(), whose download hangs in headless Chromium. The smoke test clicks the real export menu over the imported corpus document and asserts %PDF magic and a plausible size. The test browser is pinned to en-US so the labels it clicks are deterministic across machines. --- src/lib/export/pdf.ts | 6 +++++- tests/smoke/run.mjs | 18 +++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/lib/export/pdf.ts b/src/lib/export/pdf.ts index bad1401..49a960a 100644 --- a/src/lib/export/pdf.ts +++ b/src/lib/export/pdf.ts @@ -283,7 +283,11 @@ export async function exportPdf(opts: PdfOptions): Promise { } } - doc.save((opts.fileName ?? deriveFilename(opts.json)).replace(/\.(odt|pdf)$/i, '') + '.pdf'); + // Test seam: the smoke test takes the bytes here — capturing the real doc.save() + // download hangs in headless Chromium (docs/headless-testing.md). + const sink = (window as { __edentextPdfSink?: (bytes: ArrayBuffer) => void }).__edentextPdfSink; + if (sink) sink(doc.output('arraybuffer')); + else doc.save((opts.fileName ?? deriveFilename(opts.json)).replace(/\.(odt|pdf)$/i, '') + '.pdf'); } finally { cleanup(); } diff --git a/tests/smoke/run.mjs b/tests/smoke/run.mjs index 76a034d..82314d8 100644 --- a/tests/smoke/run.mjs +++ b/tests/smoke/run.mjs @@ -35,7 +35,8 @@ async function previewServer() { const server = await previewServer(); const browser = await chromium.launch({ executablePath: chromium.executablePath(), args: ['--no-sandbox'] }); -const page = await browser.newPage({ viewport: { width: 1400, height: 1000 } }); +// Fixed locale, so the UI labels the test clicks are deterministic across machines. +const page = await browser.newPage({ viewport: { width: 1400, height: 1000 }, locale: 'en-US' }); const pageErrors = []; page.on('pageerror', (err) => pageErrors.push(String(err))); page.on('dialog', (d) => d.accept()); @@ -71,6 +72,21 @@ try { null, { timeout: 30_000 }); const pages = await page.evaluate(() => document.querySelector('.statusbar')?.textContent ?? ''); check(/\d/.test(pages), 'ODT import renders table + statusbar page count'); + + // Raster-PDF export over the loaded document: the seam in export/pdf.ts hands the + // bytes to the sink instead of doc.save() (the download hangs in headless Chromium). + await page.evaluate(() => { + window.__edentextPdfSink = (buf) => { + window.__pdfHead = String.fromCharCode(...new Uint8Array(buf, 0, 5)); + window.__pdfSize = buf.byteLength; + }; + }); + await page.click('.save-chevron'); + await page.click('button:has-text("Raster PDF")'); + await page.waitForFunction(() => window.__pdfSize > 0, null, { timeout: 60_000 }); + const pdf = await page.evaluate(() => ({ head: window.__pdfHead, size: window.__pdfSize })); + check(pdf.head === '%PDF-' && pdf.size > 20_000, + `PDF export produces a PDF (${Math.round(pdf.size / 1024)} KB)`); } catch (err) { check(false, `smoke run threw: ${err.message ?? err}`); } finally {