75 lines
2.5 KiB
TypeScript
75 lines
2.5 KiB
TypeScript
import { createElement } from "react";
|
|
import { renderToStaticMarkup } from "react-dom/server";
|
|
import { describe, expect, it } from "vitest";
|
|
import { Markdown, parseMarkdown, safeHref } from "./markdown.tsx";
|
|
|
|
const html = (text: string) => renderToStaticMarkup(createElement(Markdown, { text }));
|
|
|
|
describe("Markdown 安全子集", () => {
|
|
it("块级:标题、列表、表格、代码块、引用、分隔线", () => {
|
|
const src = [
|
|
"## 结论",
|
|
"",
|
|
"**当前订阅 2 个**,来源 `inventory.query`:",
|
|
"",
|
|
"| # | 标题 | 年份 |",
|
|
"|---|:---|---:|",
|
|
"| 1 | 沙丘2 | 2024 |",
|
|
"| 2 | 沙丘:预言 | 2024 |",
|
|
"",
|
|
"- 缺 1080p",
|
|
"- 缺 4K",
|
|
"",
|
|
"1. 先搜",
|
|
"2. 再提交",
|
|
"",
|
|
"> 仅供参考",
|
|
"",
|
|
"---",
|
|
"```json",
|
|
'{"a":1}',
|
|
"```",
|
|
].join("\n");
|
|
const blocks = parseMarkdown(src);
|
|
expect(blocks.map((b) => b.type)).toEqual(["heading", "paragraph", "table", "list", "list", "quote", "hr", "code"]);
|
|
const out = html(src);
|
|
expect(out).toContain("<h4");
|
|
expect(out).toContain("<strong");
|
|
expect(out).toContain("<table");
|
|
expect(out).toContain("<td");
|
|
expect(out).toContain("沙丘:预言");
|
|
expect(out).toContain('<ol start="1"');
|
|
expect(out).toContain("<ul");
|
|
expect(out).toContain("<blockquote");
|
|
expect(out).toContain("<pre");
|
|
expect(out).toContain("text-align:right");
|
|
});
|
|
|
|
it("原文里的 HTML 按文字显示;危险链接不生成 <a>", () => {
|
|
const out = html(
|
|
"<script>alert(1)</script> <img src=x onerror=alert(1)> [点我](javascript:alert(1)) [文档](https://example.com/a)",
|
|
);
|
|
expect(out).not.toContain("<script");
|
|
expect(out).not.toContain("<img");
|
|
expect(out).toContain("<script>");
|
|
expect(out).not.toContain('href="javascript');
|
|
expect(out).toContain('href="https://example.com/a"');
|
|
expect(out).toContain('rel="noopener noreferrer nofollow"');
|
|
expect(safeHref("/console/tasks")).toBe("/console/tasks");
|
|
expect(safeHref("//evil.example")).toBeNull();
|
|
expect(safeHref("data:text/html,x")).toBeNull();
|
|
});
|
|
|
|
it("行内:代码里的星号不当强调;单换行保留为换行", () => {
|
|
const out = html("用 `a*b*c` 查询\n第二行 *强调*");
|
|
expect(out).toContain("<code");
|
|
expect(out).toContain("a*b*c");
|
|
expect(out).toContain("<br/>");
|
|
expect(out).toContain("<em>强调</em>");
|
|
});
|
|
|
|
it("空文本不渲染", () => {
|
|
expect(html(" \n\n")).toBe("");
|
|
});
|
|
});
|