134 lines
5.6 KiB
JavaScript
134 lines
5.6 KiB
JavaScript
// Standalone test for the native -> print HTML renderer (print-format.ts).
|
|
// This is the path the PDF export uses (#printBook innerHTML). It bundles the
|
|
// renderer module and verifies that chapter breaks become print sections and
|
|
// that every rich-text feature survives the native -> HTML conversion.
|
|
// Run with: node tests/run-print-test.mjs
|
|
import fs from "fs";
|
|
import { bundleForTest } from "./helpers/bundle.mjs";
|
|
|
|
const { mod, cleanupBundle } = await bundleForTest({
|
|
name: "folio-print",
|
|
entryPoints: ["src/renderer/print-format.ts"],
|
|
external: ["electron"],
|
|
});
|
|
const renderPrintChaptersNative = mod.renderPrintChaptersNative;
|
|
|
|
let failures = 0;
|
|
const check = (name, ok) => {
|
|
console.log(`${ok ? "PASS" : "FAIL"} ${name}`);
|
|
if (!ok) failures += 1;
|
|
};
|
|
|
|
// --- native document with chapter breaks + every formatting feature ---------
|
|
const text = (t, marks = []) => ({ type: "text", text: t, marks });
|
|
const para = (content, attrs = {}) => ({ type: "paragraph", attrs, content });
|
|
const heading = (level, t) => ({ type: "heading", attrs: { level }, content: [text(t)] });
|
|
const listItem = (content) => ({ type: "listItem", content });
|
|
|
|
const doc = {
|
|
type: "doc",
|
|
content: [
|
|
{ type: "chapterBreak", attrs: { chapterId: "c1", title: "One", first: true } },
|
|
heading(1, "One"),
|
|
para([
|
|
text("bold", [{ type: "bold" }]),
|
|
text(" "),
|
|
text("italic", [{ type: "italic" }]),
|
|
text(" "),
|
|
text("underline", [{ type: "underline" }]),
|
|
text(" "),
|
|
text("hl", [{ type: "highlight" }]),
|
|
text(" "),
|
|
text("red", [{ type: "textColor", attrs: { color: "#e11d48" } }]),
|
|
text(" "),
|
|
text("mk", [{ type: "highlight", attrs: { color: "#fde047" } }]),
|
|
]),
|
|
para([text("center")], { textAlign: "center" }),
|
|
{ type: "bulletList", content: [listItem([para([text("bullet one")])])] },
|
|
{
|
|
type: "orderedList",
|
|
content: [
|
|
listItem([para([text("numbered one")])]),
|
|
listItem([para([text("numbered two")])]),
|
|
],
|
|
},
|
|
{
|
|
type: "taskList",
|
|
content: [
|
|
{ type: "taskItem", attrs: { checked: true }, content: [para([text("done task")])] },
|
|
{ type: "taskItem", attrs: { checked: false }, content: [para([text("todo task")])] },
|
|
],
|
|
},
|
|
{
|
|
type: "blockquote",
|
|
attrs: { callout: "note" },
|
|
content: [
|
|
para([text("Callout title")], { class: "callout-title" }),
|
|
para([text("callout body")]),
|
|
],
|
|
},
|
|
{ type: "codeBlock", attrs: { language: "js" }, content: [text("const answer = 42;")] },
|
|
{ type: "horizontalRule" },
|
|
{
|
|
type: "table",
|
|
content: [
|
|
{
|
|
type: "tableRow",
|
|
content: [
|
|
{ type: "tableHeader", content: [para([text("Head A")])] },
|
|
{ type: "tableHeader", content: [para([text("Head B")])] },
|
|
],
|
|
},
|
|
{
|
|
type: "tableRow",
|
|
content: [
|
|
{ type: "tableCell", content: [para([text("cell 1")])] },
|
|
{ type: "tableCell", content: [para([text("cell 2")])] },
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{ type: "image", attrs: { src: "assets/pic.png", alt: "a picture" } },
|
|
para([text("Site", [{ type: "link", attrs: { href: "https://example.com" } }])]),
|
|
para([text("Go", [{ type: "link", attrs: { href: "folio:chapter/Two" } }])]),
|
|
{ type: "chapterBreak", attrs: { chapterId: "c2", title: "Two", first: false } },
|
|
heading(1, "Two"),
|
|
para([text("second chapter body")]),
|
|
],
|
|
};
|
|
|
|
const html = renderPrintChaptersNative(doc);
|
|
|
|
check("has two print-chapter sections", (html.match(/<section class="print-chapter">/g) || []).length === 2);
|
|
const iOne = html.indexOf("One");
|
|
const iTwo = html.indexOf("Two");
|
|
check("chapters appear in order", iOne >= 0 && iOne < iTwo);
|
|
check("first section contains chapter one", html.indexOf("<section") < iOne && html.indexOf("second chapter body") > iOne);
|
|
|
|
check("renders h1", /<h1>One<\/h1>/.test(html));
|
|
check("renders bold", /<strong>bold<\/strong>/.test(html));
|
|
check("renders italic", /<em>italic<\/em>/.test(html));
|
|
check("renders underline", /<u>underline<\/u>/.test(html));
|
|
check("renders highlight as mark", /<mark>hl<\/mark>/.test(html));
|
|
check("renders text color span", /<span style="color:#e11d48">red<\/span>/.test(html));
|
|
check("renders highlight color span", /<span style="background-color:#fde047">mk<\/span>/.test(html));
|
|
check("renders centered paragraph", /<p style="text-align:center">center<\/p>/.test(html));
|
|
check("renders bullet list", /<ul>[\s\S]*bullet one[\s\S]*<\/ul>/.test(html));
|
|
check("renders ordered list", /<ol>[\s\S]*numbered one[\s\S]*numbered two[\s\S]*<\/ol>/.test(html));
|
|
check("renders task list with checkboxes", html.includes("☒") && html.includes("done task") && html.includes("☐") && html.includes("todo task"));
|
|
check("renders callout", /<div class="callout callout-note">.*<p class="callout-title">Callout title<\/p>/s.test(html));
|
|
check("renders code block", /<pre><code>const answer = 42;<\/code><\/pre>/.test(html));
|
|
check("renders horizontal rule", /<hr>/.test(html));
|
|
check("renders table with header + cells", /<table class="folio-table">.*<th>Head A<\/th>.*<td>cell 1<\/td>.*<\/table>/s.test(html));
|
|
check("renders image", /<img src="assets\/pic.png" alt="a picture">/.test(html));
|
|
check("renders external link", /<a href="https:\/\/example.com">Site<\/a>/.test(html));
|
|
check("renders wikilink as internal anchor", /<a href="folio:chapter\/Two" class="wikilink internal">Go<\/a>/.test(html));
|
|
check("no raw wikilink brackets", !html.includes("[[Two"));
|
|
|
|
cleanupBundle();
|
|
|
|
if (failures > 0) {
|
|
console.error(`\n${failures} check(s) failed.`);
|
|
process.exit(1);
|
|
}
|
|
console.log("\nAll print-format checks passed.");
|