UNPKG

honkit

Version:

HonKit is building beautiful books using Markdown.

195 lines (194 loc) 8.73 kB
"use strict"; 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 watch_1 = __importDefault(require("../watch")); const tmpdir_1 = require("../../fs/tmpdir"); /** * Normalize path separators to forward slashes for cross-platform comparison */ function normalizePath(filepath) { return filepath.replace(/\\/g, "/"); } describe("watch", () => { // Increase timeout for file system operations (Windows may need more time) jest.setTimeout(30000); let tempDir; let watchers = []; beforeEach(() => { tempDir = (0, tmpdir_1.createTmpDirWithRealPath)("honkit-watch-test-"); }); afterEach(async () => { // Close all watchers await Promise.all(watchers.map((w) => w.close())); watchers = []; // Cleanup temp directory if (tempDir && fs_1.default.existsSync(tempDir)) { fs_1.default.rmSync(tempDir, { recursive: true, force: true }); } }); function createFile(relativePath, content = "# Test") { const filePath = path_1.default.join(tempDir, relativePath); const dir = path_1.default.dirname(filePath); if (!fs_1.default.existsSync(dir)) { fs_1.default.mkdirSync(dir, { recursive: true }); } fs_1.default.writeFileSync(filePath, content); return filePath; } function modifyFile(relativePath, content) { const filePath = path_1.default.join(tempDir, relativePath); fs_1.default.writeFileSync(filePath, content); return filePath; } /** * Wait for watcher to be ready and stable */ async function waitForReady(watcher) { await new Promise((resolve) => { watcher.on("ready", resolve); }); // Give the watcher a moment to stabilize after ready event // Windows needs more time for file system operations await new Promise((resolve) => setTimeout(resolve, 500)); } /** * Wait for a file change to be detected that matches the predicate * Paths are normalized to forward slashes for cross-platform compatibility */ function waitForChange(watcher, predicate, timeoutMs = 20000) { return new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error(`Timeout waiting for file change after ${timeoutMs}ms`)); }, timeoutMs); const handler = (_event, filepath) => { const fullPath = normalizePath(path_1.default.resolve(tempDir, filepath)); if (predicate(fullPath)) { clearTimeout(timeout); watcher.off("all", handler); resolve(fullPath); } }; watcher.on("all", handler); }); } describe("issue #491 - custom output folder handling", () => { it("should detect changes in custom output folder when not specified in options", async () => { createFile("README.md", "# README"); createFile("output/orphan.md", "# Orphan in output folder"); const detectedFiles = []; // Start watching WITHOUT specifying output folder const watcher = (0, watch_1.default)({ watchDir: tempDir, callback: (error, filepath) => { if (error || !filepath) return; detectedFiles.push(normalizePath(filepath)); } }); watchers.push(watcher); await waitForReady(watcher); // Modify file in output folder and wait for detection modifyFile("output/orphan.md", "# Modified"); const detected = await waitForChange(watcher, (f) => f.includes("output/orphan.md")); expect(detected).toContain("output/orphan.md"); }); it("should NOT detect changes in custom output folder when specified in options", async () => { createFile("README.md", "# README"); createFile("output/orphan.md", "# Orphan in output folder"); const detectedFiles = []; // Start watching WITH output folder specified - it should be ignored const watcher = (0, watch_1.default)({ watchDir: tempDir, outputFolder: "output", callback: (error, filepath) => { if (error || !filepath) return; detectedFiles.push(normalizePath(filepath)); } }); watchers.push(watcher); await waitForReady(watcher); // Modify both files - output should be ignored, README should be detected modifyFile("output/orphan.md", "# Modified"); modifyFile("README.md", "# Modified README"); // Wait for README change to be detected (proves watcher is working) await waitForChange(watcher, (f) => f.includes("README.md")); // Verify output folder change was NOT detected const outputChanges = detectedFiles.filter((f) => f.includes("output/")); expect(outputChanges).toHaveLength(0); }); it("should handle absolute output folder paths", async () => { createFile("README.md", "# README"); createFile("docs-output/file.md", "# File"); const detectedFiles = []; const absoluteOutputPath = path_1.default.join(tempDir, "docs-output"); const watcher = (0, watch_1.default)({ watchDir: tempDir, outputFolder: absoluteOutputPath, callback: (error, filepath) => { if (error || !filepath) return; detectedFiles.push(normalizePath(filepath)); } }); watchers.push(watcher); await waitForReady(watcher); // Modify both files modifyFile("docs-output/file.md", "# Modified"); modifyFile("README.md", "# Modified README"); // Wait for README change await waitForChange(watcher, (f) => f.includes("README.md")); // Verify docs-output was NOT detected const outputChanges = detectedFiles.filter((f) => f.includes("docs-output/")); expect(outputChanges).toHaveLength(0); }); }); describe("default _book folder", () => { it("should NOT detect changes in _book folder", async () => { createFile("file1.md", "# File 1"); createFile("file2.md", "# File 2"); createFile("_book/output.md", "# Output"); const detectedFiles = []; const watcher = (0, watch_1.default)({ watchDir: tempDir, callback: (error, filepath) => { if (error || !filepath) return; detectedFiles.push(normalizePath(filepath)); } }); watchers.push(watcher); await waitForReady(watcher); // First modify file1 to ensure watcher is working modifyFile("file1.md", "# Modified File 1"); await waitForChange(watcher, (f) => f.includes("file1.md")); // Now modify _book file (should be ignored) modifyFile("_book/output.md", "# Modified"); // Modify file2 to confirm watcher still works modifyFile("file2.md", "# Modified File 2"); await waitForChange(watcher, (f) => f.includes("file2.md")); // Verify _book was NOT detected const bookChanges = detectedFiles.filter((f) => f.includes("_book")); expect(bookChanges).toHaveLength(0); }); }); describe("source files", () => { it("should detect changes to markdown files in source directory", async () => { createFile("README.md", "# README"); createFile("orphan.md", "# Orphan - not in SUMMARY"); const watcher = (0, watch_1.default)({ watchDir: tempDir, callback: () => { } }); watchers.push(watcher); await waitForReady(watcher); modifyFile("orphan.md", "# Modified orphan"); const detected = await waitForChange(watcher, (f) => f.includes("orphan.md")); expect(detected).toContain("orphan.md"); }); }); });