Files
2026-11-13 11:50:48 +01:00

101 lines
3.5 KiB
JavaScript

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 })
}
},
)