File size: 3,414 Bytes
7b56bb5 97bf9da 7b56bb5 97bf9da 7b56bb5 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
import { describe, expect, test } from "vitest";
import { processTokensSync } from "./marked";
function renderHtml(md: string): string {
const tokens = processTokensSync(md, []);
const textToken = tokens.find((token) => token.type === "text");
if (!textToken || textToken.type !== "text") return "";
return typeof textToken.html === "string" ? textToken.html : "";
}
describe("marked basic rendering", () => {
test("renders bold text", () => {
const html = renderHtml("**bold**");
expect(html).toContain("<strong>bold</strong>");
});
test("renders links", () => {
const html = renderHtml("[link](https://example.com)");
expect(html).toContain('<a href="https://example.com"');
expect(html).toContain("link</a>");
});
test("renders paragraphs", () => {
const html = renderHtml("hello world");
expect(html).toContain("<p>hello world</p>");
});
});
describe("marked image renderer", () => {
test("renders video extensions as <video>", () => {
const html = renderHtml("");
expect(html).toContain("<video controls");
expect(html).toContain('<source src="https://example.com/clip.mp4">');
});
test("renders audio extensions as <audio>", () => {
const html = renderHtml("");
expect(html).toContain("<audio controls");
expect(html).toContain('<source src="https://example.com/clip.mp3">');
});
test("renders non-video images as <img>", () => {
const html = renderHtml("");
expect(html).toContain('<img src="https://example.com/pic.png"');
});
test("renders video with query params", () => {
const html = renderHtml("");
expect(html).toContain("<video controls");
expect(html).toContain("clip.mp4?token=abc");
});
});
describe("marked html video tag support", () => {
test("allows raw <video> tags with controls", () => {
const html = renderHtml('<video controls src="https://example.com/video.mp4"></video>');
expect(html).toContain("<video");
expect(html).toContain("controls");
expect(html).toContain('src="https://example.com/video.mp4"');
});
test("allows <video> with nested <source> tags", () => {
const html = renderHtml(
'<video controls><source src="https://example.com/video.webm" type="video/webm"></video>'
);
expect(html).toContain("<video");
expect(html).toContain("<source");
expect(html).toContain('src="https://example.com/video.webm"');
});
test("strips disallowed attributes from video tags", () => {
const html = renderHtml('<video onclick="alert(1)" src="https://example.com/v.mp4"></video>');
expect(html).toContain("<video");
expect(html).not.toContain("onclick");
});
test("strips javascript: URLs from media sources", () => {
const html = renderHtml('<video controls src="javascript:alert(1)"></video>');
expect(html).not.toContain("javascript:");
});
test("escapes disallowed html tags", () => {
const html = renderHtml("<script>alert(1)</script>");
expect(html).not.toContain("<script>");
expect(html).toContain("<script>");
});
test("allows <audio> tags with controls", () => {
const html = renderHtml(
'<audio controls><source src="https://example.com/audio.mp3" type="audio/mpeg"></audio>'
);
expect(html).toContain("<audio");
expect(html).toContain("<source");
expect(html).toContain('type="audio/mpeg"');
});
});
|