Files
STCourses/packages/feature-studio/test/markdown.test.ts
T

39 lines
2.0 KiB
TypeScript

import { expect, test } from "bun:test";
import { renderMarkdown } from "../src/ui/markdown";
test("headings, paragraphs, emphasis, inline code", () => {
expect(renderMarkdown("# Title\n\nSome **bold** and *em* and `x < y`.\nSecond line.")).toBe(
'<h1 id="title">Title</h1>\n<p>Some <strong>bold</strong> and <em>em</em> and <code>x &lt; y</code>.\nSecond line.</p>',
);
});
test("raw HTML is escaped, except the details/summary hint blocks", () => {
expect(renderMarkdown("<script>alert(1)</script>")).toBe("<p>&lt;script&gt;alert(1)&lt;/script&gt;</p>");
const h = renderMarkdown("<details>\n<summary>Exercise 1 — nudge</summary>\n\nTry **this**.\n\n</details>");
expect(h).toMatch(/<details>\s*<summary>Exercise 1 — nudge<\/summary>/);
expect(h).toContain("<p>Try <strong>this</strong>.</p>");
expect(h).toContain("</details>");
expect(renderMarkdown("<summary onclick=x>a</summary>")).not.toContain("<summary onclick");
});
test("fenced code keeps content verbatim and escaped", () => {
expect(renderMarkdown("```js\nconst a = '<b>';\n# not a heading\n```")).toBe(
'<pre class="code"><code data-lang="js">const a = \'&lt;b&gt;\';\n# not a heading</code></pre>',
);
});
test("lists, quotes, rules", () => {
expect(renderMarkdown("- a\n- b\n\n1. one\n2. two")).toBe("<ul><li>a</li><li>b</li></ul>\n<ol><li>one</li><li>two</li></ol>");
expect(renderMarkdown("> quoted\n\n---")).toBe("<blockquote><p>quoted</p></blockquote>\n<hr>");
});
test("links: safe schemes only; images resolved through the given resolver", () => {
expect(renderMarkdown("[ok](https://x.org/a?b=1&c=2)")).toBe('<p><a href="https://x.org/a?b=1&amp;c=2">ok</a></p>');
expect(renderMarkdown("[bad](javascript:alert(1))")).toBe("<p>bad</p>");
expect(renderMarkdown("![d](img/a b.png)", { resolveUrl: (u) => `/raw/${encodeURIComponent(u)}` })).toBe('<p><img src="/raw/img%2Fa%20b.png" alt="d"></p>');
});
test("front matter is not rendered", () => {
expect(renderMarkdown("---\ntitle: x\n---\n# H")).toBe('<h1 id="h">H</h1>');
});