|
| 1 | +import { describe, expect, it } from 'vitest' |
| 2 | +import { parseMarkdown } from '../src/parse' |
| 3 | +import { renderMarkdown } from '../src/render' |
| 4 | + |
| 5 | +/** |
| 6 | + * A raw-HTML element round-trips when re-parsing the rendered markdown yields |
| 7 | + * the same tree. A blank line inside the element would terminate the HTML |
| 8 | + * block (or the paragraph, for inline HTML) and split the element apart. |
| 9 | + */ |
| 10 | +async function roundTrip(md: string) { |
| 11 | + const t1 = await parseMarkdown(md) |
| 12 | + const rendered = await renderMarkdown(t1) |
| 13 | + const t2 = await parseMarkdown(rendered) |
| 14 | + return { t1, t2, rendered } |
| 15 | +} |
| 16 | + |
| 17 | +describe('raw HTML round-trip (parse → renderMarkdown → parse)', () => { |
| 18 | + const cases: Record<string, string> = { |
| 19 | + 'picture with source and img': '<picture>\n<source srcset="a.avif">\n<img src="a.jpg">\n</picture>', |
| 20 | + 'figure with img and figcaption': '<figure>\n<img src="a.jpg">\n<figcaption>cap</figcaption>\n</figure>', |
| 21 | + 'inline picture inside a paragraph': 'text <picture><source srcset="a.avif"><img src="a.jpg"></picture> tail', |
| 22 | + 'details with summary and p': '<details>\n<summary>sum</summary>\n<p>body</p>\n</details>', |
| 23 | + 'dl with dt and dd': '<dl>\n<dt>term</dt>\n<dd>def</dd>\n</dl>', |
| 24 | + 'select with two options': '<select>\n<option>a</option>\n<option>b</option>\n</select>', |
| 25 | + 'audio with two sources': '<audio controls>\n<source src="a.mp3">\n<source src="a.ogg">\n</audio>', |
| 26 | + 'object with two params': |
| 27 | + '<object data="x.swf">\n<param name="a" value="1">\n<param name="b" value="2">\n</object>', |
| 28 | + 'nested divs': '<div>\n<div>one</div>\n<div>two</div>\n</div>', |
| 29 | + 'single-child video': '<video controls>\n<source src="a.mp4" type="video/mp4">\n</video>', |
| 30 | + 'mixed text and element children': '<div>\nsome text\n<figcaption>cap</figcaption>\n</div>', |
| 31 | + } |
| 32 | + |
| 33 | + for (const [name, md] of Object.entries(cases)) { |
| 34 | + it(name, async () => { |
| 35 | + const { t1, t2, rendered } = await roundTrip(md) |
| 36 | + expect(rendered.trimEnd()).not.toMatch(/\n[ \t]*\n/) |
| 37 | + expect(t2.nodes).toEqual(t1.nodes) |
| 38 | + }) |
| 39 | + } |
| 40 | +}) |
0 commit comments