// @vitest-environment jsdom
// markdown.test.js —— Markdown 渲染 + DOMPurify 消毒 + 自定义表格/代码类(FR-CHAT-004)
import { describe, it, expect } from 'vitest';
import { renderMarkdown, NON_MONO_HEADER } from '../../../../ui/src/components/chat/markdown.js';
describe('renderMarkdown(FR-CHAT-004)', () => {
it('LLM 输出 markdown → 消毒 HTML', () => {
const html = renderMarkdown('**加粗** 与 *斜体* 与 `行内代码`');
expect(html).toContain('加粗');
expect(html).toContain('斜体');
expect(html).toContain('行内代码');
});
it('脚本注入被消毒(活 DOM 中无可执行元素/属性/协议)', () => {
const html = renderMarkdown('你好 [x](javascript:alert(3))');
const doc = new DOMParser().parseFromString(html, 'text/html');
expect(doc.querySelectorAll('script').length).toBe(0);
expect(doc.querySelectorAll('img').length).toBe(0);
expect(doc.querySelectorAll('[onerror]').length).toBe(0);
const hrefs = [...doc.querySelectorAll('a')].map((a) => a.getAttribute('href') || '');
expect(hrefs.filter((h) => h.toLowerCase().startsWith('javascript:'))).toEqual([]);
});
it('表格挂 md-table 类(thead th / tbody td)', () => {
const html = renderMarkdown('| A | B |\n|---|---|\n| 1 | 2 |');
expect(html).toContain('
| A | '); expect(html).toContain(''); }); it('代码块挂 code-block 类并转义内容', () => { const html = renderMarkdown('```\nconst x = "
|---|