import assert from 'node:assert/strict' import { existsSync } from 'node:fs' import { mkdtemp, readFile, rm } from 'node:fs/promises' import os from 'node:os' import path from 'node:path' import test from 'node:test' import { getDocument } from 'pdfjs-dist/legacy/build/pdf.mjs' import { exportWikiToPdf } from '../src/exporter.js' import { closeBrowser } from '../src/pdf-renderer.js' import { startMockWiki } from './mock-wiki.js' // The renderer keeps a Chromium instance alive between exports. Close it so // the test process can exit after the suite finishes. test.after(async () => { await closeBrowser() }) const chromiumPath = [ process.env.CHROMIUM_PATH, '/usr/bin/chromium', '/usr/bin/chromium-browser', '/opt/google/chrome/chrome', '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', ] .filter(Boolean) .find((candidate) => existsSync(candidate)) test( 'exports a subtree to a PDF with working internal and external links', { skip: chromiumPath ? false : 'No Chromium executable found for the smoke test.', timeout: 180_000 }, async () => { const wiki = await startMockWiki() const tempDir = await mkdtemp(path.join(os.tmpdir(), 'wiki-print-test-')) try { const result = await exportWikiToPdf({ baseUrl: wiki.url, apiKey: 'test-key', startPage: 'docs', maxPages: 50, outputPath: path.join(tempDir, 'export.pdf'), }) assert.equal(result.pageCount, 5) assert.equal(result.locale, 'en') assert.equal(wiki.state.assetHits, 1, 'the page image should be fetched once for embedding') const pdfData = new Uint8Array(await readFile(result.pdfPath)) const pdf = await getDocument({ data: pdfData, disableFontFace: true, useSystemFonts: true, }).promise try { let text = '' const annotations = [] for (let pageNumber = 1; pageNumber <= pdf.numPages; pageNumber += 1) { const page = await pdf.getPage(pageNumber) const content = await page.getTextContent() text += `\n${content.items.map((item) => item.str).join(' ')}` annotations.push(...(await page.getAnnotations())) } assert.ok(pdf.numPages >= 3, `expected several PDF pages, got ${pdf.numPages}`) assert.match(text, /DOCS_MARKER/) assert.match(text, /INSTALL_MARKER/) assert.match(text, /LINUX_MARKER/) assert.match(text, /OTHER_MARKER/) assert.match(text, /FALLBACK_MARKER/) assert.doesNotMatch(text, /DRAFT_MARKER/) assert.doesNotMatch(text, /EXCLUDED_SIBLING_MARKER/) assert.doesNotMatch(text, /GUIDE_OUTSIDE_MARKER/) assert.doesNotMatch(text, /window\.evil/) const links = annotations.filter((annotation) => annotation.subtype === 'Link') assert.ok(links.length > 0, 'expected link annotations in the PDF') assert.ok( links.some((link) => /example\.com/.test(link.url || link.unsafeUrl || '')), 'expected the external link to remain a URL annotation', ) assert.ok( links.some( (link) => link.dest || /^#/.test(link.url || '') || /^#/.test(link.unsafeUrl || '') || link.action === 'GoTo', ), 'expected internal wiki links to stay internal PDF links', ) } finally { await pdf.destroy() } } finally { await wiki.close() await rm(tempDir, { recursive: true, force: true }) } }, )