Files
upup/tests/markdown.test.ts
chuan 712be0fff8 feat: 支持 Agent 网页可视化和自适应预览
- 引导 Agent 主动使用网页与图表呈现适合可视化的内容
- 支持隔离网页预览、源码查看、放大及收起展开,高度随内容自动调整
- 兼容直接输出的 HTML,识别截断内容并提示重新生成
- 移除 DeepSeek 预设的固定输出限制,迁移旧默认配置并沿用服务端默认值
- 补充网页渲染和输出参数测试,更新使用文档
2026-10-24 22:52:11 +08:00

74 lines
3.8 KiB
TypeScript

import { expect, test } from "bun:test";
import { createElement } from "react";
import { renderToStaticMarkup } from "react-dom/server";
import { Markdown } from "../src/client/components/markdown";
const render = (text: string) => renderToStaticMarkup(createElement(Markdown, { children: text }));
test("assistant Markdown renders headings, bold, lists, tables and links", () => {
const html = render("## 账号\n\n**已登录**\n\n- 第一项\n- 第二项\n\n| 名称 | 状态 |\n| --- | --- |\n| 账号 | 正常 |\n\n[官网](https://example.com)");
expect(html).toContain("<h2>账号</h2>");
expect(html).toContain("<strong>已登录</strong>");
expect(html).toContain("<ul>");
expect(html).toContain("<table>");
expect(html).toContain('href="https://example.com"');
expect(html).toContain('rel="noreferrer noopener"');
});
test("spaced bold markers render without changing code or link destinations", () => {
const html = render("** 账号**\n\n`** 代码**`\n\n```text\n** 原样保留**\n```\n\n[链接](https://example.com/path_**_test)");
expect(html).toContain("<strong>账号</strong>");
expect(html).toContain("<code>** 代码**</code>");
expect(html).toContain("** 原样保留**");
expect(html).toContain('href="https://example.com/path_**_test"');
});
test("model HTML and script URLs cannot become active markup", () => {
const html = render('<script>alert(1)</script>\n\n[链接](javascript:alert%281%29)');
expect(html).not.toContain("<script>");
expect(html).not.toContain('href="javascript:');
});
test("Markdown images open a preview instead of navigating to the image URL", () => {
const html = render("![头像](https://example.com/avatar.jpg)");
expect(html).toContain('<img src="https://example.com/avatar.jpg"');
expect(html).toContain('alt="头像"');
expect(html).toContain('aria-label="放大查看头像"');
expect(html).toContain('aria-haspopup="dialog"');
expect(html).not.toContain('href="https://example.com/avatar.jpg"');
expect(html).toContain('referrerPolicy="no-referrer"');
});
test("HTML fences render in a sandboxed preview while ordinary code stays code", () => {
const html = render('```html\n<h1>运营概览</h1><script>document.body.dataset.ready="yes"</script>\n```');
expect(html).toContain('title="网页预览"');
expect(html).toContain('sandbox="allow-scripts"');
expect(html).not.toContain('allow-same-origin');
expect(html).not.toContain('<script>');
expect(html).toContain('Content-Security-Policy');
expect(html).toContain("connect-src &#x27;none&#x27;");
expect(render('```js\nconsole.log(1)\n```')).toContain('<pre><code class="language-js">');
});
test("streaming HTML waits until the response finishes before running a preview", () => {
const html = renderToStaticMarkup(createElement(Markdown, { children: '```html\n<h1>未完成', streaming: true }));
expect(html).toContain("正在生成网页…");
expect(html).not.toContain('<iframe');
});
test("bare HTML documents and unlabelled HTML fences also become isolated previews", () => {
const document = '<!DOCTYPE html><html><body><h1>数据概览</h1></body></html>';
expect(render(document)).toContain('title="网页预览"');
expect(render('```\n' + document + '\n```')).toContain('title="网页预览"');
});
test("truncated webpages show a recovery hint instead of executing a broken script", () => {
const html = render('<!DOCTYPE html><html><body><script>const values = [');
expect(html).toContain('网页内容未生成完整');
expect(html).not.toContain('<iframe');
expect(html).not.toContain('const values');
const capped = renderToStaticMarkup(createElement(Markdown, { children: '```html\n<div>部分内容</div>\n```', truncated: true }));
expect(capped).not.toContain('<iframe');
expect(capped).toContain('网页内容未生成完整');
});