Files
kjol/go/wasmruntime/svg_test.go

92 lines
3.3 KiB
Go

//go:build js && wasm
package wasmruntime
import (
"testing"
"kjol/wasmruntime/vdom"
)
// An <svg> built with document.createElement() is NOT an SVG element — it is an
// HTMLUnknownElement that happens to be spelled "svg". It has no geometry and it
// draws nothing, while still looking perfectly correct in the DOM inspector.
//
// This only bit on NAVIGATION: a server-rendered page's icons come from the HTML
// parser, which handles <svg> as foreign content correctly, and hydration merely
// adopts those nodes. Every icon the CLIENT created afterwards was inert.
func TestSVGIsCreatedInTheSVGNamespace(t *testing.T) {
root := document.Call("createElement", "div")
icon := vdom.El("svg",
vdom.Attr("viewBox", "0 0 24 24"),
vdom.El("path", vdom.Attr("d", "M4 4h16")),
)
patchChildren(root, nil, one(icon))
svg := root.Get("childNodes").Index(0)
if got := svg.Get("namespaceURI").String(); got != svgNamespace {
t.Fatalf("<svg> namespace = %q, want %q — it will render nothing", got, svgNamespace)
}
// The subtree inherits it: a <path> in the HTML namespace draws nothing either.
path := svg.Get("childNodes").Index(0)
if got := path.Get("namespaceURI").String(); got != svgNamespace {
t.Errorf("<path> namespace = %q, want %q", got, svgNamespace)
}
}
// Ordinary HTML must NOT end up in the SVG namespace, including siblings that follow
// an icon.
func TestHTMLStaysInTheHTMLNamespace(t *testing.T) {
root := document.Call("createElement", "div")
tree := vdom.El("div",
vdom.El("svg", vdom.El("path")),
vdom.El("span", vdom.Text("after the icon")),
)
patchChildren(root, nil, one(tree))
div := root.Get("childNodes").Index(0)
span := div.Get("childNodes").Index(1)
if got := span.Get("namespaceURI").String(); got == svgNamespace {
t.Errorf("<span> after an <svg> leaked into the SVG namespace")
}
}
// The navigation case, end to end: page A's tree is replaced by page B's, and the
// icon page B creates mid-diff must still be a real SVG. This is the one that broke.
func TestIconCreatedDuringNavigationIsRealSVG(t *testing.T) {
root := document.Call("createElement", "div")
pageA := vdom.El("div", vdom.El("p", vdom.Text("no icons here")))
patchChildren(root, nil, one(pageA))
// Navigate: same tag at the same index, so the diff reuses the <div> and creates
// the icon *underneath* it rather than from a fresh mount.
pageB := vdom.El("div", vdom.El("svg", vdom.Attr("viewBox", "0 0 24 24"), vdom.El("path")))
patchChildren(root, one(pageA), one(pageB))
svg := root.Get("childNodes").Index(0).Get("childNodes").Index(0)
if got := svg.Get("tag").String(); got != "svg" {
t.Fatalf("expected an <svg>, got <%s>", got)
}
if got := svg.Get("namespaceURI").String(); got != svgNamespace {
t.Errorf("icon created during navigation has namespace %q, want %q — this is the bug", got, svgNamespace)
}
}
// A <foreignObject> switches back to HTML for its contents.
func TestForeignObjectReturnsToHTML(t *testing.T) {
root := document.Call("createElement", "div")
tree := vdom.El("svg", vdom.El("foreignObject", vdom.El("div", vdom.Text("html again"))))
patchChildren(root, nil, one(tree))
fo := root.Get("childNodes").Index(0).Get("childNodes").Index(0)
inner := fo.Get("childNodes").Index(0)
if got := inner.Get("namespaceURI").String(); got == svgNamespace {
t.Error("content inside <foreignObject> should be HTML, not SVG")
}
}