101 lines
3.5 KiB
JavaScript
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 })
|
|
}
|
|
},
|
|
)
|