Skip to content

fix(mermaid): parse SVG via innerHTML instead of DOMParser xml (#1131) #1134

Merged
perber merged 6 commits into
mainfrom
fix/mermaid-img-node-parse-error
Jun 5, 2026
Merged

fix(mermaid): parse SVG via innerHTML instead of DOMParser xml (#1131) #1134
perber merged 6 commits into
mainfrom
fix/mermaid-img-node-parse-error

Conversation

@perber

@perber perber commented Jun 5, 2026

Copy link
Copy Markdown
Owner

No description provided.

perber added 2 commits June 5, 2026 19:05
Two tests:
- baseline: normal flowchart renders SVG
- regression: flowchart with <img> in node label must show SVG or
  the 'Unable to render' error UI, never raw XML parseerror text

The second test currently FAILS if the DOMParser (image/svg+xml) path
is hit with HTML void elements — documents the bug before the fix.
DOMParser with 'image/svg+xml' is a strict XML parser. When Mermaid
emits SVG containing HTML void elements (e.g. <img> inside
<foreignObject> nodes), the parser fails and returns a <parseerror>
document element. Inserting that element into the DOM renders the raw
XML error text instead of the 'Unable to render' error UI.

Switching to innerHTML parsing (HTML parser) handles void elements
correctly and is safe — Mermaid's own sanitisation has already run
on the SVG string before we receive it.
Copilot AI review requested due to automatic review settings June 5, 2026 17:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the Mermaid preview injection logic in the LeafWiki UI to avoid XML parse errors when Mermaid emits HTML void elements (e.g. <img>) inside <foreignObject>, and adds an end-to-end regression test to ensure raw XML parser errors never leak into the rendered page.

Changes:

  • Switch Mermaid SVG parsing from DOMParser(..., 'image/svg+xml') to HTML parsing via innerHTML + querySelector('svg').
  • Throw a controlled error when Mermaid output doesn’t contain an <svg> element (so the existing error UI is shown instead of raw parse output).
  • Add Playwright e2e coverage for basic Mermaid rendering and for the <img>/<foreignObject> regression scenario.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
ui/leafwiki-ui/src/features/preview/useMermaidInjector.ts Changes how Mermaid’s rendered SVG string is parsed and injected into the preview container to avoid XML parseerror nodes.
e2e/tests/mermaid.spec.ts Adds Playwright coverage for Mermaid rendering, including a regression test for the reported parseerror leak.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ui/leafwiki-ui/src/features/preview/useMermaidInjector.ts Outdated
Comment thread e2e/tests/mermaid.spec.ts Outdated
Comment thread e2e/tests/mermaid.spec.ts Outdated
Comment thread e2e/tests/mermaid.spec.ts Outdated
perber added 4 commits June 5, 2026 20:05
DOMParser with 'image/svg+xml' is a strict XML parser. When Mermaid
emits SVG containing HTML void elements (e.g. <img> inside
<foreignObject> nodes), the parser fails and inserts a raw XML
parseerror element into the DOM — showing confusing error text instead
of the expected 'Unable to render' UI.

Fix: parse the rendered SVG string via innerHTML (HTML parser), which
handles void elements correctly. Also change securityLevel from
'strict' to 'antiscript' so that HTML in node labels (e.g. <img>) is
preserved by Mermaid and rendered via foreignObject, while script tags
and event handlers are still stripped by DOMPurify.

Correct Mermaid syntax for images in nodes:
  A[label <img src='...' />]  (single quotes inside src attribute)

Reported in #1131.
- Use <template> instead of <div> for inert SVG parsing (no side-effect
  fetches from <img src=...> before the node is inserted into the DOM)
- Replace external shields.io URL in e2e test with a data URL to keep
  the test suite hermetic
- Replace fixed waitForTimeout(3000) with expect.poll to avoid flakiness
  under variable CI/local speeds
The single-quote variant only showed the fix works for src='...'. Both
quote styles must be covered since HTML allows both; the template-based
parser handles them equally.

Refactors the two img-node tests into a parameterised loop to avoid
duplicating the poll/assert logic.
- Add assertion that <img> inside the rendered SVG is actually visible,
  covering the core #1131 regression (not just that no error text appears)
- Add article.toBeVisible() pre-check before the poll so a blank page
  produces an actionable failure instead of a 15 s timeout
- Remove redundant article svg visibility check after poll; replaced by
  the more specific article svg img assertion
- Extract getCsrfScript/createPage to e2e/helpers/api.ts — previously
  copy-pasted verbatim in mermaid.spec.ts, wikilinks.spec.ts, editor.spec.ts
- Add avoidEscape: true to the ESLint quotes rule so strings containing
  single quotes can use double quotes instead of escaped single quotes
@perber
perber merged commit 13d2ef7 into main Jun 5, 2026
9 checks passed
@perber
perber deleted the fix/mermaid-img-node-parse-error branch June 5, 2026 19:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants