| 1 | import { renderToStaticMarkup } from "react-dom/server"; |
| 2 | import ReactMarkdown from "react-markdown"; |
| 3 | import remarkGfm from "remark-gfm"; |
| 4 | import { describe, expect, it } from "vite-plus/test"; |
| 5 | |
| 6 | import { remarkNormalizeListItemIndentation } from "@t3tools/shared/markdownListIndentation"; |
| 7 | |
| 8 | function renderMarkdown(markdown: string): string { |
| 9 | return renderToStaticMarkup( |
| 10 | <ReactMarkdown remarkPlugins={[remarkGfm, remarkNormalizeListItemIndentation]}> |
| 11 | {markdown} |
| 12 | </ReactMarkdown>, |
| 13 | ); |
| 14 | } |
| 15 | |
| 16 | describe("remarkNormalizeListItemIndentation", () => { |
| 17 | it("renders same-line over-indented list content as list text", () => { |
| 18 | const html = renderMarkdown(`why did you do this? |
| 19 | |
| 20 | - for (const step of rest.steps) { |
| 21 | - if (step.request.body) { |
| 22 | - step.request.body = "<redacted>"; |
| 23 | - } |
| 24 | - }`); |
| 25 | |
| 26 | expect(html).not.toContain("<pre>"); |
| 27 | expect(html).toContain("<li>for (const step of rest.steps) {</li>"); |
| 28 | expect(html).toContain("<li>if (step.request.body) {</li>"); |
| 29 | expect(html).toContain("<li>step.request.body = &quot;&lt;redacted&gt;&quot;;</li>"); |
| 30 | }); |
| 31 | |
| 32 | it("parses inline markdown in recovered list content", () => { |
| 33 | const html = renderMarkdown( |
| 34 | "- **important** [docs](https://example.com) use `inline code`, not ~~plain text~~", |
| 35 | ); |
| 36 | |
| 37 | expect(html).toContain("<strong>important</strong>"); |
| 38 | expect(html).toContain('<a href="https://example.com">docs</a>'); |
| 39 | expect(html).toContain("<code>inline code</code>"); |
| 40 | expect(html).toContain("<del>plain text</del>"); |
| 41 | expect(html).not.toContain("**important**"); |
| 42 | }); |
| 43 | |
| 44 | it("preserves every recovered block separated by blank lines", () => { |
| 45 | const html = renderMarkdown(`- **first block** |
| 46 | |
| 47 | [second block](https://example.com)`); |
| 48 | |
| 49 | expect(html).toContain("<strong>first block</strong>"); |
| 50 | expect(html).toContain('<a href="https://example.com">second block</a>'); |
| 51 | }); |
| 52 | |
| 53 | it("recursively normalizes lists in recovered tail blocks", () => { |
| 54 | const html = renderMarkdown(`- first block |
| 55 | |
| 56 | - nested block`); |
| 57 | |
| 58 | expect(html).not.toContain("<pre>"); |
| 59 | expect(html).toContain("<li>nested block</li>"); |
| 60 | }); |
| 61 | |
| 62 | it("preserves fenced code blocks within list items", () => { |
| 63 | const html = renderMarkdown(`- \`\`\`ts |
| 64 | const value = 1; |
| 65 | \`\`\``); |
| 66 | |
| 67 | expect(html).toContain('<pre><code class="language-ts">const value = 1;'); |
| 68 | }); |
| 69 | |
| 70 | it("preserves indented code blocks that start below a list marker", () => { |
| 71 | const html = renderMarkdown(`- |
| 72 | const value = 1;`); |
| 73 | |
| 74 | expect(html).toContain("<pre><code>const value = 1;"); |
| 75 | }); |
| 76 | |
| 77 | it("preserves same-line code blocks without excess indentation", () => { |
| 78 | const html = renderMarkdown("- const value = 1;"); |
| 79 | |
| 80 | expect(html).toContain("<pre><code>const value = 1;"); |
| 81 | }); |
| 82 | }); |