import test from 'node:test'; import assert from 'node:assert/strict'; import { contentHasMath, ensureMathRenderer, renderInlineMarkdown } from './renderMarkdown'; import { sanitizeMermaidCode } from '../components/doc/blocks/MermaidBlockView'; test('renderInlineMarkdown: renders bold, italic, strikethrough', () => { const input = '**粗体指标** *斜体说明* ~~废弃版本~~'; const html = renderInlineMarkdown(input); assert.ok(html.includes('粗体指标')); assert.ok(html.includes('斜体说明')); assert.ok(html.includes('废弃版本')); }); test('renderInlineMarkdown: escapes raw HTML tags to prevent XSS', () => { const scriptHtml = renderInlineMarkdown(''); assert.ok(!scriptHtml.includes('alert(1)'); assert.ok(!forged.includes(''); assert.ok(!/]/i.test(imgHtml), 'must not emit executable img tag'); assert.ok(imgHtml.includes('<img')); const underlineHtml = renderInlineMarkdown('重要条款'); assert.ok(!underlineHtml.includes('')); assert.ok(underlineHtml.includes('<u>')); }); test('renderInlineMarkdown: blocks javascript: link hrefs', () => { const html = renderInlineMarkdown('[click me](javascript:alert(1))'); assert.ok(!html.includes('javascript:')); assert.ok(html.includes('href="#"')); }); test('renderInlineMarkdown: renders inline code and preserved line breaks', () => { const input = '配置 `MIPI-CSI2` 接口\n第二行内容'; const html = renderInlineMarkdown(input, { preserveNewlines: true }); assert.ok(html.includes('')); }); test('renderInlineMarkdown: renders headings lists and tables for chat replies', () => { const input = `# 标题一 ## 小节 - 项目 A - 项目 B | 参数 | 值 | | --- | --- | | 频率 | 24kHz | --- **结论**:可行。`; const html = renderInlineMarkdown(input, { preserveNewlines: true }); assert.ok(html.includes('结论')); }); test('renderInlineMarkdown loads katex only after a formula is seen', async () => { assert.equal(contentHasMath('报价 12 元'), false); const pending = renderInlineMarkdown('能量 $E=mc^2$'); assert.match(pending, /math-pending/); assert.equal(pending.includes('class="katex"'), false); await ensureMathRenderer(); const html = renderInlineMarkdown('能量 $E=mc^2$'); assert.match(html, /class="katex"/); }); test('sanitizeMermaidCode: auto wraps unquoted labels containing brackets or comparison operators', () => { const rawMermaid = `graph LR LaserSource[NIR近红外与白光LED复用光源] --> FPGA[FPGA双路色彩配准与超低延迟融合引擎] FPGA --> Display[4K医用级超低延迟监视器 (延时 < 35ms)] Display --> CleanNode["已用引号包裹的 (正常节点)"]`; const sanitized = sanitizeMermaidCode(rawMermaid); // 原有含括号未包裹的节点必须被加上双引号 assert.ok(sanitized.includes('Display["4K医用级超低延迟监视器 (延时 < 35ms)"]')); // 已有双引号的节点保持不变 assert.ok(sanitized.includes('CleanNode["已用引号包裹的 (正常节点)"]')); });