- Pass gfm:true + breaks:true explicitly to marked.parse() so table support is guaranteed even if global setOptions() is bypassed or reset by a future refactor (defense-in-depth) - Add display:block + overflow-x:auto to .chat-text table so wide multi-column tables scroll horizontally instead of being clipped by the parent overflow-x:hidden chat container - Add regression tests for GFM table rendering in markdown.test.ts
86 lines
2.7 KiB
TypeScript
86 lines
2.7 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { toSanitizedMarkdownHtml } from "./markdown.ts";
|
|
|
|
describe("toSanitizedMarkdownHtml", () => {
|
|
it("renders basic markdown", () => {
|
|
const html = toSanitizedMarkdownHtml("Hello **world**");
|
|
expect(html).toContain("<strong>world</strong>");
|
|
});
|
|
|
|
it("strips scripts and unsafe links", () => {
|
|
const html = toSanitizedMarkdownHtml(
|
|
[
|
|
"<script>alert(1)</script>",
|
|
"",
|
|
"[x](javascript:alert(1))",
|
|
"",
|
|
"[ok](https://example.com)",
|
|
].join("\n"),
|
|
);
|
|
expect(html).not.toContain("<script");
|
|
expect(html).not.toContain("javascript:");
|
|
expect(html).toContain("https://example.com");
|
|
});
|
|
|
|
it("renders fenced code blocks", () => {
|
|
const html = toSanitizedMarkdownHtml(["```ts", "console.log(1)", "```"].join("\n"));
|
|
expect(html).toContain("<pre>");
|
|
expect(html).toContain("<code");
|
|
expect(html).toContain("console.log(1)");
|
|
});
|
|
|
|
it("preserves img tags with src and alt from markdown images (#15437)", () => {
|
|
const html = toSanitizedMarkdownHtml("");
|
|
expect(html).toContain("<img");
|
|
expect(html).toContain('src="https://example.com/image.png"');
|
|
expect(html).toContain('alt="Alt text"');
|
|
});
|
|
|
|
it("preserves base64 data URI images (#15437)", () => {
|
|
const html = toSanitizedMarkdownHtml("");
|
|
expect(html).toContain("<img");
|
|
expect(html).toContain("data:image/png;base64,");
|
|
});
|
|
|
|
it("strips javascript image urls", () => {
|
|
const html = toSanitizedMarkdownHtml(")");
|
|
expect(html).toContain("<img");
|
|
expect(html).not.toContain("javascript:");
|
|
expect(html).not.toContain("src=");
|
|
});
|
|
|
|
it("renders GFM markdown tables (#20410)", () => {
|
|
const md = [
|
|
"| Feature | Status |",
|
|
"|---------|--------|",
|
|
"| Tables | ✅ |",
|
|
"| Borders | ✅ |",
|
|
].join("\n");
|
|
const html = toSanitizedMarkdownHtml(md);
|
|
expect(html).toContain("<table");
|
|
expect(html).toContain("<thead");
|
|
expect(html).toContain("<th>");
|
|
expect(html).toContain("Feature");
|
|
expect(html).toContain("Tables");
|
|
expect(html).not.toContain("|---------|");
|
|
});
|
|
|
|
it("renders GFM tables surrounded by text (#20410)", () => {
|
|
const md = [
|
|
"Text before.",
|
|
"",
|
|
"| Col1 | Col2 |",
|
|
"|------|------|",
|
|
"| A | B |",
|
|
"",
|
|
"Text after.",
|
|
].join("\n");
|
|
const html = toSanitizedMarkdownHtml(md);
|
|
expect(html).toContain("<table");
|
|
expect(html).toContain("Col1");
|
|
expect(html).toContain("Col2");
|
|
// Pipes from table delimiters must not appear as raw text
|
|
expect(html).not.toContain("|------|");
|
|
});
|
|
});
|