Automatic update from web-platform-tests Fix custom element upgrade in declarative shadow roots parsed via setHTMLUnsafe (#59888) When template.setHTMLUnsafe() parses declarative shadow roots, the template document has no domWindow(), causing AttachShadowRootInternal to call SetCustomElementRegistry(nullptr) which incorrectly sets waiting_for_registry_=true. After adoption into the live document, customElementRegistry() returns null, blocking TryToUpgrade. Fix by adding an explicit waiting_for_scoped_registry parameter to AttachShadowRootInternal to distinguish 'no window available' from 'explicitly null registry'. SetCustomElementRegistry is now only called when registry || waiting_for_scoped_registry. Also update sethtml-with-declarative-shadow-root.tentative.html expectation that customElementRegistry is null when the sanitizer strips shadowrootcustomelementregistry. The null was accidental — shadow roots parsed in template documents (used by setHTML with sanitizer via ForceInertTemplate) were incorrectly stuck with null registries. The correct default when the attribute is absent is the global registry. Bug: 512514744 Change-Id: If9cc66a90c46c6c3cdeda0bf9e090abff4da021a Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7844339 Reviewed-by: Noam Rosenthal <nrosenthal@google.com> Reviewed-by: Mason Freed <masonf@chromium.org> Commit-Queue: Jayson Chen <jaysonchen@microsoft.com> Cr-Commit-Position: refs/heads/main@{#1630685} Co-authored-by: Jayson Chen <jaysonchen@microsoft.com> -- wpt-commits: d21d659d9020b1a2ea83e443bf05e8c59a8090c1 wpt-pr: 59888
104 lines
6.1 KiB
JavaScript
104 lines
6.1 KiB
JavaScript
test(() => {
|
|
const template = document.createElement("template");
|
|
assert_false(template.hasAttribute("shadowrootcustomelementregistry"));
|
|
assert_equals(template.shadowRootCustomElementRegistry, "");
|
|
|
|
template.shadowRootCustomElementRegistry = "blah";
|
|
assert_equals(template.getAttribute("shadowrootcustomelementregistry"), "blah");
|
|
assert_equals(template.shadowRootCustomElementRegistry, "blah");
|
|
}, "shadowRootCustomElementRegistry reflects as string");
|
|
|
|
test(() => {
|
|
const div = document.createElement("div");
|
|
div.setHTMLUnsafe(`<span><template shadowrootmode=open shadowrootcustomelementregistry shadowrootserializable></template></span>`);
|
|
assert_equals(div.firstChild.firstChild, null);
|
|
assert_equals(div.getHTML({ serializableShadowRoots: true }), "<span><template shadowrootmode=\"open\" shadowrootserializable=\"\" shadowrootcustomelementregistry=\"\"></template></span>");
|
|
}, "Serializing a null registry ShadowRoot with a global registry host (document)");
|
|
|
|
test(() => {
|
|
const div = document.createElement("div");
|
|
div.setHTMLUnsafe(`<span><template shadowrootmode=open shadowrootserializable></template></span>`);
|
|
assert_equals(div.firstChild.firstChild, null);
|
|
assert_equals(div.firstChild.shadowRoot.customElementRegistry, customElements);
|
|
assert_equals(div.getHTML({ serializableShadowRoots: true }), "<span><template shadowrootmode=\"open\" shadowrootserializable=\"\"></template></span>");
|
|
}, "Serializing a global registry ShadowRoot with a global registry host (document)");
|
|
|
|
test(() => {
|
|
const div = document.createElement("div");
|
|
div.setHTMLUnsafe(`<span><template shadowrootmode=open shadowrootcustomelementregistry shadowrootserializable></template></span>`);
|
|
const registry = new CustomElementRegistry();
|
|
registry.initialize(div.firstChild.shadowRoot);
|
|
assert_equals(div.firstChild.shadowRoot.customElementRegistry, registry);
|
|
assert_equals(div.getHTML({ serializableShadowRoots: true }), "<span><template shadowrootmode=\"open\" shadowrootserializable=\"\" shadowrootcustomelementregistry=\"\"></template></span>");
|
|
}, "Serializing a scoped registry ShadowRoot with a global registry host (document)");
|
|
|
|
test(() => {
|
|
const div = document.implementation.createHTMLDocument().createElement("div");
|
|
assert_equals(div.customElementRegistry, null);
|
|
div.setHTMLUnsafe(`<span><template shadowrootmode=open shadowrootcustomelementregistry shadowrootserializable></template></span>`);
|
|
assert_equals(div.firstChild.shadowRoot.customElementRegistry, null);
|
|
assert_equals(div.getHTML({ serializableShadowRoots: true }), "<span><template shadowrootmode=\"open\" shadowrootserializable=\"\"></template></span>");
|
|
}, "Serializing a null registry ShadowRoot with a null registry host (document)");
|
|
|
|
test(() => {
|
|
const div = document.implementation.createHTMLDocument().createElement("div");
|
|
assert_equals(div.customElementRegistry, null);
|
|
div.setHTMLUnsafe(`<span><template shadowrootmode=open shadowrootcustomelementregistry shadowrootserializable></template></span>`);
|
|
const registry = new CustomElementRegistry();
|
|
registry.initialize(div.firstChild.shadowRoot);
|
|
assert_equals(div.firstChild.shadowRoot.customElementRegistry, registry);
|
|
assert_equals(div.getHTML({ serializableShadowRoots: true }), "<span><template shadowrootmode=\"open\" shadowrootserializable=\"\" shadowrootcustomelementregistry=\"\"></template></span>");
|
|
}, "Serializing a scoped registry ShadowRoot with a null registry host (document)");
|
|
|
|
test(() => {
|
|
const registry = new CustomElementRegistry();
|
|
const hostDocument = document.implementation.createHTMLDocument();
|
|
registry.initialize(hostDocument);
|
|
assert_equals(hostDocument.customElementRegistry, registry);
|
|
const host = hostDocument.createElement('div');
|
|
assert_equals(host.customElementRegistry, registry);
|
|
const shadow = host.attachShadow({ mode: "closed", serializable: true, customElementRegistry: null });
|
|
assert_equals(shadow.customElementRegistry, null);
|
|
assert_equals(host.getHTML({ serializableShadowRoots: true }), `<template shadowrootmode="closed" shadowrootserializable="" shadowrootcustomelementregistry=""></template>`);
|
|
}, "Serializing a null registry ShadowRoot with a scoped registry host (document)");
|
|
|
|
test(() => {
|
|
const registry = new CustomElementRegistry();
|
|
const hostDocument = document.implementation.createHTMLDocument();
|
|
registry.initialize(hostDocument);
|
|
assert_equals(hostDocument.customElementRegistry, registry);
|
|
const host = hostDocument.createElement('div');
|
|
assert_equals(host.customElementRegistry, registry);
|
|
const shadow = host.attachShadow({ mode: "closed", serializable: true, customElementRegistry: registry });
|
|
assert_equals(shadow.customElementRegistry, registry);
|
|
assert_equals(host.getHTML({ serializableShadowRoots: true }), `<template shadowrootmode="closed" shadowrootserializable="" shadowrootcustomelementregistry=""></template>`);
|
|
}, "Serializing a scoped registry ShadowRoot with a scoped registry host (document)");
|
|
|
|
test(() => {
|
|
const registry = new CustomElementRegistry();
|
|
const element = document.createElement('a-b', { customElementRegistry: registry });
|
|
element.setHTMLUnsafe(`<a-b><template shadowrootmode="open"></template></a-b>`);
|
|
assert_equals(element.firstChild.customElementRegistry, registry);
|
|
assert_equals(element.firstChild.shadowRoot.customElementRegistry, customElements);
|
|
}, "A declarative shadow root gets its default registry from its node document");
|
|
|
|
test(() => {
|
|
const name = "declarative-shadow-upgrade-el";
|
|
let connectedCount = 0;
|
|
class TestElement extends HTMLElement {
|
|
connectedCallback() { connectedCount++; }
|
|
}
|
|
customElements.define(name, TestElement);
|
|
|
|
const template = document.createElement("template");
|
|
template.setHTMLUnsafe(
|
|
`<div><template shadowrootmode="open"><${name}></${name}></template></div>`);
|
|
document.body.appendChild(template.content);
|
|
|
|
const host = document.body.lastElementChild;
|
|
const el = host.shadowRoot.querySelector(name);
|
|
assert_true(el instanceof TestElement);
|
|
assert_equals(connectedCount, 1);
|
|
host.remove();
|
|
}, "Custom element upgrades inside a declarative shadow root parsed via template.setHTMLUnsafe()");
|