0

Disallow multiple declarative roots and mismatched imperative ones

Two changes:
 1. If two declarative shadow roots are included within a single
    host element, only the *first* one will remain. This is a
    change in behavior from before, but reached consensus [1]
    and hopefully won't be a breaking change for anyone.
 2. If attachShadow() is used on an existing declarative shadow
    root, and the parameters (e.g. shadow root type, etc.) do
    not match, an exception is thrown. This, also, is a breaking
    change, but hopefully not one that gets hit. See also [1].

See [2] and [3] for the corresponding spec PRs.

[1] https://github.com/whatwg/dom/issues/1235
[2] https://github.com/whatwg/html/pull/10069
[3] https://github.com/whatwg/dom/pull/1246

Bug: 1379513,1042130
Change-Id: Ia81088227797013f9f62f5ac90f76898663b0bc4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5191750
Commit-Queue: Mason Freed <masonf@chromium.org>
Auto-Submit: Mason Freed <masonf@chromium.org>
Commit-Queue: David Baron <dbaron@chromium.org>
Reviewed-by: David Baron <dbaron@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1249214}
This commit is contained in:
Mason Freed
2024-01-19 03:09:50 +00:00
committed by Chromium LUCI CQ
parent 85bcd3e36b
commit fe5237a87b
13 changed files with 308 additions and 14 deletions

