| <!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> |
| 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'); |
| wrapper.innerHTML = 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') { |
| // TODO(masonfreed): Add a check for ElementInternals.shadowRoot once that exists. |
| assert_true(!!element.shadowRoot, 'Shadow root should be present'); |
| assert_equals(element.shadowRoot.innerHTML, shadowContent, 'Correct shadow content'); |
| 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') { |
| // TODO(masonfreed): Add a check for ElementInternals.shadowRoot once that exists. |
| 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> |