When converting documents containing Chinese, Japanese, or Korean characters to PDF via pandoc/xelatex, the output was blank or missing glyphs because no CJK-capable font was installed or configured. Changes: - Dockerfile: Add fonts-noto-cjk and texlive-lang-chinese packages - pandoc.ts: Pass -V CJKmainfont=Noto Sans CJK SC to pandoc when converting to pdf/latex, so xelatex uses a CJK-capable font - pandoc.test.ts: Add 3 tests verifying CJK font argument is present for pdf/latex output and absent for other formats Fixes #547
107 lines
3.6 KiB
TypeScript
107 lines
3.6 KiB
TypeScript
import { beforeEach, expect, test, describe } from "bun:test";
|
|
import { convert } from "../../src/converters/pandoc";
|
|
import type { ExecFileFn } from "../../src/converters/types";
|
|
|
|
describe("convert", () => {
|
|
let mockExecFile: ExecFileFn;
|
|
|
|
beforeEach(() => {
|
|
mockExecFile = (cmd, args, callback) => callback(null, "output-data", "");
|
|
});
|
|
|
|
test("should call pandoc with correct arguments (normal)", async () => {
|
|
let calledArgs: Parameters<ExecFileFn> = ["", [], () => {}];
|
|
mockExecFile = (cmd, args, callback) => {
|
|
calledArgs = [cmd, args, callback];
|
|
callback(null, "output-data", "");
|
|
};
|
|
|
|
const result = await convert(
|
|
"input.md",
|
|
"markdown",
|
|
"html",
|
|
"output.html",
|
|
undefined,
|
|
mockExecFile,
|
|
);
|
|
|
|
expect(calledArgs[0]).toBe("pandoc");
|
|
expect(calledArgs[1]).toEqual([
|
|
"input.md",
|
|
"-f",
|
|
"markdown",
|
|
"-t",
|
|
"html",
|
|
"-o",
|
|
"output.html",
|
|
]);
|
|
expect(result).toBe("Done");
|
|
});
|
|
|
|
test("should add xelatex argument for pdf/latex", async () => {
|
|
let calledArgs: Parameters<ExecFileFn> = ["", [], () => {}];
|
|
mockExecFile = (cmd, args, callback) => {
|
|
calledArgs = [cmd, args, callback];
|
|
callback(null, "output-data", "");
|
|
};
|
|
|
|
await convert("input.md", "markdown", "pdf", "output.pdf", undefined, mockExecFile);
|
|
|
|
expect(calledArgs[1][0]).toBe("--pdf-engine=xelatex");
|
|
expect(calledArgs[1]).toContain("input.md");
|
|
expect(calledArgs[1]).toContain("-f");
|
|
expect(calledArgs[1]).toContain("markdown");
|
|
expect(calledArgs[1]).toContain("-t");
|
|
expect(calledArgs[1]).toContain("pdf");
|
|
expect(calledArgs[1]).toContain("-o");
|
|
expect(calledArgs[1]).toContain("output.pdf");
|
|
});
|
|
|
|
test("should add CJK mainfont argument for pdf output", async () => {
|
|
let calledArgs: Parameters<ExecFileFn> = ["", [], () => {}];
|
|
mockExecFile = (cmd, args, callback) => {
|
|
calledArgs = [cmd, args, callback];
|
|
callback(null, "output-data", "");
|
|
};
|
|
|
|
await convert("input.md", "markdown", "pdf", "output.pdf", undefined, mockExecFile);
|
|
|
|
const cjkFontIndex = calledArgs[1].indexOf("-V");
|
|
expect(cjkFontIndex).toBeGreaterThan(-1);
|
|
expect(calledArgs[1][cjkFontIndex + 1]).toBe("CJKmainfont=Noto Sans CJK SC");
|
|
});
|
|
|
|
test("should add CJK mainfont argument for latex output", async () => {
|
|
let calledArgs: Parameters<ExecFileFn> = ["", [], () => {}];
|
|
mockExecFile = (cmd, args, callback) => {
|
|
calledArgs = [cmd, args, callback];
|
|
callback(null, "output-data", "");
|
|
};
|
|
|
|
await convert("input.md", "markdown", "latex", "output.tex", undefined, mockExecFile);
|
|
|
|
expect(calledArgs[1][0]).toBe("--pdf-engine=xelatex");
|
|
const cjkFontIndex = calledArgs[1].indexOf("-V");
|
|
expect(cjkFontIndex).toBeGreaterThan(-1);
|
|
expect(calledArgs[1][cjkFontIndex + 1]).toBe("CJKmainfont=Noto Sans CJK SC");
|
|
});
|
|
|
|
test("should not add CJK mainfont for non-pdf/latex output", async () => {
|
|
let calledArgs: Parameters<ExecFileFn> = ["", [], () => {}];
|
|
mockExecFile = (cmd, args, callback) => {
|
|
calledArgs = [cmd, args, callback];
|
|
callback(null, "output-data", "");
|
|
};
|
|
|
|
await convert("input.md", "markdown", "html", "output.html", undefined, mockExecFile);
|
|
|
|
expect(calledArgs[1].some((arg) => arg.startsWith("CJKmainfont"))).toBe(false);
|
|
});
|
|
|
|
test("should reject if execFile returns an error", async () => {
|
|
mockExecFile = (cmd, args, callback) => callback(new Error("fail"), "", "");
|
|
await expect(
|
|
convert("input.md", "markdown", "html", "output.html", undefined, mockExecFile),
|
|
).rejects.toMatch(/error: Error: fail/);
|
|
});
|
|
});
|