d2/d2js/js/test/unit/basic.test.js
2025-02-25 21:30:51 +00:00

223 lines
6.3 KiB
JavaScript

import { expect, test, describe } from "bun:test";
import { D2 } from "../../dist/node-esm/index.js";
describe("D2 Unit Tests", () => {
test("basic compilation works", async () => {
const d2 = new D2();
const result = await d2.compile("x -> y");
expect(result.diagram).toBeDefined();
await d2.worker.terminate();
}, 20000);
test("elk layout works", async () => {
const d2 = new D2();
const result = await d2.compile("x -> y", { layout: "elk" });
expect(result.diagram).toBeDefined();
await d2.worker.terminate();
}, 20000);
test("import works", async () => {
const d2 = new D2();
const fs = {
index: "a: @import",
"import.d2": "x: {shape: circle}",
};
const result = await d2.compile({ fs });
expect(result.diagram).toBeDefined();
await d2.worker.terminate();
}, 20000);
test("relative import works", async () => {
const d2 = new D2();
const fs = {
"folder/index.d2": "a: @../import",
"import.d2": "x: {shape: circle}",
};
const inputPath = "folder/index.d2";
const result = await d2.compile({ fs, inputPath });
expect(result.diagram).toBeDefined();
await d2.worker.terminate();
}, 20000);
test("render works", async () => {
const d2 = new D2();
const result = await d2.compile("x -> y");
const svg = await d2.render(result.diagram);
expect(svg).toContain("<svg");
expect(svg).toContain("</svg>");
await d2.worker.terminate();
}, 20000);
test("d2-config read correctly", async () => {
const d2 = new D2();
const result = await d2.compile(
`
vars: {
d2-config: {
theme-id: 4
dark-theme-id: 200
pad: 10
center: true
sketch: true
layout-engine: elk
}
}
x -> y
`
);
expect(result.renderOptions.sketch).toBe(true);
expect(result.renderOptions.themeID).toBe(4);
expect(result.renderOptions.darkThemeID).toBe(200);
expect(result.renderOptions.center).toBe(true);
expect(result.renderOptions.pad).toBe(10);
await d2.worker.terminate();
}, 20000);
test("render options take priority", async () => {
const d2 = new D2();
const result = await d2.compile(
`
vars: {
d2-config: {
theme-id: 4
dark-theme-id: 200
pad: 10
center: true
sketch: true
layout-engine: elk
}
}
x -> y
`,
{
sketch: false,
themeID: 100,
darkThemeID: 300,
center: false,
pad: 0,
layout: "dagre",
}
);
expect(result.renderOptions.sketch).toBe(false);
expect(result.renderOptions.themeID).toBe(100);
expect(result.renderOptions.darkThemeID).toBe(300);
expect(result.renderOptions.center).toBe(false);
expect(result.renderOptions.pad).toBe(0);
await d2.worker.terminate();
}, 20000);
test("sketch render works", async () => {
const d2 = new D2();
const result = await d2.compile("x -> y", { sketch: true });
const svg = await d2.render(result.diagram, { sketch: true });
expect(svg).toContain("<svg");
expect(svg).toContain("</svg>");
expect(svg).toContain("sketch-overlay");
await d2.worker.terminate();
}, 20000);
test("center render works", async () => {
const d2 = new D2();
const result = await d2.compile("x -> y", { center: true });
const svg = await d2.render(result.diagram, { center: true });
expect(svg).toContain("<svg");
expect(svg).toContain("</svg>");
expect(svg).toContain("xMidYMid meet");
await d2.worker.terminate();
}, 20000);
test("no XML tag works", async () => {
const d2 = new D2();
const result = await d2.compile("x -> y");
const svg = await d2.render(result.diagram, { noXMLTag: true });
expect(svg).not.toContain('<?xml version="1.0"');
await d2.worker.terminate();
}, 20000);
test("force appendix works", async () => {
const d2 = new D2();
const result = await d2.compile("x: {tooltip: x appendix}", { forceAppendix: true });
const svg = await d2.render(result.diagram, { forceAppendix: true });
expect(svg).toContain("<svg");
expect(svg).toContain("</svg>");
expect(svg).toContain('class="appendix"');
await d2.worker.terminate();
}, 20000);
test("animated multi-board works", async () => {
const d2 = new D2();
const source = `
x -> y
layers: {
numbers: {
1 -> 2
}
}
`;
const options = { target: "*", animateInterval: 1000 };
const result = await d2.compile(source, options);
const svg = await d2.render(result.diagram, result.renderOptions);
expect(svg).toContain("<svg");
expect(svg).toContain("</svg>");
await d2.worker.terminate();
}, 20000);
test("latex works", async () => {
const d2 = new D2();
const result = await d2.compile("x: |latex \\frac{f(x+h)-f(x)}{h} |");
const svg = await d2.render(result.diagram);
expect(svg).toContain("<svg");
expect(svg).toContain("</svg>");
await d2.worker.terminate();
}, 20000);
test("handles syntax errors correctly", async () => {
const d2 = new D2();
try {
await d2.compile("invalid -> -> syntax");
throw new Error("Should have thrown syntax error");
} catch (err) {
expect(err).toBeDefined();
expect(err.message).not.toContain("Should have thrown syntax error");
}
await d2.worker.terminate();
}, 20000);
test("handles unanimated multi-board error correctly", async () => {
const d2 = new D2();
const source = `
x -> y
layers: {
numbers: {
1 -> 2
}
}
`;
const result = await d2.compile(source);
try {
await d2.render(result.diagram, { target: "*" });
throw new Error("Should have thrown compile error");
} catch (err) {
expect(err).toBeDefined();
expect(err.message).not.toContain("Should have thrown compile error");
}
await d2.worker.terminate();
}, 20000);
test("handles invalid imports correctly", async () => {
const d2 = new D2();
const fs = {
"folder/index.d2": "a: @../invalid",
"import.d2": "x: {shape: circle}",
};
const inputPath = "folder/index.d2";
try {
await d2.compile({ fs, inputPath });
throw new Error("Should have thrown compile error");
} catch (err) {
expect(err).toBeDefined();
expect(err.message).not.toContain("Should have thrown compile error");
}
await d2.worker.terminate();
}, 20000);
});