---
name: feedback-fake-dom-escapehtml-harness
description: When writing an ad hoc fake-DOM harness to independently verify frontend/app.js click/navigation flows, document.createElement's stub must implement real textContent->innerHTML entity-escaping, or escapeHtml() silently returns "" and looks like a content bug that isn't real.
metadata:
type: feedback
---
`frontend/app.js`'s `escapeHtml(text)` (line ~20) works by setting a real DOM
element's `.textContent` and reading `.innerHTML` back, relying on the browser
to do entity-escaping as a side effect — it does not use string replace itself.
**Why:** while independently verifying task 773a7a08 (Planner 产出总览 list
click-through to `#/artifacts/:id`), I wrote a throwaway Node `vm` harness to
simulate a real click -> hashchange -> render() -> mountArtifactBrowser ->
showPreview flow (going beyond the repo's own `frontend/test_graph_console_smoke.js`,
which only exercises pure render functions, not the full DOM/fetch mount flow).
My first `document.createElement` stub had a naive `innerHTML` getter/setter
pair that just stored/returned a string, with no `textContent` handling at
all — so every `escapeHtml()` call inside app.js silently returned `""`, and
the simulated artifact preview came back completely blank (type and content
both empty) even though the fetched artifact object was 100% correct. This
looked exactly like the real bug this task was fixing. Only after tracing
`artifact.lineage`/`artifact.content` at every step and finding them intact
right up until the final `escapeHtml()` call did the harness bug become
obvious.
**How to apply:** any time you build a fake DOM to validate `frontend/app.js`
logic beyond what `frontend/test_graph_console_smoke.js`'s `makeFakeDiv()`
already covers, either reuse that file's `makeFakeDiv()` verbatim or give your
own stub a `textContent` setter that HTML-escapes (`&`, `<`, `>`, `"`) into
the same backing store `innerHTML` reads from. If a simulated preview/content
render comes back suspiciously blank while every value up to the last
`escapeHtml()`/DOM-write call traces correctly, suspect the harness's fake DOM
before suspecting app.js.