@ -5380,7 +5380,7 @@ bool Element::CanAttachShadowRoot() const {
tag_name == html_names::kSelectlistTag;
}
const char* Element::ErrorMessageForAttachShadow() const {
const char* Element::ErrorMessageForAttachShadow(bool for_declarative) const {
// https://dom.spec.whatwg.org/#concept-attach-a-shadow-root
// 1. If shadow hosts namespace is not the HTML namespace, then throw a
// "NotSupportedError" DOMException.
@ -5413,11 +5413,21 @@ const char* Element::ErrorMessageForAttachShadow() const {
}
}
// 4. If shadow host has a non-null shadow root whose "is declarative shadow
// root" property is false, then throw an "NotSupportedError" DOMException.
if (GetShadowRoot() && !GetShadowRoot()->IsDeclarativeShadowRoot()) {
return "Shadow root cannot be created on a host "
"which already hosts a shadow tree.";
if (!GetShadowRoot()) {
return nullptr;
}
// If shadow host has a non-null shadow root and "for declarative" is set,
// then throw a "NotSupportedError" DOMException.
if (for_declarative &&
RuntimeEnabledFeatures::ShadowRootAttachmentNewBehaviorEnabled()) {
return "A second declarative shadow root cannot be created on a host.";
}
// If shadow host has a non-null shadow root, "for declarative" is unset,
// and shadow root's "is declarative shadow root" property is false, then
// throw a "NotSupportedError" DOMException.
if (!GetShadowRoot()->IsDeclarativeShadowRoot()) {
return "Shadow root cannot be created on a host which already hosts a "
"shadow tree.";
}
return nullptr;
}
@ -5445,12 +5455,31 @@ ShadowRoot* Element::attachShadow(const ShadowRootInit* shadow_root_init_dict,
CustomElementRegistry* registry = shadow_root_init_dict->hasRegistry()
? shadow_root_init_dict->registry()
: nullptr;
if (const char* error_message = ErrorMessageForAttachShadow()) {
if (const char* error_message =
ErrorMessageForAttachShadow(/*for_declarative*/ false)) {
exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
error_message);
return nullptr;
}
// If there's already a declarative shadow root, verify that the parameters
// are all the same.
if (RuntimeEnabledFeatures::ShadowRootAttachmentNewBehaviorEnabled()) {
if (auto* existing_shadow = GetShadowRoot()) {
CHECK(existing_shadow->IsDeclarativeShadowRoot());
if (existing_shadow->GetType() != type ||
existing_shadow->delegatesFocus() !=
(focus_delegation == FocusDelegation::kDelegateFocus) ||
existing_shadow->GetSlotAssignmentMode() != slot_assignment) {
exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
"Parameters used for attachShadow() "
"don't match existing declarative "
"shadow root");
return nullptr;
}
}
}
ShadowRoot& shadow_root = AttachShadowRootInternal(type, focus_delegation,
slot_assignment, registry);
@ -5471,7 +5500,8 @@ bool Element::AttachDeclarativeShadowRoot(HTMLTemplateElement& template_element,
// host element, mode equal to declarative shadow mode, and delegates focus
// equal to declarative shadow delegates focus. If an exception was thrown by
// attach a shadow root, catch it, and ignore the exception.
if (const char* error_message = ErrorMessageForAttachShadow()) {
if (const char* error_message =
ErrorMessageForAttachShadow(/*for_declarative*/ true)) {
GetDocument().AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
mojom::blink::ConsoleMessageSource::kOther,
mojom::blink::ConsoleMessageLevel::kError, error_message));

@ -1452,7 +1452,7 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
delete; // This will catch anyone doing an unnecessary check.
bool CanAttachShadowRoot() const;
const char* ErrorMessageForAttachShadow() const;
const char* ErrorMessageForAttachShadow(bool for_declarative) const;
void StyleAttributeChanged(const AtomicString& new_style_string,
AttributeModificationReason);

@ -1252,6 +1252,7 @@
{
// This is a killswitch (enabled by *enabling* the feature) for the
// removal of the IDL reflection of the old 'shadowroot' attribute.
// This should be removed in M124 (Feb 20, 2024) assuming no issues.
name: "DeprecatedTemplateShadowRoot",
},
{
@ -3431,6 +3432,14 @@
name: "SetSequentialFocusStartingPoint",
status: "experimental",
},
{
// This is a killswitch for the change in declarative/imperative shadow
// root attachment (see [1]). This should be removed in M124 (Feb 20,
// 2024) assuming no issues are encountered.
// [1] https://github.com/whatwg/dom/issues/1235
name: "ShadowRootAttachmentNewBehavior",
status: "stable",
},
{
name: "SharedArrayBuffer",
base_feature: "none",

@ -1089,6 +1089,17 @@
"args": ["--enable-blink-features=DeprecatedTemplateShadowRoot"],
"expires": "Jul 1, 2024"
},
{
"prefix": "new-shadowroot-attach-behavior-disabled",
"owners": ["masonf@chromium.org"],
"platforms": ["Linux"],
"bases": [
"external/wpt/shadow-dom/declarative",
"shadow-dom"
],
"args": ["--disable-blink-features=ShadowRootAttachmentNewBehavior"],
"expires": "Jul 1, 2024"
},
{
"prefix": "details-styling-disabled",
"owners": ["dbaron@chromium.org", "dom-dev@chromium.org"],

@ -42,9 +42,13 @@ function testElementType(allowed, nochildren, elementType, mode, delegatesFocus)
originalShadowRoot = element.shadowRoot;
}
// Now, call attachShadow() and make sure we get back the same (original) shadowRoot, but empty.
const oppositeMode = (mode === 'open') ? 'closed' : 'open';
const newShadow = element.attachShadow({mode: oppositeMode}); // Should be no exception here
assert_throws_dom('NotSupportedError', () => {
element.attachShadow({mode: oppositeMode});
}, 'Calling attachShadow with a declarative shadow fails if the mode doesn\'t match');
// Now, call attachShadow() and make sure we get back the same (original) shadowRoot, but empty.
const newShadow = element.attachShadow({mode: mode, delegatesFocus: delegatesFocus});
if (mode === 'open') {
assert_equals(element.shadowRoot, originalShadowRoot, 'The same shadow root should be returned');
assert_equals(element.shadowRoot.innerHTML, '', 'Empty shadow content');

@ -154,10 +154,14 @@ test(() => {
<script>
test(() => {
const host = document.querySelector('#multi-host');
assert_equals(host.querySelector('template'), null, "No leftover template nodes from either root");
const leftover = host.querySelector('template');
assert_true(!!leftover, "The second (duplicate) template should be left in the DOM");
assert_true(leftover instanceof HTMLTemplateElement);
assert_equals(leftover.getAttribute('shadowrootmode'),"closed");
assert_equals(leftover.shadowRootMode,"closed");
assert_true(!!host.shadowRoot,"No open shadow root found - first root should remain");
const innerSpan = host.shadowRoot.querySelector('span');
assert_equals(innerSpan.textContent, 'root 2', "Content should come from last declarative shadow root");
assert_equals(innerSpan.textContent, 'root 1', "Content should come from first declarative shadow root");
}, 'Declarative Shadow DOM: Multiple roots');
</script>

@ -0,0 +1,73 @@
<!DOCTYPE html>
<title>Declarative Shadow DOM Element Attachment</title>
<link rel='author' href='mailto:masonf@chromium.org'>
<link rel='help' href='https://github.com/whatwg/dom/issues/1235'>
<link rel='help' href='https://github.com/whatwg/html/pull/10069'>
<link rel='help' href='https://github.com/whatwg/dom/pull/1246'>
<script src='/resources/testharness.js'></script>
<script src='/resources/testharnessreport.js'></script>
<script src='../../html/resources/common.js'></script>
<script src="support/helpers.js"></script>
<div id=multiple1>
<template shadowrootmode=open>Open</template>
<template shadowrootmode=closed>Closed</template>
</div>
<div id=multiple2>
<template shadowrootmode=closed>Closed</template>
<template shadowrootmode=open>Open</template>
</div>
<script>
test((t) => {
let shadow = multiple1.shadowRoot;
assert_true(!!shadow,'Remaining shadow root should be open');
assert_equals(shadow.textContent,"Open");
shadow = multiple2.shadowRoot;
assert_false(!!shadow,'Remaining shadow root should be closed');
multiple1.remove(); // Cleanup
multiple2.remove();
},'Repeated declarative shadow roots keep only the first');
</script>
<div id=open1>
<template shadowrootmode=open>Open</template>
</div>
<script>
test((t) => {
assert_throws_dom("NotSupportedError",() => {
open1.attachShadow({mode: "closed"});
},'Mismatched shadow root type should throw');
const initialShadow = open1.shadowRoot;
const shadow = open1.attachShadow({mode: "open"}); // Shouldn't throw
assert_equals(shadow,initialShadow,'Same shadow should be returned');
assert_equals(shadow.textContent,'','Shadow should be empty');
},'Calling attachShadow() on declarative shadow root must match type');
</script>
<div id=open2>
<template shadowrootmode=open shadowrootdelegatesfocus>
Open, delegates focus (not the default), named slot assignment (the default)
</template>
</div>
<script>
test((t) => {
assert_throws_dom("NotSupportedError",() => {
open2.attachShadow({mode: "closed", delegatesFocus: true, slotAssignment: "named"});
},'Mismatched shadow root type should throw');
assert_throws_dom("NotSupportedError",() => {
open2.attachShadow({mode: "open", delegatesFocus: false, slotAssignment: "named"});
},'Mismatched shadow root delegatesFocus should throw');
assert_throws_dom("NotSupportedError",() => {
open2.attachShadow({mode: "open", delegatesFocus: true, slotAssignment: "manual"});
},'Mismatched shadow root slotAssignment should throw');
const initialShadow = open2.shadowRoot;
const shadow = open2.attachShadow({mode: "open", delegatesFocus: true, slotAssignment: "named"}); // Shouldn't throw
assert_equals(shadow,initialShadow,'Same shadow should be returned');
assert_equals(shadow.textContent,'','Shadow should be empty');
},'Calling attachShadow() on declarative shadow root must match all parameters');
</script>

@ -1,6 +1,6 @@
CONSOLE ERROR: This element does not support attachShadow
CONSOLE ERROR: attachShadow() is disabled by disabledFeatures static field.
CONSOLE ERROR: Shadow root cannot be created on a host which already hosts a shadow tree.
CONSOLE ERROR: A second declarative shadow root cannot be created on a host.
PASS successfullyParsed is true
TEST COMPLETE

@ -0,0 +1,2 @@
# This suite runs tests with --disable-blink-features=ShadowRootAttachmentNewBehavior.
This is to ensure the killswitch works.

@ -0,0 +1,140 @@
This is a testharness.js-based test.
Found 68 FAIL, 0 TIMEOUT, 0 NOTRUN.
[FAIL] Declarative Shadow DOM as a child of <article>, with mode=open, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <aside>, with mode=open, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <blockquote>, with mode=open, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <div>, with mode=open, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <footer>, with mode=open, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h1>, with mode=open, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h2>, with mode=open, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h3>, with mode=open, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h4>, with mode=open, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h5>, with mode=open, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h6>, with mode=open, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <header>, with mode=open, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <main>, with mode=open, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <nav>, with mode=open, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <p>, with mode=open, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <section>, with mode=open, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <span>, with mode=open, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <article>, with mode=closed, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <aside>, with mode=closed, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <blockquote>, with mode=closed, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <div>, with mode=closed, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <footer>, with mode=closed, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h1>, with mode=closed, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h2>, with mode=closed, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h3>, with mode=closed, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h4>, with mode=closed, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h5>, with mode=closed, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h6>, with mode=closed, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <header>, with mode=closed, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <main>, with mode=closed, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <nav>, with mode=closed, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <p>, with mode=closed, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <section>, with mode=closed, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <span>, with mode=closed, delegatesFocus=false. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <article>, with mode=open, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <aside>, with mode=open, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <blockquote>, with mode=open, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <div>, with mode=open, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <footer>, with mode=open, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h1>, with mode=open, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h2>, with mode=open, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h3>, with mode=open, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h4>, with mode=open, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h5>, with mode=open, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h6>, with mode=open, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <header>, with mode=open, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <main>, with mode=open, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <nav>, with mode=open, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <p>, with mode=open, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <section>, with mode=open, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <span>, with mode=open, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <article>, with mode=closed, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <aside>, with mode=closed, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <blockquote>, with mode=closed, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <div>, with mode=closed, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <footer>, with mode=closed, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h1>, with mode=closed, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h2>, with mode=closed, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h3>, with mode=closed, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h4>, with mode=closed, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h5>, with mode=closed, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <h6>, with mode=closed, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <header>, with mode=closed, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <main>, with mode=closed, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <nav>, with mode=closed, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <p>, with mode=closed, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <section>, with mode=closed, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
[FAIL] Declarative Shadow DOM as a child of <span>, with mode=closed, delegatesFocus=true. Should be safelisted.
assert_throws_dom: Calling attachShadow with a declarative shadow fails if the mode doesn't match function "() => {\n element.attachShadow({mode: oppositeMode});\n }" did not throw
Harness: the test ran to completion.

@ -0,0 +1,5 @@
This is a testharness.js-based test.
[FAIL] Declarative Shadow DOM: Multiple roots
assert_true: The second (duplicate) template should be left in the DOM expected true got false
Harness: the test ran to completion.

@ -0,0 +1,9 @@
This is a testharness.js-based test.
[FAIL] Repeated declarative shadow roots keep only the first
assert_equals: expected "Open" but got "Closed"
[FAIL] Calling attachShadow() on declarative shadow root must match type
assert_throws_dom: Mismatched shadow root type should throw function "() => {\n open1.attachShadow({mode: "closed"});\n }" did not throw
[FAIL] Calling attachShadow() on declarative shadow root must match all parameters
assert_throws_dom: Mismatched shadow root type should throw function "() => {\n open2.attachShadow({mode: "closed", delegatesFocus: true, slotAssignment: "named"});\n }" did not throw
Harness: the test ran to completion.

@ -0,0 +1,7 @@
CONSOLE ERROR: This element does not support attachShadow
CONSOLE ERROR: attachShadow() is disabled by disabledFeatures static field.
CONSOLE ERROR: Shadow root cannot be created on a host which already hosts a shadow tree.
PASS successfullyParsed is true
TEST COMPLETE