//go:build js && wasm package wasmruntime import ( "strings" "testing" "kjol/vdom" ) // The reconciler is wasm-only and needs a DOM, so these do not run under a plain // `go test ./...` (the native build of this package is an empty placeholder). // Run them against the minimal DOM in testdata/domexec.js — from kjol/go: // // GOOS=js GOARCH=wasm go test -exec="node testdata/domexec.js" ./wasmruntime // A Raw() node carries its markup in VNode.HTML and has NO children — the markup // only exists in the DOM. So when the diff reuses that element for a node that // has children instead (same tag, same index — e.g. a route change from a page // with a server-rendered SVG to one without), the new children must not simply be // appended alongside the surviving markup. func TestPatchClearsRawHTMLWhenElementIsReused(t *testing.T) { root := document.Call("createElement", "div") chart := vdom.El("div", vdom.Attr("class", "grid"), vdom.El("div", vdom.Attr("class", "cell"), vdom.Raw(``)), ) patchChildren(root, nil, one(chart)) if got := root.Get("innerHTML").String(); !strings.Contains(got, ``) { t.Fatalf("raw HTML was not mounted: %s", got) } // Same tags at the same indexes, so the diff adopts the DOM rather than // replacing it. data := vdom.El("div", vdom.Attr("class", "cards"), vdom.El("div", vdom.Attr("class", "card"), vdom.Text("gob section")), ) patchChildren(root, one(chart), one(data)) got := root.Get("innerHTML").String() if strings.Contains(got, "svg") { t.Errorf("stale raw HTML survived the patch (the chart would follow you to the next page):\n%s", got) } if !strings.Contains(got, "gob section") { t.Errorf("new children were not rendered:\n%s", got) } } // The reverse transition: an element with real children reused for a Raw() node. // innerHTML replaces the children wholesale, so nothing may linger. func TestPatchReplacesChildrenWithRawHTML(t *testing.T) { root := document.Call("createElement", "div") withKids := vdom.El("div", vdom.El("span", vdom.Text("hello"))) patchChildren(root, nil, one(withKids)) withRaw := vdom.El("div", vdom.Raw(``)) patchChildren(root, one(withKids), one(withRaw)) got := root.Get("innerHTML").String() if strings.Contains(got, "hello") || strings.Contains(got, "span") { t.Errorf("old children survived under raw HTML:\n%s", got) } if !strings.Contains(got, ``) { t.Errorf("raw HTML was not applied:\n%s", got) } } // Raw markup that does not change must be left alone (it is not re-set on every // render, which would blow away any DOM state inside it). func TestPatchKeepsUnchangedRawHTML(t *testing.T) { root := document.Call("createElement", "div") a := vdom.El("div", vdom.Raw(``)) patchChildren(root, nil, one(a)) before := rt(a).dom.Get("childNodes").Index(0) b := vdom.El("div", vdom.Raw(``)) patchChildren(root, one(a), one(b)) after := rt(b).dom.Get("childNodes").Index(0) if !before.Equal(after) { t.Error("unchanged raw HTML was re-parsed instead of being left in place") } }