honkit
Version:
HonKit is building beautiful books using Markdown.
161 lines (155 loc) • 6.15 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const child_process_1 = require("child_process");
const tmpdir_1 = require("../../fs/tmpdir");
/**
* Integration tests for honkit serve rebuild behavior
*
* These tests verify that:
* 1. SUMMARY.md changes trigger full rebuild and generate new pages
* 2. New file additions are detected and processed
*
* This is a black-box test that starts serve, modifies files, and checks output.
*/
jest.setTimeout(60000);
describe("serve integration", () => {
let tempDir;
let outputDir;
let serveProcess = null;
beforeEach(() => {
tempDir = (0, tmpdir_1.createTmpDirWithRealPath)("honkit-serve-test-");
outputDir = path_1.default.join(tempDir, "_book");
});
afterEach(async () => {
// Kill serve process
if (serveProcess && !serveProcess.killed) {
serveProcess.kill("SIGKILL");
await new Promise((resolve) => {
serveProcess?.on("exit", resolve);
setTimeout(resolve, 1000);
});
}
serveProcess = null;
// Cleanup temp directory
if (tempDir && fs_1.default.existsSync(tempDir)) {
fs_1.default.rmSync(tempDir, { recursive: true, force: true });
}
});
function createBookStructure() {
fs_1.default.writeFileSync(path_1.default.join(tempDir, "README.md"), `# Test Book
Welcome to the test book.
`);
fs_1.default.writeFileSync(path_1.default.join(tempDir, "SUMMARY.md"), `# Summary
* [Introduction](README.md)
`);
}
function getOutputFiles() {
if (!fs_1.default.existsSync(outputDir))
return [];
const files = [];
const walk = (dir, prefix = "") => {
const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
if (entry.isDirectory()) {
walk(path_1.default.join(dir, entry.name), relativePath);
}
else {
files.push(relativePath);
}
}
};
walk(outputDir);
return files.sort();
}
function startServe() {
return new Promise((resolve, reject) => {
const binPath = path_1.default.resolve(__dirname, "../../../bin/honkit.js");
// Use port 0 to let OS assign an available port
serveProcess = (0, child_process_1.spawn)(process.execPath, [binPath, "serve", tempDir, outputDir, "--port", "0", "--lrport", "0"], {
stdio: ["pipe", "pipe", "pipe"],
env: { ...process.env }
});
let started = false;
const checkStarted = (output) => {
if (output.includes("Serving book on") && !started) {
started = true;
// Wait a bit for initial build to complete
setTimeout(resolve, 1000);
}
};
serveProcess.stdout?.on("data", (data) => {
checkStarted(data.toString());
});
serveProcess.stderr?.on("data", (data) => {
// HonKit outputs to stderr for info/warn
checkStarted(data.toString());
});
serveProcess.on("error", reject);
// Timeout after 10 seconds
setTimeout(() => {
if (!started) {
reject(new Error("Timeout waiting for serve to start"));
}
}, 10000);
});
}
function waitForFile(filePath, timeoutMs = 15000) {
return new Promise((resolve, reject) => {
const startTime = Date.now();
const check = () => {
if (fs_1.default.existsSync(filePath)) {
resolve();
}
else if (Date.now() - startTime > timeoutMs) {
reject(new Error(`Timeout waiting for file: ${filePath}`));
}
else {
setTimeout(check, 200);
}
};
check();
});
}
describe("file watching and rebuild", () => {
it("should generate new page when SUMMARY.md is updated during serve", async () => {
createBookStructure();
await startServe();
// Verify initial build - only index.html
expect(getOutputFiles()).toContain("index.html");
expect(getOutputFiles()).not.toContain("chapter1.html");
// Add chapter1.md
fs_1.default.writeFileSync(path_1.default.join(tempDir, "chapter1.md"), `# Chapter 1
This is chapter 1.
`);
// Update SUMMARY.md to include chapter1
fs_1.default.writeFileSync(path_1.default.join(tempDir, "SUMMARY.md"), `# Summary
* [Introduction](README.md)
* [Chapter 1](chapter1.md)
`);
// Wait for rebuild
await waitForFile(path_1.default.join(outputDir, "chapter1.html"));
// Verify chapter1.html was generated
expect(getOutputFiles()).toContain("chapter1.html");
});
it("should copy new asset file when added during serve", async () => {
createBookStructure();
await startServe();
// Verify initial state
expect(getOutputFiles()).not.toContain("notes.md");
// Add new asset file (not in SUMMARY.md)
fs_1.default.writeFileSync(path_1.default.join(tempDir, "notes.md"), `# Notes
These are my notes.
`);
// Wait for the asset to be copied
await waitForFile(path_1.default.join(outputDir, "notes.md"));
// Verify asset was copied
expect(getOutputFiles()).toContain("notes.md");
});
});
});