Files
deerflow-code/frontend-web/src/core/utils/mermaid-sanitize.test.ts
T
董宏凯andCursor f109a95535 feat: 新增报告协作页,并强化 Deep Research 运行诊断与报告兜底
支持浏览器侧素材快照撰写、拒绝报告读时修复、Mermaid PNG 导出与 Word 导出加固。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 11:16:50 +08:00

86 lines
3.0 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import { findMermaidFenceMatches, getMermaidImageFileName, sanitizeMermaidSource } from "./mermaid";
test("inserts a missing arrow before a bare edge label", () => {
const input = "E --> G|价值输出 V_s| H[PPO 损失]";
assert.equal(
sanitizeMermaidSource(input),
"E --> G -->|价值输出 V_s| H[PPO 损失]",
);
});
test("leaves already-valid labeled edges unchanged", () => {
const input = "E -->|价值输出 V_s| H[PPO 损失]\nG -->|状态| I";
assert.equal(sanitizeMermaidSource(input), input);
});
test("fixes a label attached to a shaped node", () => {
const input = "E[Actor 网络]|价值输出 V_s| H[PPO 损失]";
assert.equal(
sanitizeMermaidSource(input),
"E[Actor 网络] -->|价值输出 V_s| H[PPO 损失]",
);
});
test("fixes several bare labels on one line", () => {
const input = "A|x| B|y| C";
assert.equal(sanitizeMermaidSource(input), "A -->|x| B -->|y| C");
});
test("inserts a space after class when the model starts the id list with a comma", () => {
const input = " class,E,F,G,H,I,J,K loss;";
assert.equal(
sanitizeMermaidSource(input),
" class E,F,G,H,I,J,K loss;",
);
});
test("splits zip-assigned class names onto one statement per class", () => {
const input = " class A,B,C,D input,module,module,module;";
assert.equal(
sanitizeMermaidSource(input),
" class A input;\n class B,C,D module;",
);
});
test("leaves a valid class assignment and classDef alone", () => {
const input = [
" classDef input fill:#e3f2fd,stroke:#1565c0;",
" class A,B input;",
].join("\n");
assert.equal(sanitizeMermaidSource(input), input);
});
test("repairs the DAC-PPO architecture diagram class block", () => {
const input = `graph TD
A[智能体观测 o_t] --> B[个体 Encoder]
E --> G -->|价值输出 V_s| H[PPO 损失]
classDef input fill:#e3f2fd,stroke:#1565c0;
classDef module fill:#fff3e0,stroke:#e65100;
classDef loss fill:#e8f5e9,stroke:#2e7d32;
class A,B,C,D input,module,module,module;
class,E,F,G,H,I,J,K loss;`;
const output = sanitizeMermaidSource(input);
assert.match(output, /class A input;/);
assert.match(output, /class B,C,D module;/);
assert.match(output, /class E,F,G,H,I,J,K loss;/);
assert.doesNotMatch(output, /class,/);
assert.doesNotMatch(output, /input,module/);
});
test("turns mermaid source filenames into png downloads", () => {
assert.equal(getMermaidImageFileName("outputs/图2.mmd"), "图2.png");
assert.equal(getMermaidImageFileName("chart.mermaid", "png"), "chart.png");
assert.equal(getMermaidImageFileName("flowchart.png"), "flowchart.png");
});
test("finds mermaid fences for Word image replacement", () => {
const markdown = "前文\n```mermaid\nflowchart TB\nA-->B\n```\n后文\n```mmd\ngraph LR\nC-->D\n```";
const fences = findMermaidFenceMatches(markdown);
assert.equal(fences.length, 2);
assert.equal(fences[0].source, "flowchart TB\nA-->B");
assert.equal(fences[1].source, "graph LR\nC-->D");
});