92 lines
3.3 KiB
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")
|
|
}
|
|
}
|