blob: b9033f599242237626985f35ac6560527c972b32 [file] [log] [blame]
<!DOCTYPE html>
<title>Declarative Shadow DOM Element Attachment</title>
<link rel='author' title='Mason Freed' href='mailto:masonfreed@chromium.org'>
<link rel='help' href='https://github.com/whatwg/dom/issues/831'>
<script src='/resources/testharness.js'></script>
<script src='/resources/testharnessreport.js'></script>
<script src='../resources/shadow-dom-utils.js'></script>
<script src="support/helpers.js"></script>
<script>
const shadowContent = '<span>Shadow tree</span><slot></slot>';
function getDeclarativeContent(mode, delegatesFocus) {
const delegatesFocusText = delegatesFocus ? ' shadowrootdelegatesfocus' : '';
return `<template shadowroot=${mode}${delegatesFocusText}>${shadowContent}</template>`;
}
const lightDomTextContent = 'Light DOM';
function addDeclarativeShadowRoot(elementType, mode, delegatesFocus) {
const declarativeString = `<${elementType} id=theelement>${getDeclarativeContent(mode, delegatesFocus)}
<span class='lightdom'>${lightDomTextContent}</span></${elementType}>`;
const wrapper = document.createElement('div');
setInnerHTML(wrapper, declarativeString);
const element = wrapper.querySelector('#theelement');
return {wrapper: wrapper, element: element};
}
function testElementType(allowed, nochildren, elementType, mode, delegatesFocus) {
var t = test(function() {
const nodes = addDeclarativeShadowRoot(elementType, mode, delegatesFocus);
if (allowed) {
const element = nodes.element;
assert_true(!!element, 'Unable to locate the element');
// Just one light DOM child, and no leftover template.
assert_true(!nodes.wrapper.querySelector('template'));
assert_equals(element.children.length, 1);
assert_equals(element.children[0].textContent, lightDomTextContent);
let originalShadowRoot = null;
if (mode === 'open') {
assert_true(!!element.shadowRoot, 'Shadow root should be present');
assert_equals(element.shadowRoot.innerHTML, shadowContent, 'Correct shadow content');
assert_equals(element.shadowRoot.delegatesFocus,delegatesFocus,'Correct 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
if (mode === 'open') {
assert_equals(element.shadowRoot, originalShadowRoot, 'The same shadow root should be returned');
assert_equals(element.shadowRoot.innerHTML, '', 'Empty shadow content');
assert_equals(element.shadowRoot.mode, mode, 'Original shadow mode');
}
} else {
const wrapper = nodes.wrapper;
if (!nochildren) {
// Invalid elements should retain a <template> element child with a shadowroot attribute.
const template = nodes.wrapper.querySelector('template[shadowroot]');
assert_true(!!template);
assert_equals(template.getAttribute('shadowroot'), mode, `Template with shadowroot=${mode} should be left over`);
const span = nodes.wrapper.querySelector('span.lightdom');
assert_true(!!span);
assert_equals(span.textContent, lightDomTextContent);
if (nodes.element) {
// For some tags (e.g. <html>) there won't be an element inside wrapper.
assert_true(!nodes.element.shadowRoot, 'Shadow root should not be present');
}
}
}
}, `Declarative Shadow DOM as a child of <${elementType}>, with mode=${mode}, delegatesFocus=${delegatesFocus}. Should be ${allowed ? 'safelisted' : 'disallowed'}.`);
}
function runAllTests() {
const noCheck = ['body'];
const safelisted = ATTACHSHADOW_SAFELISTED_ELEMENTS.filter(el => !noCheck.includes(el));
const disallowed = ATTACHSHADOW_DISALLOWED_ELEMENTS.filter(el => !noCheck.includes(el));
const noChildElements = ['iframe','noscript','script','select','style','textarea','title'];
for (let delegatesFocus of [false, true]) {
for (let mode of ['open', 'closed', 'invalid']) {
for (let elementName of safelisted) {
testElementType(mode !== 'invalid', false, elementName, mode, delegatesFocus);
}
for (let elementName of disallowed) {
testElementType(false, noChildElements.includes(elementName), elementName, mode, delegatesFocus);
}
}
}
}
runAllTests();
</script>