import assert from 'node:assert/strict'
import test from 'node:test'
import * as cheerio from 'cheerio'
import { buildExportHtml } from '../src/html-builder.js'
import { normalizeBaseUrl } from '../src/utils.js'
const baseUrl = normalizeBaseUrl('https://wiki.example.com')
const pages = [
{
path: 'docs',
locale: 'en',
title: 'Docs',
depth: 0,
updatedAt: '2026-01-01T00:00:00.000Z',
render: `
Docs
Local
Child heading
Child
Outside subtree
German docs
External
Anchor target
`,
},
{
path: 'docs/child',
locale: 'en',
title: 'Child',
depth: 1,
updatedAt: '2026-01-01T00:00:00.000Z',
render: `
Sub heading
Auto heading
Back
Docs
Grand
Clickable
`,
},
{
path: 'docs/child/grand',
locale: 'en',
title: 'Grand',
depth: 2,
updatedAt: '2026-01-01T00:00:00.000Z',
render: `Grand child heading
`,
},
]
async function build(overrides = {}) {
return buildExportHtml({
pages,
baseUrl,
locale: 'en',
startPath: 'docs',
startPage: { title: 'Docs' },
localization: { namespacing: true, namespaces: ['en'] },
includeToc: true,
inlineImages: false,
apiKey: 'test-key',
...overrides,
})
}
test('rewrites internal links to PDF anchors and keeps external links online', async () => {
const html = await build()
const $ = cheerio.load(html)
assert.equal($('.wiki-content a[href="#wp1-sub-heading"]').length, 1)
assert.equal($('.wiki-content a[href="#wiki-page-1"]').length, 1)
assert.equal($('.wiki-content a[href="#wp2-child-heading"]').length, 1)
assert.equal($('.wiki-content a[href="#wp0-local"]').length, 1)
assert.ok(
$('.wiki-content a[data-wiki-path="docs"]')
.toArray()
.map((element) => $(element).attr('href'))
.includes('#wiki-page-0'),
)
assert.equal($('a[href="https://wiki.example.com/en/docs-other"]').length, 1)
assert.equal($('a[href="https://wiki.example.com/de/docs"]').length, 1)
assert.equal($('a[href="https://example.com/page"]').length, 1)
assert.equal($('#wp1-sub-heading').length, 1)
assert.equal($('#wp1-auto-heading').length, 1)
assert.equal($('a[name="wp1-old-anchor"]').length, 1)
assert.equal($('[aria-labelledby="wp1-sub-heading other-id"]').length, 1)
const childHrefs = $('.wiki-content a[data-wiki-path="docs/child"]')
.toArray()
.map((element) => $(element).attr('href'))
assert.ok(childHrefs.includes('#wp1-sub-heading'))
assert.ok(childHrefs.includes('#wiki-page-1'))
assert.equal(
$('.wiki-content a[data-wiki-path="docs/child/grand"]').attr('href'),
'#wp2-child-heading',
)
assert.ok(
$('.wiki-content a[data-wiki-path="docs"]')
.toArray()
.map((element) => $(element).attr('href'))
.includes('#wiki-page-0'),
)
})
test('sanitizes scripts, event handlers, forms and iframes', async () => {
const html = await build()
const $ = cheerio.load(html)
assert.equal($('script').length, 0)
assert.equal($('[onclick]').length, 0)
assert.equal($('form').length, 0)
assert.equal($('input').length, 0)
assert.equal($('iframe').length, 0)
assert.equal($('.pdf-embed a[href="https://wiki.example.com/embedded"]').length, 1)
assert.match($('.wiki-content').text(), /Form content/)
})
test('resolves images even when embedding is disabled', async () => {
const html = await build()
const $ = cheerio.load(html)
const image = $('img[alt="Picture"]')
assert.equal(image.attr('src'), 'https://wiki.example.com/assets/pic.png')
assert.equal(image.attr('srcset'), undefined)
assert.equal(image.attr('loading'), undefined)
})
test('supports wikis without URL locale namespacing', async () => {
const withoutNamespacing = pages.map((page) => ({
...page,
render: page.render.replaceAll('/en/', '/'),
}))
const html = await build({
pages: withoutNamespacing,
localization: { namespacing: false, namespaces: [] },
})
const $ = cheerio.load(html)
const childHrefs = $('.wiki-content a[data-wiki-path="docs/child"]')
.toArray()
.map((element) => $(element).attr('href'))
assert.ok(childHrefs.includes('#wp1-sub-heading'))
assert.ok(childHrefs.includes('#wiki-page-1'))
assert.equal(
$('.wiki-content a[data-wiki-path="docs/child/grand"]').attr('href'),
'#wp2-child-heading',
)
assert.ok(
$('.wiki-content a[data-wiki-path="docs"]')
.toArray()
.map((element) => $(element).attr('href'))
.includes('#wiki-page-0'),
)
})
test('includes only the exported pages in the table of contents', async () => {
const html = await build()
const $ = cheerio.load(html)
const tocHrefs = $('.toc-entry a').toArray().map((element) => $(element).attr('href'))
assert.deepEqual(tocHrefs, ['#wiki-page-0', '#wiki-page-1', '#wiki-page-2'])
assert.equal($('.wiki-page').length, 3)
})