summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/shadow-dom
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /testing/web-platform/tests/shadow-dom
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'testing/web-platform/tests/shadow-dom')
-rw-r--r--testing/web-platform/tests/shadow-dom/Document-prototype-adoptNode.html31
-rw-r--r--testing/web-platform/tests/shadow-dom/Document-prototype-currentScript.html98
-rw-r--r--testing/web-platform/tests/shadow-dom/Document-prototype-importNode.html31
-rw-r--r--testing/web-platform/tests/shadow-dom/Element-interface-attachShadow.html94
-rw-r--r--testing/web-platform/tests/shadow-dom/Element-interface-shadowRoot-attribute.html45
-rw-r--r--testing/web-platform/tests/shadow-dom/Extensions-to-Event-Interface.html234
-rw-r--r--testing/web-platform/tests/shadow-dom/HTMLSlotElement-interface.html269
-rw-r--r--testing/web-platform/tests/shadow-dom/MouseEvent-prototype-offsetX-offsetY.html154
-rw-r--r--testing/web-platform/tests/shadow-dom/Node-prototype-cloneNode.html57
-rw-r--r--testing/web-platform/tests/shadow-dom/OWNERS5
-rw-r--r--testing/web-platform/tests/shadow-dom/ShadowRoot-interface.html111
-rw-r--r--testing/web-platform/tests/shadow-dom/Slotable-interface.html94
-rw-r--r--testing/web-platform/tests/shadow-dom/event-composed-path-with-related-target.html260
-rw-r--r--testing/web-platform/tests/shadow-dom/event-composed-path.html281
-rw-r--r--testing/web-platform/tests/shadow-dom/event-composed.html81
-rw-r--r--testing/web-platform/tests/shadow-dom/event-inside-shadow-tree.html148
-rw-r--r--testing/web-platform/tests/shadow-dom/event-inside-slotted-node.html258
-rw-r--r--testing/web-platform/tests/shadow-dom/event-with-related-target.html256
-rw-r--r--testing/web-platform/tests/shadow-dom/leaktests/get-elements.html174
-rw-r--r--testing/web-platform/tests/shadow-dom/leaktests/html-collection.html76
-rw-r--r--testing/web-platform/tests/shadow-dom/leaktests/window-frames.html36
-rw-r--r--testing/web-platform/tests/shadow-dom/resources/Document-prototype-currentScript-helper.js1
-rw-r--r--testing/web-platform/tests/shadow-dom/resources/event-path-test-helpers.js93
-rw-r--r--testing/web-platform/tests/shadow-dom/resources/shadow-dom-utils.js154
-rw-r--r--testing/web-platform/tests/shadow-dom/resources/shadow-dom.js130
-rw-r--r--testing/web-platform/tests/shadow-dom/scroll-to-the-fragment-in-shadow-tree.html127
-rw-r--r--testing/web-platform/tests/shadow-dom/slotchange-event.html620
-rw-r--r--testing/web-platform/tests/shadow-dom/slotchange.html270
-rw-r--r--testing/web-platform/tests/shadow-dom/slots-fallback.html221
-rw-r--r--testing/web-platform/tests/shadow-dom/slots.html508
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/LICENSE107
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/README2
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-element-interface/attributes/test-006.html37
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-element-interface/methods/test-001.html39
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-element-interface/methods/test-002.html45
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-event-interface/event-path-001.html56
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/activeElement-confirm-return-null.html78
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-007.html50
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-009.html43
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-010.html75
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-011.html56
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-012.html39
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-013.html39
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-001.html61
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-004.html51
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-006.html57
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-007.html62
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-010.html42
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/events/event-dispatch/test-002.html61
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/events/event-dispatch/test-003.html81
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/events/event-retargeting/test-001.html106
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/events/event-retargeting/test-003.html61
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-focus-events/test-001.html322
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-focus-events/test-002.html63
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-focus-events/test-003.html62
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-relatedtarget/test-001.html69
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-relatedtarget/test-002.html64
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-relatedtarget/test-003.html56
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/events/test-001.html70
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/html-elements-in-shadow-trees/html-forms/test-001.html73
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/html-elements-in-shadow-trees/html-forms/test-002.html103
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/html-elements-in-shadow-trees/html-forms/test-003.html88
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/html-elements-in-shadow-trees/inert-html-elements/test-001.html79
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/html-elements-in-shadow-trees/inert-html-elements/test-002.html45
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/resources/blank.html5
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/resources/bobs_page.html35
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/nested-shadow-trees/nested_tree_reftest-ref.html25
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/nested-shadow-trees/nested_tree_reftest.html30
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/reprojection/reprojection-001-ref.html35
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/reprojection/reprojection-001.html39
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/shadow-root-001-ref.html25
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/shadow-root-001.html35
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/shadow-root-002-ref.html31
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/shadow-root-002.html49
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/text-decoration-001-ref.html13
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/text-decoration-001.html22
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/dom-tree-accessors-001.html227
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/dom-tree-accessors-002.html71
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/ownerdocument-001.html108
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/ownerdocument-002.html56
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/selectors-api-001.html80
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/selectors-api-002.html84
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/shadow-root-001.html63
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-005.html73
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-007.html74
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-009.html244
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-011.html51
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/window-named-properties-001.html47
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/window-named-properties-002.html50
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/window-named-properties-003.html47
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/styles/not-apply-in-shadow-root-001-ref.html27
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/styles/not-apply-in-shadow-root-001.html39
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/styles/test-001.html85
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/styles/test-003.html69
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/styles/test-005.html63
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/styles/test-008.html56
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/user-interaction/active-element/test-001.html48
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/user-interaction/active-element/test-002.html49
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/user-interaction/editing/inheritance-of-content-editable-001.html65
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/user-interaction/ranges-and-selections/test-001.html81
-rw-r--r--testing/web-platform/tests/shadow-dom/untriaged/user-interaction/ranges-and-selections/test-002.html81
101 files changed, 9541 insertions, 0 deletions
diff --git a/testing/web-platform/tests/shadow-dom/Document-prototype-adoptNode.html b/testing/web-platform/tests/shadow-dom/Document-prototype-adoptNode.html
new file mode 100644
index 000000000..e9b07d0c8
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/Document-prototype-adoptNode.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>DOM and Shadow DOM: Document.prototype.adoptNode</title>
+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+<meta name="assert" content="The adoptNode(node) method must throw a HierarchyRequestError exception if node is a shadow root.">
+<link rel="help" href="https://dom.spec.whatwg.org/#dom-document-adoptnode">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+function testAdoptNode(mode) {
+ test(function () {
+ var newDocument = document.implementation.createHTMLDocument();
+ assert_throws({'name': 'HierarchyRequestError'}, function () {
+ var element = document.createElement('div');
+ var shadowRoot = element.attachShadow({mode: mode});
+ newDocument.adoptNode(shadowRoot);
+ });
+ }, 'adoptNode on a shadow root in ' + mode + ' mode must throw a HierarchyRequestError');
+}
+
+testAdoptNode('open');
+testAdoptNode('closed');
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/Document-prototype-currentScript.html b/testing/web-platform/tests/shadow-dom/Document-prototype-currentScript.html
new file mode 100644
index 000000000..867cea979
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/Document-prototype-currentScript.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>HTML: Document.prototype.currentScript</title>
+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+<meta name="assert" content="If the script element is in a document, then set the script element's node document's currentScript attribute to the script element.">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/scripting.html#execute-the-script-block">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script id="outerScriptElement">
+
+var outerScriptElement = document.currentScript;
+
+function testInlineScript(mode)
+{
+ test(function () {
+ var host = document.createElement('div');
+ var shadowRoot = host.attachShadow({mode: mode});
+ var scriptElement = document.createElement('script');
+ scriptElement.textContent = 'assert_equals(document.currentScript, null)';
+ shadowRoot.appendChild(scriptElement);
+
+ assert_equals(document.currentScript, outerScriptElement,
+ 'document.currentScript must be set to the currently excusing script element in a document tree before executing a script in a shadow tree');
+ document.body.appendChild(host);
+ assert_equals(document.currentScript, outerScriptElement,
+ 'document.currentScript must be set to the currently excusing script element in a document tree after executing a script in a shadow tree');
+
+ }, 'document.currentScript must not to be set to a script element in a shadow tree in ' + mode + ' mode');
+}
+
+testInlineScript('open');
+testInlineScript('closed');
+
+var executeExternalScript = null;
+var testedScriptElement = null;
+function executeNextTest()
+{
+ var testCase = asyncScriptTests.shift();
+ var mode = testCase.mode;
+ if (!testCase)
+ return;
+
+ testCase.test.step(function () {
+ testedScriptElement = document.createElement('script');
+ testedScriptElement.src = 'resources/Document-prototype-currentScript-helper.js';
+
+ if (mode !== null) {
+ var host = document.createElement('div');
+ var shadowRoot = host.attachShadow({mode: mode});
+ shadowRoot.appendChild(testedScriptElement);
+ document.body.appendChild(host);
+ } else {
+ document.body.appendChild(testedScriptElement);
+ }
+
+ if (testCase.remove)
+ testedScriptElement.parentNode.removeChild(testedScriptElement);
+ });
+
+ executeExternalScript = function () {
+ testCase.test.step(function () {
+ assert_equals(document.currentScript, testCase.expected());
+ });
+ testCase.test.done();
+ setTimeout(executeNextTest, 1);
+ }
+}
+
+var asyncScriptTests = [
+ {
+ test: async_test('document.currentScript must be set to a script element that loads an external script in a document tree'),
+ mode: null, remove: false, expected: function () { return testedScriptElement; }},
+ {
+ test: async_test('document.currentScript must be set to a script element that loads an external script in a document tree'),
+ mode: null, remove: true, expected: function () { return testedScriptElement; }},
+ {
+ test: async_test('document.currentScript must not be set to a script element that loads an external script in an open shadow tree'),
+ mode: 'open', remove: false, expected: function () { return null; }},
+ {
+ test: async_test('document.currentScript must not be set to a script element that loads an external script in a closed shadow tree'),
+ mode: 'closed', remove: false, expected: function () { return null; }},
+ {
+ test: async_test('document.currentScript must be set to a script element that loads an external script that was in an open shadow tree and then removed'),
+ mode: 'open', remove: true, expected: function () { return testedScriptElement; }},
+ {
+ test: async_test('document.currentScript must be set to a script element that loads an external script that was in a closed shadow tree and then removed'),
+ mode: 'closed', remove: true, expected: function () { return testedScriptElement; }},
+];
+
+executeNextTest();
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/Document-prototype-importNode.html b/testing/web-platform/tests/shadow-dom/Document-prototype-importNode.html
new file mode 100644
index 000000000..4566e4e83
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/Document-prototype-importNode.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>DOM and Shadow DOM: Document.prototype.importNode</title>
+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+<meta name="assert" content="The importNode(node, deep) method must throw a NotSupportedError exception if node is a shadow root.">
+<link rel="help" href="https://dom.spec.whatwg.org/#dom-document-importnode">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+function testImportNode(mode) {
+ test(function () {
+ var newDocument = document.implementation.createHTMLDocument();
+ assert_throws({'name': 'NotSupportedError'}, function () {
+ var element = document.createElement('div');
+ var shadowRoot = element.attachShadow({mode: mode});
+ newDocument.importNode(shadowRoot);
+ });
+ }, 'importNode on a shadow root in ' + mode + ' mode must throw a NotSupportedError');
+}
+
+testImportNode('open');
+testImportNode('closed');
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/Element-interface-attachShadow.html b/testing/web-platform/tests/shadow-dom/Element-interface-attachShadow.html
new file mode 100644
index 000000000..6b07f7a0d
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/Element-interface-attachShadow.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Shadow DOM: Attaching a ShadowRoot</title>
+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+<meta name="assert" content="Element.prototype.attachShadow should create an instance of ShadowRoot">
+<link rel="help" href="https://w3c.github.io/webcomponents/spec/shadow/#widl-Element-attachShadow-ShadowRoot-ShadowRootInit-shadowRootInitDict">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+test(function () {
+ assert_true('attachShadow' in Element.prototype, 'Element.prototype.attachShadow must exist');
+ assert_equals(typeof(document.createElement('div').attachShadow), 'function', 'An instance of div must have attachShadow which is a function');
+}, 'Check the existence of Element.attachShadow');
+
+test(function () {
+ assert_false('attachShadow' in Node.prototype, 'Node.prototype.attachShadow must not exist');
+ assert_false('attachShadow' in CharacterData.prototype, 'CharacterData.prototype.attachShadow must not exist');
+ assert_false('attachShadow' in Comment.prototype, 'Comment.prototype.attachShadow must not exist');
+ assert_equals(typeof(document.createComment('').attachShadow), 'undefined', 'An instance of comment must not have attachShadow');
+ assert_false('attachShadow' in Document.prototype, 'Document.prototype.attachShadow must not exist');
+ assert_equals(typeof(document.attachShadow), 'undefined', 'An instance of document must not have attachShadow which is a function');
+ assert_false('attachShadow' in DocumentFragment.prototype, 'DocumentFragment.prototype.attachShadow must not exist');
+ assert_equals(typeof((new DOMParser()).parseFromString('', 'text/html').attachShadow), 'undefined', 'An instance of document must not have attachShadow which is a function');
+ assert_false('attachShadow' in Text.prototype, 'Text.prototype.attachShadow must not exist');
+ assert_equals(typeof(document.createTextNode('').attachShadow), 'undefined', 'An instance of text node must not have attachShadow');
+}, 'Nodes other than Element should not have attachShadow');
+
+test(function () {
+ assert_throws({'name': 'TypeError'}, function () {
+ document.createElement('div').attachShadow({})
+ }, 'attachShadow must throw a TypeError when mode is omitted');
+
+ assert_throws({'name': 'TypeError'}, function () {
+ document.createElement('div').attachShadow({mode: true})
+ }, 'attachShadow must throw a TypeError when mode is a boolean');
+
+ assert_throws({'name': 'TypeError'}, function () {
+ document.createElement('div').attachShadow({mode: 1})
+ }, 'attachShadow must throw a TypeError when mode is 1');
+}, 'Element.attachShadow must throw a TypeError if mode is not "open" or "closed"');
+
+test(function () {
+ assert_true(document.createElement('div').attachShadow({mode: "open"}) instanceof ShadowRoot,
+ 'attachShadow({mode: "open"}) should create an instance of ShadowRoot');
+ assert_true(document.createElement('div').attachShadow({mode: "closed"}) instanceof ShadowRoot,
+ 'attachShadow({mode: "closed"}) should create an instance of ShadowRoot');
+}, 'Element.attachShadow must create an instance of ShadowRoot');
+
+test(function () {
+ assert_throws({'name': 'InvalidStateError'}, function () {
+ var div = document.createElement('div');
+ div.attachShadow({mode: "open"});
+ div.attachShadow({mode: "open"});
+ }, 'Calling attachShadow({mode: "open"}) twice on the same element must throw');
+
+ assert_throws({'name': 'InvalidStateError'}, function () {
+ var div = document.createElement('div');
+ div.attachShadow({mode: "closed"});
+ div.attachShadow({mode: "closed"});
+ }, 'Calling attachShadow({mode: "closed"}) twice on the same element must throw');
+
+ assert_throws({'name': 'InvalidStateError'}, function () {
+ var div = document.createElement('div');
+ div.attachShadow({mode: "open"});
+ div.attachShadow({mode: "closed"});
+ }, 'Calling attachShadow({mode: "closed"}) after attachShadow({mode: "open"}) on the same element must throw');
+
+ assert_throws({'name': 'InvalidStateError'}, function () {
+ var div = document.createElement('div');
+ div.attachShadow({mode: "closed"});
+ div.attachShadow({mode: "open"});
+ }, 'Calling attachShadow({mode: "open"}) after attachShadow({mode: "closed"}) on the same element must throw');
+}, 'Element.attachShadow must throw a InvalidStateError if the context object already hosts a shadow tree');
+
+test(function () {
+ for (var elementName of ['button', 'details', 'input', 'marquee', 'meter', 'progress', 'select', 'textarea', 'keygen']) {
+ assert_throws({'name': 'NotSupportedError'}, function () {
+ document.createElement(elementName).attachShadow({mode: "open"});
+ }, 'Calling attachShadow({mode: "open"}) on ' + elementName + ' element must throw');
+
+ assert_throws({'name': 'NotSupportedError'}, function () {
+ document.createElement(elementName).attachShadow({mode: "closed"});
+ }, 'Calling attachShadow({mode: "closed"}) on ' + elementName + ' element must throw');
+ }
+}, 'Element.attachShadow must throw a NotSupportedError for button, details, input, marquee, meter, progress, select, textarea, and keygen elements');
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/Element-interface-shadowRoot-attribute.html b/testing/web-platform/tests/shadow-dom/Element-interface-shadowRoot-attribute.html
new file mode 100644
index 000000000..02d805099
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/Element-interface-shadowRoot-attribute.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Shadow DOM: Element interface shadowRoot attribute</title>
+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+<meta name="assert" content="shadowRoot attribute on Element interface must return the associated open shadow tree if there is one">
+<link rel="help" href="https://w3c.github.io/webcomponents/spec/shadow/#the-shadowroot-interface">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+test(function () {
+ assert_true('shadowRoot' in Element.prototype, 'shadowRoot must be defined on Element prototype');
+ assert_true('shadowRoot' in document.createElement('div'), 'shadowRoot must be defined on an instance of div element');
+ assert_false('shadowRoot' in Node.prototype, 'shadowRoot must not be defined on Node prototype');
+ assert_false('shadowRoot' in Text.prototype, 'shadowRoot must not be defined on Text prototype');
+ assert_false('shadowRoot' in document.createTextNode(''), 'shadowRoot must not be defined on an instance of Text node');
+ assert_false('shadowRoot' in Comment.prototype, 'shadowRoot must not be defined on Comment prototype');
+ assert_false('shadowRoot' in document.createComment(''), 'shadowRoot must not be defined on an instance of Comment node');
+ assert_false('shadowRoot' in Document.prototype, 'shadowRoot must not be defined on Document prototype');
+ assert_false('shadowRoot' in document, 'shadowRoot must not be defined on an instance of Document');
+ assert_false('shadowRoot' in DocumentFragment.prototype, 'shadowRoot must not be defined on DocumentFragment prototype');
+ assert_false('shadowRoot' in (new DOMParser).parseFromString('', 'text/html'), 'shadowRoot must not be defined on an instance of DocumentFragment node');
+}, 'shadowRoot must be defined on Element prototype');
+
+test(function () {
+ var host = document.createElement('div');
+ assert_equals(host.shadowRoot, null, 'shadowRoot must return null when the host does not have a shadow tree attached to it');
+
+ var openShadowRoot = host.attachShadow({mode: 'open'});
+ assert_equals(host.shadowRoot, openShadowRoot, 'shadowRoot must return the open shadow root attachShadow attached');
+}, 'shadowRoot attribute must return the open shadow root associated with the element');
+
+test(function () {
+ var host = document.createElement('div');
+ host.attachShadow({mode: 'closed'});
+ assert_equals(host.shadowRoot, null);
+}, 'shadowRoot attribute must return null if the shadow root attached to the element is closed');
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/Extensions-to-Event-Interface.html b/testing/web-platform/tests/shadow-dom/Extensions-to-Event-Interface.html
new file mode 100644
index 000000000..4d4afaf65
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/Extensions-to-Event-Interface.html
@@ -0,0 +1,234 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Shadow DOM: Extensions to Event Interface</title>
+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+<meta name="assert" content="Event interface must have composedPath() as a method">
+<link rel="help" href="http://w3c.github.io/webcomponents/spec/shadow/#extensions-to-event-interface">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/event-path-test-helpers.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+test(function () {
+ assert_true('composedPath' in Event.prototype);
+ assert_true('composedPath' in new Event('my-event'));
+}, 'composedPath() must exist on Event');
+
+test(function () {
+ var event = new Event('my-event');
+ assert_array_equals(event.composedPath(), []);
+}, 'composedPath() must return an empty array when the event has not been dispatched');
+
+test(function () {
+ var event = new Event('my-event');
+ document.body.dispatchEvent(event);
+ assert_array_equals(event.composedPath(), []);
+}, 'composedPath() must return an empty array when the event is no longer dispatched');
+
+test(function () {
+ assert_true('composed' in Event.prototype);
+ assert_true('composed' in new Event('my-event'));
+}, 'composed must exist on Event');
+
+test(function () {
+ var event = new Event('my-event');
+ assert_false(event.composed);
+}, 'composed on EventInit must default to false');
+
+test(function () {
+ var event = new Event('my-event', {composed: true});
+ assert_true(event.composed);
+
+ event = new Event('my-event', {composed: false});
+ assert_false(event.composed);
+}, 'composed on EventInit must set the composed flag');
+
+/*
+-SR: ShadowRoot -S: Slot target: (~) *: indicates start digit: event path order
+A (4) --------------------------- A-SR (3)
++ B ------------ B-SR + A1 (2) --- A1-SR (1)
+ + C + B1 --- B1-SR + A2-S + A1a (*; 0)
+ + D --- D-SR + B1a + B1b --- B1b-SR
+ + D1 + B1c-S + B1b1
+ + B1b2
+*/
+
+function testComposedEvent(mode) {
+ test(function () {
+ var nodes = createTestTree(mode);
+ var log = dispatchEventWithLog(nodes, nodes.A1a, new Event('my-event', {composed: true, bubbles: true}));
+
+ var expectedPath = ['A1a', 'A1-SR', 'A1', 'A-SR', 'A'];
+ assert_array_equals(log.eventPath, expectedPath);
+ assert_array_equals(log.eventPath.length, log.pathAtTargets.length);
+ assert_array_equals(log.pathAtTargets[0], expectedPath);
+ assert_array_equals(log.pathAtTargets[1], expectedPath);
+ assert_array_equals(log.pathAtTargets[2], mode == 'open' ? expectedPath : ['A1', 'A-SR', 'A'],
+ 'composedPath must only contain unclosed nodes of the current target.');
+ }, 'The event must propagate out of ' + mode + ' mode shadow boundaries when the composed flag is set');
+}
+
+testComposedEvent('open');
+testComposedEvent('closed');
+
+/*
+-SR: ShadowRoot -S: Slot target: (~) *: indicates start digit: event path order
+A ------------------------------- A-SR
++ B ------------ B-SR + A1 --- A1-SR (1)
+ + C + B1 --- B1-SR + A2-S + A1a (*; 0)
+ + D --- D-SR + B1a + B1b --- B1b-SR
+ + D1 + B1c-S + B1b1
+ + B1b2
+*/
+
+function testNonComposedEvent(mode) {
+ test(function () {
+ var nodes = createTestTree(mode);
+ var log = dispatchEventWithLog(nodes, nodes.A1a, new Event('my-event', {composed: false, bubbles: true}));
+
+ var expectedPath = ['A1a', 'A1-SR'];
+ assert_array_equals(log.eventPath, expectedPath);
+ assert_array_equals(log.eventPath.length, log.pathAtTargets.length);
+ assert_array_equals(log.pathAtTargets[0], expectedPath);
+ assert_array_equals(log.pathAtTargets[1], expectedPath);
+ }, 'The event must not propagate out of ' + mode + ' mode shadow boundaries when the composed flag is unset');
+}
+
+testNonComposedEvent('open');
+testNonComposedEvent('closed');
+
+/*
+-SR: ShadowRoot -S: Slot target: (~) relatedTarget: [~] *: indicates start digit: event path order
+A ------------------------------- A-SR
++ B ------------ B-SR + A1 ----------- A1-SR (1)
+ + C + B1 --- B1-SR + A2-S [*; 0-1] + A1a (*; 0)
+ + D --- D-SR + B1a + B1b --- B1b-SR
+ + D1 + B1c-S + B1b1
+ + B1b2
+*/
+
+function testNonComposedEventWithRelatedTarget(mode) {
+ test(function () {
+ var nodes = createTestTree(mode);
+ var log = dispatchEventWithLog(nodes, nodes.A1a, new MouseEvent('foo', {composed: false, bubbles: true, relatedTarget: nodes['A2-S']}));
+
+ var expectedPath = ['A1a', 'A1-SR'];
+ assert_array_equals(log.eventPath, expectedPath);
+ assert_array_equals(log.eventPath.length, log.pathAtTargets.length);
+ assert_array_equals(log.pathAtTargets[0], expectedPath);
+ assert_array_equals(log.pathAtTargets[1], expectedPath);
+ assert_array_equals(log.relatedTargets, ['A2-S', 'A2-S']);
+ }, 'The event must not propagate out of ' + mode + ' mode shadow boundaries when the composed flag is unset on an event with relatedTarget');
+}
+
+testNonComposedEventWithRelatedTarget('open');
+testNonComposedEventWithRelatedTarget('closed');
+
+/*
+-SR: ShadowRoot -S: Slot target: (~) relatedTarget: [~] *: indicates start digit: event path order
+A ------------------------------------------------ A-SR
++ B ------------ B-SR (4) + A1 --- A1-SR
+ + C + B1 (3) [0,3-4] --- B1-SR (2) + A2-S + A1a
+ + D --- D-SR + B1a (*; 0) + B1b [1-2] --- B1b-SR
+ + D1 + B1c-S (1) + B1b1
+ + B1b2 [*]
+*/
+
+function testScopedEventWithUnscopedRelatedTargetThroughSlot(mode) {
+ test(function () {
+ var nodes = createTestTree(mode);
+ var log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {scoped: true, relatedTargetScoped: false, bubbles: true, relatedTarget: nodes['B1b2']}));
+
+ var expectedPath = ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR'];
+ var pathExposedToB1a = ['B1a', 'B1', 'B-SR'];
+ assert_array_equals(log.eventPath, expectedPath);
+ assert_array_equals(log.eventPath.length, log.pathAtTargets.length);
+ assert_array_equals(log.pathAtTargets[0], mode == 'open' ? expectedPath : pathExposedToB1a);
+ assert_array_equals(log.pathAtTargets[1], expectedPath);
+ assert_array_equals(log.pathAtTargets[2], expectedPath);
+ assert_array_equals(log.pathAtTargets[3], mode == 'open' ? expectedPath : pathExposedToB1a);
+ assert_array_equals(log.pathAtTargets[4], mode == 'open' ? expectedPath : pathExposedToB1a);
+ assert_array_equals(log.relatedTargets, ['B1', 'B1b', 'B1b', 'B1', 'B1']);
+ }, 'The event must not propagate out of ' + mode + ' mode shadow tree of the target but must propagate out of inner shadow trees when the scoped flag is set');
+}
+
+testScopedEventWithUnscopedRelatedTargetThroughSlot('open');
+testScopedEventWithUnscopedRelatedTargetThroughSlot('closed');
+
+/*
+-SR: ShadowRoot -S: Slot target: (~) relatedTarget: [~] *: indicates start digit: event path order
+A ------------------------------- A-SR (3)
++ B ------------ B-SR + A1 (2) ------- A1-SR (1)
+ + C + B1 --- B1-SR + A2-S [*; 0-3] + A1a (*; 0)
+ + D --- D-SR + B1a + B1b --- B1b-SR
+ + D1 + B1c-S + B1b1
+ + B1b2
+*/
+
+function testComposedEventWithRelatedTarget(mode) {
+ test(function () {
+ var nodes = createTestTree(mode);
+ log = dispatchEventWithLog(nodes, nodes.A1a, new MouseEvent('foo', {composed: true, bubbles: true, relatedTarget: nodes['A2-S']}));
+
+ var expectedPath = ['A1a', 'A1-SR', 'A1', 'A-SR'];
+ var pathExposedToA1 = ['A1', 'A-SR'];
+ assert_array_equals(log.eventPath, expectedPath);
+ assert_array_equals(log.eventPath.length, log.pathAtTargets.length);
+ assert_array_equals(log.pathAtTargets[0], expectedPath);
+ assert_array_equals(log.pathAtTargets[1], expectedPath);
+ assert_array_equals(log.pathAtTargets[2], mode == 'open' ? expectedPath : pathExposedToA1);
+ assert_array_equals(log.pathAtTargets[3], mode == 'open' ? expectedPath : pathExposedToA1);
+ assert_array_equals(log.relatedTargets, ['A2-S', 'A2-S', 'A2-S', 'A2-S']);
+ }, 'The event must propagate out of ' + mode + ' mode shadow tree in which the relative target and the relative related target are the same');
+}
+
+testComposedEventWithRelatedTarget('open');
+testComposedEventWithRelatedTarget('closed');
+
+/*
+-SR: ShadowRoot -S: Slot target: (~) relatedTarget: [~] *: indicates start digit: event path order
+A (8) [0-5,8] ---------------------------------------- A-SR (7)
++ B (5) ------- B-SR (4) + A1 [6,7] --- A1-SR
+ + C + B1 (3) ------- B1-SR (2) + A2-S (6) + A1a [*]
+ + D --- D-SR + B1a (*; 0) + B1b ------- B1b-SR
+ + D1 + B1c-S (1) + B1b1
+ + B1b2
+*/
+
+function testComposedEventThroughSlot(mode) {
+ test(function () {
+ var nodes = createTestTree(mode);
+ log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {composed: true, bubbles: true, relatedTarget: nodes.A1a}));
+
+ var expectedPath = ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR', 'B', 'A2-S', 'A-SR', 'A'];
+ var expectedRelatedTarget = ['A', 'A', 'A', 'A', 'A', 'A', 'A1', 'A1', 'A'];
+ var pathExposedToB1a = ['B1a', 'B1', 'B-SR', 'B', 'A'];
+ var pathExposedToB1cS = ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR', 'B', 'A'];
+ var pathExposedToB = [ 'B', 'A'];
+ var pathExposedToA1 = [ 'B', 'A2-S', 'A-SR', 'A'];
+
+ assert_array_equals(log.eventPath, expectedPath);
+ assert_array_equals(log.eventPath.length, log.pathAtTargets.length);
+ assert_array_equals(log.pathAtTargets[0], mode == 'open' ? expectedPath : pathExposedToB1a);
+ assert_array_equals(log.pathAtTargets[1], mode == 'open' ? expectedPath : pathExposedToB1cS);
+ assert_array_equals(log.pathAtTargets[2], mode == 'open' ? expectedPath : pathExposedToB1cS);
+ assert_array_equals(log.pathAtTargets[3], mode == 'open' ? expectedPath : pathExposedToB1a);
+ assert_array_equals(log.pathAtTargets[4], mode == 'open' ? expectedPath : pathExposedToB1a);
+ assert_array_equals(log.pathAtTargets[5], mode == 'open' ? expectedPath : pathExposedToB);
+ assert_array_equals(log.pathAtTargets[6], mode == 'open' ? expectedPath : pathExposedToA1);
+ assert_array_equals(log.pathAtTargets[7], mode == 'open' ? expectedPath : pathExposedToA1);
+ assert_array_equals(log.pathAtTargets[8], mode == 'open' ? expectedPath : pathExposedToB);
+ assert_array_equals(log.relatedTargets, expectedRelatedTarget);
+ }, 'composedPath() must contain and only contain the unclosed nodes of target in ' + mode + ' mode shadow trees');
+}
+
+testComposedEventThroughSlot('open');
+testComposedEventThroughSlot('closed');
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/HTMLSlotElement-interface.html b/testing/web-platform/tests/shadow-dom/HTMLSlotElement-interface.html
new file mode 100644
index 000000000..a9ab4661b
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/HTMLSlotElement-interface.html
@@ -0,0 +1,269 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Shadow DOM: HTMLSlotElement interface</title>
+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+<meta name="assert" content="HTMLSlotElement must exist on window with name attribute and getAssignedNode() method">
+<link rel="help" href="https://w3c.github.io/webcomponents/spec/shadow/#the-slot-element">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+test(function () {
+ assert_true('HTMLSlotElement' in window, 'HTMLSlotElement must be defined on window');
+ assert_equals(HTMLSlotElement.prototype.__proto__, HTMLElement.prototype, 'HTMLSlotElement should inherit from HTMLElement');
+ assert_true(document.createElement('slot') instanceof HTMLSlotElement, 'slot element should be an instance of HTMLSlotElement');
+ assert_true(document.createElement('slot') instanceof HTMLElement, 'slot element should be an instance of HTMLElement');
+}, 'HTMLSlotElement must be defined on window');
+
+test(function () {
+ assert_true('name' in HTMLSlotElement.prototype, '"name" attribute must be defined on HTMLSlotElement.prototype');
+
+ var slotElement = document.createElement('slot');
+ assert_equals(slotElement.name, '', '"name" attribute must return the empty string when "name" content attribute is not set');
+
+ slotElement.setAttribute('name', 'foo');
+ assert_equals(slotElement.name, 'foo', '"name" attribute must return the value of the "name" content attribute');
+
+ slotElement.name = 'bar';
+ assert_equals(slotElement.name, 'bar', '"name" attribute must return the assigned value');
+ assert_equals(slotElement.getAttribute('name'), 'bar', '"name" attribute must update the "name" content attribute');
+}, '"name" attribute on HTMLSlotElement must reflect "name" attribute');
+
+function testSlotOutsideShadowTree(options)
+{
+ test(function () {
+ assert_true('assignedNodes' in HTMLSlotElement.prototype, '"assignedNodes" method must be defined on HTMLSlotElement.prototype');
+
+ var slotElement = document.createElement('slot');
+ assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes() must return an empty array when the slot element is not in any tree');
+
+ document.body.appendChild(slotElement);
+ assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes() must return an empty array when the slot element is in a document tree');
+
+ }, 'assignedNodes(' + (options ? JSON.stringify(options) : '')
+ + ') on a HTMLSlotElement must return an empty array when the slot element is not in a tree or in a document tree');
+}
+
+testSlotOutsideShadowTree(null);
+testSlotOutsideShadowTree({flattened: false});
+testSlotOutsideShadowTree({flattened: true});
+
+function testSingleLevelOfSlotting(options)
+{
+ test(function () {
+ assert_true('assignedNodes' in HTMLSlotElement.prototype, '"assignedNodes" method must be defined on HTMLSlotElement.prototype');
+
+ var shadowHost = document.createElement('div');
+ var child = document.createElement('p');
+
+ var shadowRoot = shadowHost.attachShadow({mode: 'open'});
+ var slotElement = document.createElement('slot');
+ shadowRoot.appendChild(slotElement);
+
+ assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes() must return an empty array when there are no nodes in the shadow tree');
+
+ shadowHost.appendChild(child);
+ assert_array_equals(slotElement.assignedNodes(options), [child], 'assignedNodes() on a default slot must return an element without slot element');
+
+ child.setAttribute('slot', 'foo');
+ assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes() on a default slot must not return an element with non-empty slot attribute');
+
+ child.setAttribute('slot', '');
+ assert_array_equals(slotElement.assignedNodes(options), [child], 'assignedNodes() on a default slot must return an element with empty slot attribute');
+
+ slotElement.setAttribute('name', 'bar');
+ assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes() on a named slot must not return an element with empty slot attribute');
+
+ slotElement.setAttribute('name', '');
+ assert_array_equals(slotElement.assignedNodes(options), [child], 'assignedNodes() on an empty name slot must return an element with empty slot attribute');
+
+ }, 'assignedNodes(' + (options ? JSON.stringify(options) : '') + ') must return the list of assigned nodes when none of the assigned nodes themselves are slots');
+}
+
+testSingleLevelOfSlotting(null);
+testSingleLevelOfSlotting({flattened: false});
+testSingleLevelOfSlotting({flattened: true});
+
+function testMutatingSlottedContents(options)
+{
+ test(function () {
+ var shadowHost = document.createElement('div');
+ var p = document.createElement('p');
+ var b = document.createElement('b');
+ shadowHost.appendChild(p);
+ shadowHost.appendChild(b);
+
+ var shadowRoot = shadowHost.attachShadow({mode: 'open'});
+ var slotElement = document.createElement('slot');
+ shadowRoot.appendChild(slotElement);
+
+ assert_array_equals(slotElement.assignedNodes(options), [p, b], 'assignedNodes must return the distributed nodes');
+
+ slotElement.name = 'foo';
+ assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes must be empty when there are no matching elements for the slot name');
+
+ b.slot = 'foo';
+ assert_array_equals(slotElement.assignedNodes(options), [b], 'assignedNodes must return the nodes with the matching slot name');
+
+ p.slot = 'foo';
+ assert_array_equals(slotElement.assignedNodes(options), [p, b], 'assignedNodes must return the nodes with the matching slot name in the tree order');
+
+ slotElement.removeAttribute('name');
+ assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes must be empty for a default slot when all elements have "slot" attributes specified');
+
+ }, 'assignedNodes(' + (options ? JSON.stringify(options) : '') + ') must update when slot and name attributes are modified');
+}
+
+testMutatingSlottedContents(null);
+testMutatingSlottedContents({flattened: false});
+testMutatingSlottedContents({flattened: true});
+
+function testMutatingSlotName(options)
+{
+ test(function () {
+ var shadowHost = document.createElement('div');
+ var child = document.createElement('span');
+ shadowHost.appendChild(child);
+
+ var shadowRoot = shadowHost.attachShadow({mode: 'open'});
+ var slotElement = document.createElement('slot');
+ slotElement.name = 'foo';
+ shadowRoot.appendChild(slotElement);
+
+ assert_array_equals(slotElement.assignedNodes(options), [], 'assignedNodes must be empty when there are no matching elements for the slot name');
+
+ slotElement.removeAttribute('name');
+ assert_array_equals(slotElement.assignedNodes(options), [child], 'assignedNodes must be empty when there are no matching elements for the slot name');
+
+ }, 'assignedNodes must update when a default slot is introduced dynamically by a slot rename');
+}
+
+testMutatingSlotName(null);
+testMutatingSlotName({flattened: false});
+testMutatingSlotName({flattened: true});
+
+function testInsertingAndRemovingSlots(options)
+{
+ test(function () {
+ var shadowHost = document.createElement('div');
+ var p = document.createElement('p');
+ var text = document.createTextNode('');
+ var comment = document.createComment('');
+ var processingInstruction = document.createProcessingInstruction('target', 'data');
+ var b = document.createElement('b');
+ shadowHost.appendChild(p);
+ shadowHost.appendChild(text);
+ shadowHost.appendChild(comment);
+ shadowHost.appendChild(processingInstruction);
+ shadowHost.appendChild(b);
+
+ var shadowRoot = shadowHost.attachShadow({mode: 'open'});
+
+ var firstSlotElement = document.createElement('slot');
+ shadowRoot.appendChild(firstSlotElement);
+
+ var secondSlotElement = document.createElement('slot');
+ shadowRoot.appendChild(secondSlotElement);
+
+ assert_array_equals(firstSlotElement.assignedNodes(options), [p, text, b],
+ 'assignedNodes on a default slot must return the elements without slot attributes and text nodes');
+ assert_array_equals(secondSlotElement.assignedNodes(options), [],
+ 'assignedNodes on the second unnamed slot element must return an empty array');
+
+ shadowRoot.removeChild(firstSlotElement);
+ assert_array_equals(firstSlotElement.assignedNodes(options), [],
+ 'assignedNodes on a detached formerly-default slot must return an empty array');
+ assert_array_equals(secondSlotElement.assignedNodes(options), [p, text, b],
+ 'assignedNodes on the second unnamed slot element after removing the first must return the elements without slot attributes and text nodes');
+
+ shadowRoot.removeChild(secondSlotElement);
+ shadowRoot.appendChild(secondSlotElement);
+ assert_array_equals(firstSlotElement.assignedNodes(options), [],
+ 'Removing and re-inserting a default slot must not change the result of assignedNodes on a detached slot');
+ assert_array_equals(secondSlotElement.assignedNodes(options), [p, text, b],
+ 'Removing and re-inserting a default slot must not change the result of assignedNodes');
+
+ shadowRoot.insertBefore(firstSlotElement, secondSlotElement);
+ assert_array_equals(firstSlotElement.assignedNodes(options), [p, text, b],
+ 'assignedNodes on a newly inserted unnamed slot element must return the elements without slot attributes and text nodes');
+ assert_array_equals(secondSlotElement.assignedNodes(options), [],
+ 'assignedNodes on formerly-first but now second unnamed slot element must return an empty array');
+
+ }, 'assignedNodes must update when slot elements are inserted or removed');
+}
+
+testInsertingAndRemovingSlots(null);
+testInsertingAndRemovingSlots({flattened: false});
+testInsertingAndRemovingSlots({flattened: true});
+
+test(function () {
+ var outerHost = document.createElement('div');
+ var outerChild = document.createElement('span');
+ outerHost.appendChild(outerChild);
+
+ var outerShadow = outerHost.attachShadow({mode: 'closed'});
+ var innerHost = document.createElement('div');
+ var outerSlot = document.createElement('slot');
+ var innerChild = document.createElement('b');
+ outerShadow.appendChild(innerHost);
+ innerHost.appendChild(outerSlot);
+ innerHost.appendChild(innerChild);
+
+ var innerShadow = innerHost.attachShadow({mode: 'closed'});
+ var innerSlot = document.createElement('slot');
+ innerShadow.appendChild(innerSlot);
+
+ assert_array_equals(outerSlot.assignedNodes(), [outerChild], 'assignedNodes() on a default slot must return the assigned nodes');
+ assert_array_equals(outerSlot.assignedNodes({flatten: false}), [outerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes');
+ assert_array_equals(outerSlot.assignedNodes({flatten: true}), [outerChild], 'assignedNodes({flatten: true}) on a default slot must return the assigned nodes if they are not themselves slots');
+
+ assert_array_equals(innerSlot.assignedNodes(), [outerSlot, innerChild], 'assignedNodes() on a default slot must return the assigned nodes');
+ assert_array_equals(innerSlot.assignedNodes({flatten: false}), [outerSlot, innerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes');
+ assert_array_equals(innerSlot.assignedNodes({flatten: true}), [outerChild, innerChild], 'assignedNodes({flatten: true}) on a default slot must return the distributed nodes');
+
+ outerSlot.name = 'foo';
+ assert_array_equals(outerSlot.assignedNodes(), [], 'assignedNodes() on a named slot must return an empty array if there are no matching elements');
+ assert_array_equals(outerSlot.assignedNodes({flatten: false}), [], 'assignedNodes({flatten: false}) on a named slot must return an empty array if there are no matching elements');
+ assert_array_equals(outerSlot.assignedNodes({flatten: true}), [], 'assignedNodes({flatten: true}) on a named slot must return an empty array if there are no matching elements');
+
+ assert_array_equals(innerSlot.assignedNodes(), [outerSlot, innerChild], 'assignedNodes() on a default slot must return the assigned nodes');
+ assert_array_equals(innerSlot.assignedNodes({flatten: false}), [outerSlot, innerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes');
+ assert_array_equals(innerSlot.assignedNodes({flatten: true}), [innerChild], 'assignedNodes({flatten: true}) on a default slot must return the distributed nodes');
+
+ outerChild.slot = 'foo';
+ assert_array_equals(outerSlot.assignedNodes(), [outerChild], 'assignedNodes() on a named slot must return matching elements');
+ assert_array_equals(outerSlot.assignedNodes({flatten: false}), [outerChild], 'assignedNodes({flatten: false}) on a named slot must return matching elements');
+ assert_array_equals(outerSlot.assignedNodes({flatten: true}), [outerChild], 'assignedNodes({flatten: true}) on a named slot must return matching elements');
+
+ assert_array_equals(innerSlot.assignedNodes(), [outerSlot, innerChild], 'assignedNodes() on a default slot must return the assigned nodes');
+ assert_array_equals(innerSlot.assignedNodes({flatten: false}), [outerSlot, innerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes');
+ assert_array_equals(innerSlot.assignedNodes({flatten: true}), [outerChild, innerChild], 'assignedNodes({flatten: true}) on a default slot must return the distributed nodes');
+
+ var newInnerSlot = document.createElement('slot');
+ innerShadow.insertBefore(newInnerSlot, innerSlot);
+ assert_array_equals(newInnerSlot.assignedNodes(), [outerSlot, innerChild], 'assignedNodes() on a default slot must return the assigned nodes');
+ assert_array_equals(newInnerSlot.assignedNodes({flatten: false}), [outerSlot, innerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes');
+ assert_array_equals(newInnerSlot.assignedNodes({flatten: true}), [outerChild, innerChild], 'assignedNodes({flatten: true}) on a default slot must return the distributed nodes');
+
+ assert_array_equals(innerSlot.assignedNodes(), [], 'assignedNodes() on a nameless slot element which appears after a default slot must return an empty array');
+ assert_array_equals(innerSlot.assignedNodes({flatten: false}), [], 'assignedNodes({flatten: false}) on a nameless slot element which appears after a default slot must return an empty array');
+ assert_array_equals(innerSlot.assignedNodes({flatten: true}), [], 'assignedNodes({flatten: true}) on a nameless slot element which appears after a default slot must return an empty array');
+
+ innerShadow.removeChild(newInnerSlot);
+ assert_array_equals(newInnerSlot.assignedNodes(), [], 'assignedNodes() must return an empty array when the slot element is not in any tree');
+ assert_array_equals(newInnerSlot.assignedNodes({flatten: false}), [], 'assignedNodes({flatten: false}) must return an empty array when the slot element is not in any tree');
+ assert_array_equals(newInnerSlot.assignedNodes({flatten: true}), [], 'assignedNodes({flatten: true}) must return an empty array when the slot element is not in any tree');
+
+ assert_array_equals(innerSlot.assignedNodes(), [outerSlot, innerChild], 'assignedNodes() on a default slot must return the assigned nodes');
+ assert_array_equals(innerSlot.assignedNodes({flatten: false}), [outerSlot, innerChild], 'assignedNodes({flatten: false}) on a default slot must return the assigned nodes');
+ assert_array_equals(innerSlot.assignedNodes({flatten: true}), [outerChild, innerChild], 'assignedNodes({flatten: true}) on a default slot must return the distributed nodes');
+
+}, 'assignedNodes({flatten: true}) must return the distributed nodes, and assignedNodes() and assignedNodes({flatten: false}) must returned the assigned nodes');
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/MouseEvent-prototype-offsetX-offsetY.html b/testing/web-platform/tests/shadow-dom/MouseEvent-prototype-offsetX-offsetY.html
new file mode 100644
index 000000000..643736b85
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/MouseEvent-prototype-offsetX-offsetY.html
@@ -0,0 +1,154 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Shadow DOM: MouseEvent's offsetX and offsetY attributes must be relative to the relative target.</title>
+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+<meta name="assert" content="The MouseEvent offsetX and offsetY attributes must return the coordinates relative to the origin of the padding edge of the relative target">
+<link rel="help" href="http://w3c.github.io/webcomponents/spec/shadow/#event-dispatch">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/event-path-test-helpers.js"></script>
+</head>
+<body>
+<style>
+html, body { padding: 0; margin: 0; }
+my-host { display: block; width: 180px; height: 80px; margin: 10px 20px; padding: 10px; background: #ccc; }
+#log { margin: 1rem; }
+</style>
+<my-host></my-host>
+<div id="log"></div>
+<script>
+
+var shadowStyle = '#container { width: 160px; height: 60px; padding: 10px; background: yellow; } #target { margin-left: 5px; background: orange; }';
+var host = document.querySelector('my-host');
+
+function attachLoggers(targets)
+{
+ var eventLogs = [];
+ for (var i = 0; i < targets.length; i++) {
+ targets[i].addEventListener('mousedown', function (event) {
+ eventLogs.push({current: this, target: event.target, offsetX: event.offsetX, offsetY: event.offsetY});
+ });
+ }
+ return eventLogs;
+}
+
+test(function () {
+ host.innerHTML = '<style>' + shadowStyle + '</style><div id="container"><span id="target">Click here</div></div>';
+
+ var target = host.querySelector('#target');
+ var container = host.querySelector('#container');
+
+ var eventLogs = attachLoggers([target, container, host, document.body]);
+ var mouseEvent = new MouseEvent('mousedown', {clientX: 51, clientY: 37, composed: true, bubbles: true});
+ target.dispatchEvent(mouseEvent);
+
+ assert_equals(host.offsetLeft, 20, 'The host must be at (20px, 10px)');
+ assert_equals(host.offsetTop, 10, 'The host must be at (20px, 10px)');
+ assert_equals(target.offsetLeft, 45, 'The target must be at (45px, 30px)');
+ assert_equals(target.offsetTop, 30, 'The target must be at (45px, 30px)');
+
+ assert_equals(eventLogs[0].current, target);
+ assert_equals(eventLogs[0].target, target);
+ assert_equals(eventLogs[0].offsetX, 21); // Padding edge of target is at (30px, 20px)
+ assert_equals(eventLogs[0].offsetY, 17);
+
+ assert_equals(eventLogs[1].current, container);
+ assert_equals(eventLogs[1].target, target);
+ assert_equals(eventLogs[1].offsetX, 21);
+ assert_equals(eventLogs[1].offsetY, 17);
+
+ assert_equals(eventLogs[2].current, host);
+ assert_equals(eventLogs[2].target, target);
+ assert_equals(eventLogs[2].offsetX, 21);
+ assert_equals(eventLogs[2].offsetY, 17);
+
+ assert_equals(eventLogs[3].current, document.body);
+ assert_equals(eventLogs[3].target, target);
+ assert_equals(eventLogs[3].offsetX, 21);
+ assert_equals(eventLogs[3].offsetY, 17);
+}, 'MouseEvent\'s offsetX and offsetY attributes must be relative to the target.');
+
+var shadowRoot = host.attachShadow({mode: 'closed'});
+test(function () {
+ shadowRoot.innerHTML = '<style>' + shadowStyle + '</style><div id="container"><span id="target">Click here</div></div>';
+
+ var target = shadowRoot.querySelector('#target');
+ var container = shadowRoot.querySelector('#container');
+
+ var eventLogs = attachLoggers([target, container, shadowRoot, host, document.body]);
+ var mouseEvent = new MouseEvent('mousedown', {clientX: 51, clientY: 37, composed: true, bubbles: true});
+ target.dispatchEvent(mouseEvent);
+
+ assert_equals(host.offsetLeft, 20, 'The host must be at (20px, 10px)');
+ assert_equals(host.offsetTop, 10, 'The host must be at (20px, 10px)');
+ assert_equals(target.offsetLeft, 45, 'The target must be at (45px, 30px)');
+ assert_equals(target.offsetTop, 30, 'The target must be at (45px, 30px)');
+
+ assert_equals(eventLogs[0].current, target);
+ assert_equals(eventLogs[0].target, target);
+ assert_equals(eventLogs[0].offsetX, 21); // Padding edge of target is at (30px, 20px)
+ assert_equals(eventLogs[0].offsetY, 17);
+
+ assert_equals(eventLogs[1].current, container);
+ assert_equals(eventLogs[1].target, target);
+ assert_equals(eventLogs[1].offsetX, 21);
+ assert_equals(eventLogs[1].offsetY, 17);
+
+ assert_equals(eventLogs[3].current, host);
+ assert_equals(eventLogs[3].target, host);
+ assert_equals(eventLogs[3].offsetX, 31); // Padding edge of host is at (20px, 10px)
+ assert_equals(eventLogs[3].offsetY, 27);
+
+ assert_equals(eventLogs[4].current, document.body);
+ assert_equals(eventLogs[4].target, host);
+ assert_equals(eventLogs[4].offsetX, 31);
+ assert_equals(eventLogs[4].offsetY, 27);
+}, 'MouseEvent\'s offsetX and offsetY attributes must be relative to the shadow host when an event is dispatched inside its shadow tree.');
+
+test(function () {
+ shadowRoot.innerHTML = '<style>' + shadowStyle + '</style><div id="container"><slot></slot></div>';
+ host.innerHTML = '<style>' + shadowStyle + '</style><div id="target">Click here</div>';
+
+ var target = host.querySelector('#target');
+ var container = shadowRoot.querySelector('#container');
+
+ var eventLogs = attachLoggers([target, container, shadowRoot, host, document.body]);
+ var mouseEvent = new MouseEvent('mousedown', {clientX: 51, clientY: 37, composed: true, bubbles: true});
+ target.dispatchEvent(mouseEvent);
+
+ assert_equals(host.offsetLeft, 20, 'The host must be at (20px, 10px)');
+ assert_equals(host.offsetTop, 10, 'The host must be at (20px, 10px)');
+ assert_equals(target.offsetLeft, 45, 'The target must be at (45px, 30px)');
+ assert_equals(target.offsetTop, 30, 'The target must be at (45px, 30px)');
+
+ assert_equals(eventLogs[0].current, target);
+ assert_equals(eventLogs[0].target, target);
+ assert_equals(eventLogs[0].target.offsetParent, document.body);
+ assert_equals(eventLogs[0].offsetX, 6); // Padding edge of target is at (45px, 30px)
+ assert_equals(eventLogs[0].offsetY, 7);
+
+ assert_equals(eventLogs[1].current, container);
+ assert_equals(eventLogs[1].target, target);
+ assert_equals(eventLogs[1].offsetX, 6);
+ assert_equals(eventLogs[1].offsetY, 7);
+
+ assert_equals(eventLogs[2].current, shadowRoot);
+ assert_equals(eventLogs[2].target, target);
+ assert_equals(eventLogs[2].offsetX, 6);
+ assert_equals(eventLogs[2].offsetY, 7);
+
+ assert_equals(eventLogs[3].current, host);
+ assert_equals(eventLogs[3].target, target);
+ assert_equals(eventLogs[3].offsetX, 6);
+ assert_equals(eventLogs[3].offsetY, 7);
+
+ assert_equals(eventLogs[4].current, document.body);
+ assert_equals(eventLogs[4].target, target);
+ assert_equals(eventLogs[4].offsetX, 6);
+ assert_equals(eventLogs[4].offsetY, 7);
+}, 'MouseEvent\'s offsetX and offsetY attributes must be relative to the target when an event is dispatched on a slotted content.');
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/Node-prototype-cloneNode.html b/testing/web-platform/tests/shadow-dom/Node-prototype-cloneNode.html
new file mode 100644
index 000000000..6c6b24bc0
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/Node-prototype-cloneNode.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>DOM: cloneNode(deep)</title>
+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+<meta name="assert" content="If context object is a shadow root, then it must throw a NotSupportedError.">
+<link rel="help" href="https://dom.spec.whatwg.org/#dom-node-clonenode">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+function testCloneNode(mode) {
+ test(function () {
+ assert_throws({'name': 'NotSupportedError'}, function () {
+ var element = document.createElement('div');
+ var shadowRoot = element.attachShadow({mode: mode});
+ shadowRoot.cloneNode(false);
+ }, 'cloneNode(false) on a shadow root in ' + mode + ' mode must throw a NotSupportedError');
+
+ assert_throws({'name': 'NotSupportedError'}, function () {
+ var element = document.createElement('div');
+ var shadowRoot = element.attachShadow({mode: mode});
+ shadowRoot.cloneNode(false);
+ }, 'cloneNode(true) on a closed shadow root must throw a NotSupportedError');
+
+ }, 'cloneNode on a shadow root in ' + mode + ' mode must throw a NotSupportedError');
+}
+
+testCloneNode('open');
+testCloneNode('closed');
+
+test(function () {
+ var element = document.createElement('div');
+ var shadowRoot = element.attachShadow({mode: 'open'});
+
+ assert_equals(element.cloneNode(false).shadowRoot, null, 'cloneNode(false) on an element with an open shadow root should not clone its shadow root');
+ assert_equals(element.cloneNode(true).shadowRoot, null, 'cloneNode(true) on an element with an open shadow root should not clone its shadow root');
+}, 'cloneNode on an element with an open shadow root should not clone its shadow root');
+
+test(function () {
+ var element = document.createElement('div');
+ var shadowRoot = element.attachShadow({mode: 'closed'});
+
+ assert_true(element.cloneNode(false).attachShadow({mode: 'closed'}) instanceof ShadowRoot,
+ 'An element returned by cloneNode(false) on an element with a closed shadow root should allow attachShadow');
+
+ assert_true(element.cloneNode(true).attachShadow({mode: 'closed'}) instanceof ShadowRoot,
+ 'An element returned by cloneNode(true) on an element with a closed shadow root should allow attachShadow');
+
+}, 'cloneNode on an element with a closed shadow root should not clone its shadow root');
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/OWNERS b/testing/web-platform/tests/shadow-dom/OWNERS
new file mode 100644
index 000000000..a7406e584
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/OWNERS
@@ -0,0 +1,5 @@
+@kojiishi
+@rniwa
+@sideshowbarker
+@takayoshikochi
+@hayatoito
diff --git a/testing/web-platform/tests/shadow-dom/ShadowRoot-interface.html b/testing/web-platform/tests/shadow-dom/ShadowRoot-interface.html
new file mode 100644
index 000000000..6b49f93b3
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/ShadowRoot-interface.html
@@ -0,0 +1,111 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Shadow DOM: ShadowRoot interface</title>
+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+<meta name="assert" content="ShadowRoot interface and its attributes must be defined">
+<link rel="help" href="https://w3c.github.io/webcomponents/spec/shadow/#the-shadowroot-interface">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+test(function () {
+ assert_true('ShadowRoot' in window, '"ShadowRoot" exists on window');
+}, 'Check the existence of ShadowRoot interface');
+
+test(function () {
+ assert_equals(ShadowRoot.prototype.__proto__, DocumentFragment.prototype, 'ShadowRoot must inherit from DocumentFragment');
+}, 'ShadowRoot must inherit from DocumentFragment');
+
+test(function () {
+ assert_throws({'name': 'TypeError'}, function () { new ShadowRoot(); }, 'new ShadowRoot() must throw a TypeError');
+}, 'ShadowRoot must not be a constructor');
+
+function testActiveElement(mode) {
+ test(function () {
+ var host = document.createElement('div');
+ document.body.appendChild(host);
+ var shadowRoot = host.attachShadow({'mode': mode});
+ shadowRoot.appendChild(document.createElement('input'));
+ assert_equals(shadowRoot.activeElement, null, 'ShadowRoot.host must return null if an ' + mode + ' shadow tree does not have a focused element');
+ shadowRoot.firstChild.focus();
+ assert_equals(shadowRoot.activeElement, shadowRoot.firstChild, 'ShadowRoot.host must return the focused element of an ' + mode + ' shadow tree');
+ host.remove();
+ assert_equals(shadowRoot.activeElement, null, 'ShadowRoot.host must return null if an ' + mode + ' shadow tree lost focus');
+ }, 'ShadowRoot.activeElement must return the focused element of the context object when shadow root is ' + mode + '.');
+}
+
+testActiveElement('open');
+testActiveElement('closed');
+
+test(function () {
+ var host1 = document.createElement('div');
+ assert_equals(host1.attachShadow({'mode': 'open'}).host, host1, 'ShadowRoot.host must return the shadow host of an open shadow tree')
+
+ var host2 = document.createElement('div');
+ assert_equals(host2.attachShadow({'mode': 'closed'}).host, host2, 'ShadowRoot.host must return the shadow host of a closed shadow tree');
+}, 'ShadowRoot.host must return the shadow host of the context object.');
+
+function testInnerHTML(mode) {
+ test(function () {
+ var host = document.createElement('div');
+ var shadowRoot = host.attachShadow({'mode': mode});
+ assert_equals(shadowRoot.innerHTML, '', 'ShadowRoot.innerHTML must be an empty string when the shadow root does not have any children');
+
+ shadowRoot.appendChild(document.createTextNode('hello'));
+ assert_equals(shadowRoot.innerHTML, 'hello', 'ShadowRoot.innerHTML must serialize a text node child');
+
+ shadowRoot.appendChild(document.createElement('span'));
+ assert_equals(shadowRoot.innerHTML, 'hello<span></span>', 'ShadowRoot.innerHTML must serialize a HTML element child');
+ }, 'ShadowRoot.innerHTML must return the result of the HTML fragment serialization algorithm when shadow root is ' + mode + '.');
+}
+
+testInnerHTML('open');
+testInnerHTML('closed');
+
+function testSetInnerHTML(mode) {
+ test(function () {
+ var host = document.createElement('div');
+ var shadowRoot = host.attachShadow({'mode': mode});
+ shadowRoot.innerHTML = 'hello';
+ assert_equals(shadowRoot.childNodes.length, 1, 'ShadowRoot.innerHTML = "hello" must insert a single child (text node)');
+ assert_true(shadowRoot.firstChild instanceof Text, 'The first child of the shadow root after ShadowRoot.innerHTML = "hello" must be a Text node');
+ assert_equals(shadowRoot.firstChild.data, 'hello', 'The first Text node should contain the string "hello" after ShadowRoot.innerHTML = "hello"');
+
+ shadowRoot.innerHTML = '<b>hello</b>';
+ assert_equals(shadowRoot.childNodes.length, 1, 'ShadowRoot.innerHTML = "<b>hello</b>" must insert a single child (b)');
+ assert_true(shadowRoot.firstChild instanceof HTMLElement, 'The first child of the shadow root after ShadowRoot.innerHTML = "<b>hello</b>" must be a HTML element');
+ assert_equals(shadowRoot.firstChild.localName, 'b', 'The local name of the shadow root\'s first child after ShadowRoot.innerHTML = "<b>hello</b>" must be "b"');
+ assert_equals(shadowRoot.innerHTML, '<b>hello</b>', 'ShadowRoot.innerHTML must be "<b>hello</b>" after ShadowRoot.innerHTML = "<b>hello</b>"');
+
+ shadowRoot.innerHTML = '';
+ assert_equals(shadowRoot.childNodes.length, 0, 'ShadowRoot.innerHTML = "" must remove all its children');
+ }, 'ShadowRoot.innerHTML must replace all with the result of invoking the fragment parsing algorithm when shadow root is ' + mode + '.');
+}
+
+testSetInnerHTML('open');
+testSetInnerHTML('closed');
+
+function testStyleSheets(mode) {
+ test(function () {
+ var host = document.createElement('div');
+ var shadowRoot = host.attachShadow({'mode': mode});
+
+ assert_equals(shadowRoot.styleSheets.length, 0, 'shadowRoot.styleSheets must be empty when the shadow root does not contain any stylesheets');
+ shadowRoot.innerHTML = '<span></span><style> a.rule {} </style><style> b.rule {} </style>';
+ assert_equals(shadowRoot.styleSheets.length, 2, 'shadowRoot.styleSheets must contain two items when the shadow root has two style elements');
+ var styles = shadowRoot.querySelectorAll('style');
+ assert_equals(shadowRoot.styleSheets[0], styles[0].sheet, 'shadowRoot.styleSheets[0] must be the first style element in the shadow root');
+ assert_equals(shadowRoot.styleSheets[1], styles[1].sheet, 'shadowRoot.styleSheets[1] must be the second style element in the shadow root');
+ }, 'ShadowRoot.styleSheets must return a StyleSheetList sequence containing the shadow root style sheets when shadow root is ' + mode + '.');
+}
+
+testStyleSheets('open');
+testStyleSheets('closed');
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/Slotable-interface.html b/testing/web-platform/tests/shadow-dom/Slotable-interface.html
new file mode 100644
index 000000000..a7b97e802
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/Slotable-interface.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Shadow DOM: Slotable interface</title>
+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+<meta name="assert" content="Element and Text interfaces must implement Slotable interface">
+<link rel="help" href="https://dom.spec.whatwg.org/#slotable">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+test(function () {
+ assert_true('assignedSlot' in Element.prototype, 'assignedSlot must be defined on Element.prototype');
+ assert_true('assignedSlot' in document.createElement('div'), 'assignedSlot must be defined on a div element');
+
+ assert_true('assignedSlot' in Text.prototype, 'assignedSlot must be defined on Text.prototype');
+ assert_true('assignedSlot' in document.createTextNode(''), 'assignedSlot must be defined on a text node');
+ assert_false('assignedSlot' in document.createComment(''), 'assignedSlot must not be defined on a comment node');
+ assert_false('assignedSlot' in document.createProcessingInstruction('target', 'data'), 'assignedSlot must not be defined on a processing instruction node');
+
+}, 'assignedSlot attribute must be defined on Element and Text interfaces');
+
+test(function () {
+ assert_equals(document.createElement('div').assignedSlot, null, 'assignedSlot must be null when the element is not in any tree');
+
+ var shadowHost = document.createElement('div');
+ var shadowRoot = shadowHost.attachShadow({mode: 'open'});
+
+ var childElement = document.createElement('b');
+ shadowHost.appendChild(childElement);
+ assert_equals(childElement.assignedSlot, null, 'assignedSlot on an element must be null when a node is not assigned of any slot');
+
+ var childTextNode = document.createTextNode('');
+ shadowHost.appendChild(childTextNode);
+ assert_equals(childTextNode.assignedSlot, null, 'assignedSlot on a text node must be null when a node is not assigned of any slot');
+
+ var slot = document.createElement('slot');
+ slot.name = 'foo';
+ shadowRoot.appendChild(slot);
+ assert_equals(childElement.assignedSlot, null, 'assignedSlot on an element must be null when a node does not match any slot');
+ assert_equals(childTextNode.assignedSlot, null, 'assignedSlot on a text node must be null when a node does not match any slot');
+
+}, 'assignedSlot must return null when the node does not have an assigned node');
+
+test(function () {
+ var shadowHost = document.createElement('div');
+ var childElement = document.createElement('b');
+ shadowHost.appendChild(childElement);
+
+ var childTextNode = document.createTextNode('');
+ shadowHost.appendChild(childTextNode);
+
+ var shadowRoot = shadowHost.attachShadow({mode: 'open'});
+ var slot = document.createElement('slot');
+ shadowRoot.appendChild(slot);
+
+ assert_equals(childElement.assignedSlot, slot, 'assignedSlot on an element must return the assigned default slot element');
+ assert_equals(childTextNode.assignedSlot, slot, 'assignedSlot on a text node must return the assigned default slot element');
+
+ slot.name = 'foo';
+ assert_equals(childElement.assignedSlot, null, 'assignedSlot on an element must null when the element is unassigned from a slot element');
+ assert_equals(childTextNode.assignedSlot, null, 'assignedSlot on a text node must null when the node is unassigned from a slot element');
+
+ childElement.slot = 'foo';
+ assert_equals(childElement.assignedSlot, slot, 'assignedSlot on an element must return the re-assigned slot element');
+
+ slot.removeAttribute('name');
+ assert_equals(childTextNode.assignedSlot, slot, 'assignedSlot on a text node must return the re-assigned slot element');
+
+}, 'assignedSlot must return the assigned slot');
+
+test(function () {
+ var shadowHost = document.createElement('div');
+ var childElement = document.createElement('b');
+ shadowHost.appendChild(childElement);
+
+ var childTextNode = document.createTextNode('');
+ shadowHost.appendChild(childTextNode);
+
+ var shadowRoot = shadowHost.attachShadow({mode: 'closed'});
+ var slot = document.createElement('slot');
+ shadowRoot.appendChild(slot);
+
+ assert_equals(childElement.assignedSlot, null, 'assignedSlot on an element must return null if the slot is inside a closed shadow tree.');
+ assert_equals(childTextNode.assignedSlot, null, 'assignedSlot on a text node must return null if the slot is inside a closed shadow tree.');
+
+}, 'assignedSlot must return null when the assigned slot element is inside a closed shadow tree');
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/event-composed-path-with-related-target.html b/testing/web-platform/tests/shadow-dom/event-composed-path-with-related-target.html
new file mode 100644
index 000000000..675a7d7b1
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/event-composed-path-with-related-target.html
@@ -0,0 +1,260 @@
+<!DOCTYPE html>
+<title>Shadow DOM: Event path and Event.composedPath() (with related target)</title>
+<meta name="author" title="Hayato Ito" href="mailto:hayato@google.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/shadow-dom.js"></script>
+
+<div id="test1">
+ <div id="target"></div>
+ <div id="related"></div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test1);
+ let log = dispatchEventWithLog(n, n.target, new FocusEvent('my-focus', { bubbles: true, composed: true, relatedTarget: n.related }));
+ let path = ['target', 'test1'];
+ assert_event_path_equals(log, [['target', 'target', 'related', path],
+ ['test1', 'target', 'related', path]]);
+}, 'Event path for an event with a relatedTarget. relatedTarget != target.');
+</script>
+
+<script>
+test(() => {
+ let n = createTestTree(test1);
+ let log = dispatchEventWithLog(n, n.target, new FocusEvent('my-focus', { bubbles: true, composed: true, relatedTarget: n.target }));
+ let path = ['target', 'test1'];
+ assert_event_path_equals(log, [['target', 'target', 'target', path],
+ ['test1', 'target', 'target', path]]);
+}, 'Event path for an event with a relatedTarget. Event should be dispatched even when target and relatedTarget are same.');
+</script>
+
+<div id="test2">
+ <div id="host">
+ <template id="sr" data-mode="open">
+ <div id="target"></div>
+ <div id="related"></div>
+ </template>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test2);
+ let log = dispatchEventWithLog(n, n.target, new FocusEvent('my-focus', { bubbles: true, composed: true, relatedTarget: n.related }));
+ let path = ['target', 'sr'];
+ assert_event_path_equals(log, [['target', 'target', 'related', path],
+ ['sr', 'target', 'related', path]]);
+}, 'Event path for an event with a relatedTarget. Event should stop at the shadow root');
+
+test(() => {
+ let n = createTestTree(test2);
+ let log = dispatchEventWithLog(n, n.target, new FocusEvent('my-focus', { bubbles: true, composed: true, relatedTarget: n.target }));
+ let path = ['target', 'sr'];
+ assert_event_path_equals(log, [['target', 'target', 'target', path],
+ ['sr', 'target', 'target', path]]);
+}, 'Event path for an event with a relatedTarget which is identical to target. Event should be dispatched and should stop at the shadow root.');
+</script>
+
+<div id="test3_1">
+ <div id="host1">
+ <template id="sr1" data-mode="open">
+ <div id="target1"></div>
+ </template>
+ </div>
+</div>
+
+<div id="test3_2">
+ <div id="host2">
+ <template id="sr2" data-mode="open">
+ <div id="target2"></div>
+ </template>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n1 = createTestTree(test3_1);
+ let n2 = createTestTree(test3_2);
+ let log = dispatchEventWithLog(n1, n1.target1, new FocusEvent('my-focus', { bubbles: true, composed: true, relatedTarget: n2.target2 }));
+ let path = ['target1', 'sr1', 'host1', 'test3_1'];
+ assert_event_path_equals(log, [['target1', 'target1', 'host2', path],
+ ['sr1', 'target1', 'host2', path],
+ ['host1', 'host1', 'host2', path],
+ ['test3_1', 'host1', 'host2', path]]);
+}, 'Event path for an event with a relatedTarget. target and relaterTarget do not share any shadow-including ancestor. target is in a shadow tree.');
+
+test(() => {
+ let n1 = createTestTree(test3_1);
+ let n2 = createTestTree(test3_2);
+ let log = dispatchEventWithLog(n1, n1.host1, new FocusEvent('my-focus', { bubbles: true, composed: true, relatedTarget: n2.target2 }));
+ let path = ['host1', 'test3_1'];
+ assert_event_path_equals(log, [['host1', 'host1', 'host2', path],
+ ['test3_1', 'host1', 'host2', path]]);
+}, 'Event path for an event with a relatedTarget. target and relaterTarget do not share any shadow-including ancestor. target is not in a shadow tree');
+</script>
+
+<div id="test4">
+ <div id="host1">
+ <template id="sr1" data-mode="open">
+ <div id="host2">
+ <template id="sr2" data-mode="open">
+ <div id="target"></div>
+ </template>
+ </div>
+ <div id="host3">
+ <template id="sr3" data-mode="open">
+ <div id="related"></div>
+ </template>
+ </div>
+ </template>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test4);
+ let log = dispatchEventWithLog(n, n.target, new FocusEvent('my-focus', { bubbles: true, composed: true, relatedTarget: n.related }));
+ let path = ['target', 'sr2', 'host2', 'sr1'];
+ assert_event_path_equals(log, [['target', 'target', 'host3', path],
+ ['sr2', 'target', 'host3', path],
+ ['host2', 'host2', 'host3', path],
+ ['sr1', 'host2', 'host3', path]]);
+}, 'Event path for an event with a relatedTarget. target and relaterTarget share the same shadow-including ancestor. Both are in shadow trees.');
+
+test(() => {
+ let n = createTestTree(test4);
+ let log = dispatchEventWithLog(n, n.target, new FocusEvent('my-focus', { bubbles: true, composed: true, relatedTarget: n.host1 }));
+ let path = ['target', 'sr2', 'host2', 'sr1'];
+ assert_event_path_equals(log, [['target', 'target', 'host1', path],
+ ['sr2', 'target', 'host1', path],
+ ['host2', 'host2', 'host1', path],
+ ['sr1', 'host2', 'host1', path]]);
+}, 'Event path for an event with a relatedTarget. relaterTarget is a shadow-including ancestor of target.');
+
+test(() => {
+ let n = createTestTree(test4);
+ let log = dispatchEventWithLog(n, n.host1, new FocusEvent('my-focus', { bubbles: true, composed: true, relatedTarget: n.target }));
+ let path = ['host1', 'test4'];
+ assert_event_path_equals(log, [['host1', 'host1', 'host1', path],
+ ['test4', 'host1', 'host1', path]]);
+}, 'Event path for an event with a relatedTarget. target is a shadow-including ancestor of relatedTarget.');
+</script>
+
+<div id="test5">
+ <div id="host">
+ <template id="sr" data-mode="open">
+ <slot id="slot"></slot>
+ <div id="related"></div>
+ </template>
+ <div id="target"></div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test5);
+ let log = dispatchEventWithLog(n, n.target, new FocusEvent('my-focus', { bubbles: true, composed: true, relatedTarget: n.related }));
+ let path = ['target', 'slot', 'sr', 'host', 'test5'];
+ assert_event_path_equals(log, [['target', 'target', 'host', path],
+ ['slot', 'target', 'related', path],
+ ['sr', 'target', 'related', path],
+ ['host', 'target', 'host', path],
+ ['test5', 'target', 'host', path]]);
+}, 'Event path for an event with a relatedTarget. target is assigned to a slot.');
+
+test(() => {
+ let n = createTestTree(test5);
+ let log = dispatchEventWithLog(n, n.related, new FocusEvent('my-focus', { bubbles: true, composed: true, relatedTarget: n.target }));
+ let path = ['related', 'sr', 'host', 'test5'];
+ assert_event_path_equals(log, [['related', 'related', 'target', path],
+ ['sr', 'related', 'target', path],
+ ['host', 'host', 'target', path],
+ ['test5', 'host', 'target', path]]);
+}, 'Event path for an event with a relatedTarget. relatedTarget is assigned to a slot.');
+</script>
+
+<div id="test6">
+ <div id="host0">
+ <template id="sr0" data-mode="open">
+ <div id="host1">
+ <template id="sr1" data-mode="open">
+ <div id="host2">
+ <template id="sr2" data-mode="open">
+ <slot id="slot2"></slot>
+ <div id="related2"></div>
+ </template>
+ <div id="related1"></div>
+ <div id="d1">
+ <slot id="slot1"></slot>
+ </div>
+ </div>
+ </template>
+ <div id="host3">
+ <template id="sr3" data-mode="open">
+ <div id="host4">
+ <template id="sr4" data-mode="open">
+ <div id="host5">
+ <template id="sr5" data-mode="open">
+ <slot id="slot5"></slot>
+ </template>
+ <slot id="slot4"></slot>
+ </div>
+ </template>
+ <div id="target"></div>
+ </div>
+ </template>
+ </div>
+ </div>
+ </template>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test6);
+ let log = dispatchEventWithLog(n, n.target, new FocusEvent('my-focus', { bubbles: true, composed: true, relatedTarget: n.related1 }));
+ let path = ['target', 'slot4', 'slot5', 'sr5', 'host5', 'sr4', 'host4', 'sr3', 'host3', 'slot1', 'd1', 'slot2', 'sr2', 'host2', 'sr1', 'host1', 'sr0'];
+ assert_event_path_equals(log, [['target', 'target', 'host1', path],
+ ['slot4', 'target', 'host1', path],
+ ['slot5', 'target', 'host1', path],
+ ['sr5', 'target', 'host1', path],
+ ['host5', 'target', 'host1', path],
+ ['sr4', 'target', 'host1', path],
+ ['host4', 'target', 'host1', path],
+ ['sr3', 'target', 'host1', path],
+ ['host3', 'host3', 'host1', path],
+ ['slot1', 'host3', 'related1', path],
+ ['d1' , 'host3', 'related1', path],
+ ['slot2', 'host3', 'related1', path],
+ ['sr2', 'host3', 'related1', path],
+ ['host2', 'host3', 'related1', path],
+ ['sr1', 'host3', 'related1', path],
+ ['host1', 'host3', 'host1', path],
+ ['sr0', 'host3', 'host1' , path]]);
+}, 'Event path for an event with a relatedTarget. Event should be dispatched at every slots.');
+
+test(() => {
+ let n = createTestTree(test6);
+ let log = dispatchEventWithLog(n, n.target, new FocusEvent('my-focus', { bubbles: true, composed: true, relatedTarget: n.related2 }));
+ let path = ['target', 'slot4', 'slot5', 'sr5', 'host5', 'sr4', 'host4', 'sr3', 'host3', 'slot1', 'd1', 'slot2', 'sr2', 'host2', 'sr1', 'host1', 'sr0'];
+ assert_event_path_equals(log, [['target', 'target', 'host1', path],
+ ['slot4', 'target', 'host1', path],
+ ['slot5', 'target', 'host1', path],
+ ['sr5', 'target', 'host1', path],
+ ['host5', 'target', 'host1', path],
+ ['sr4', 'target', 'host1', path],
+ ['host4', 'target', 'host1', path],
+ ['sr3', 'target', 'host1', path],
+ ['host3', 'host3', 'host1', path],
+ ['slot1', 'host3', 'host2', path],
+ ['d1' , 'host3', 'host2', path],
+ ['slot2', 'host3', 'related2', path],
+ ['sr2', 'host3', 'related2', path],
+ ['host2', 'host3', 'host2', path],
+ ['sr1', 'host3', 'host2', path],
+ ['host1', 'host3', 'host1', path],
+ ['sr0', 'host3', 'host1' , path]]);
+}, 'Event path for an event with a relatedTarget. Event should be dispatched at every slots. relatedTarget should be correctly retargeted.');
+</script>
diff --git a/testing/web-platform/tests/shadow-dom/event-composed-path.html b/testing/web-platform/tests/shadow-dom/event-composed-path.html
new file mode 100644
index 000000000..8c37b1c3b
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/event-composed-path.html
@@ -0,0 +1,281 @@
+<!DOCTYPE html>
+<title>Shadow DOM: Event path and Event.composedPath()</title>
+<meta name="author" title="Hayato Ito" href="mailto:hayato@google.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/shadow-dom.js"></script>
+
+<div id="test1">
+ <div id="d1">
+ <div id="target"></div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test1);
+ let log = dispatchEventWithLog(n, n.target, new Event('my-event', { bubbles: true, composed: true }));
+ let path = ['target', 'd1', 'test1'];
+ assert_event_path_equals(log,
+ [['target', 'target', null, path],
+ ['d1', 'target', null, path],
+ ['test1', 'target', null, path]]);
+}, 'Event Path without ShadowRoots.');
+</script>
+
+<div id="test2">
+ <div id="host">
+ <template id="sr" data-mode="open">
+ <div id="target"></div>
+ </template>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test2);
+ let log = dispatchEventWithLog(n, n.target, new Event('my-event', { bubbles: true, composed: true }));
+ let path = ['target', 'sr', 'host', 'test2'];
+ assert_event_path_equals(log,
+ [['target', 'target', null, path],
+ ['sr', 'target', null, path],
+ ['host', 'host', null, path],
+ ['test2', 'host', null, path]]);
+}, 'Event Path with an open ShadowRoot.');
+</script>
+
+<div id="test3">
+ <div id="host">
+ <template id="sr" data-mode="closed">
+ <div id="target"></div>
+ </template>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test3);
+ let log = dispatchEventWithLog(n, n.target, new Event('my-event', { bubbles: true, composed: true }));
+ let path = ['target','sr', 'host', 'test3'];
+ let path1 = ['host', 'test3'];
+ assert_event_path_equals(log, [['target', 'target', null, path],
+ ['sr', 'target', null, path],
+ ['host', 'host', null, path1],
+ ['test3', 'host', null, path1]]);
+}, 'Event Path with a closed ShadowRoot.');
+</script>
+
+<div id="test4">
+ <div id="host1">
+ <template id="sr1" data-mode="open">
+ <div id="host2">
+ <template id="sr2" data-mode="open">
+ <div id="target"></div>
+ </template>
+ </div>
+ </template>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test4);
+ let log = dispatchEventWithLog(n, n.target, new Event('my-event', { bubbles: true, composed: true }));
+ let path = ['target', 'sr2', 'host2', 'sr1', 'host1', 'test4'];
+ assert_event_path_equals(log, [['target', 'target', null, path],
+ ['sr2', 'target', null, path],
+ ['host2', 'host2', null, path],
+ ['sr1', 'host2', null, path],
+ ['host1', 'host1', null, path],
+ ['test4', 'host1', null, path]]);
+}, 'Event Path with nested ShadowRoots: open > open.');
+</script>
+
+<div id="test5">
+ <div id="host1">
+ <template id="sr1" data-mode="open">
+ <div id="host2">
+ <template id="sr2" data-mode="closed">
+ <div id="target"></div>
+ </template>
+ </div>
+ </template>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test5);
+ let log = dispatchEventWithLog(n, n.target, new Event('my-event', { bubbles: true, composed: true }));
+ let path = ['target', 'sr2', 'host2', 'sr1', 'host1', 'test5'];
+ let path1 = ['host2', 'sr1', 'host1', 'test5'];
+ assert_event_path_equals(log, [['target', 'target', null, path],
+ ['sr2', 'target', null, path],
+ ['host2', 'host2', null, path1],
+ ['sr1', 'host2', null, path1],
+ ['host1', 'host1', null, path1],
+ ['test5', 'host1', null, path1]]);
+}, 'Event Path with nested ShadowRoots: open > closed.');
+</script>
+
+<div id="test6">
+ <div id="host1">
+ <template id="sr1" data-mode="closed">
+ <div id="host2">
+ <template id="sr2" data-mode="open">
+ <div id="target"></div>
+ </template>
+ </div>
+ </template>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test6);
+ let log = dispatchEventWithLog(n, n.target, new Event('my-event', { bubbles: true, composed: true }));
+ let path = ['target', 'sr2', 'host2', 'sr1', 'host1', 'test6'];
+ let path1 = ['host1', 'test6'];
+ assert_event_path_equals(log, [['target', 'target', null, path],
+ ['sr2', 'target', null, path],
+ ['host2', 'host2', null, path],
+ ['sr1', 'host2', null, path],
+ ['host1', 'host1', null, path1],
+ ['test6', 'host1', null, path1]]);
+}, 'Event Path with nested ShadowRoots: closed > open.');
+</script>
+
+<div id="test7">
+ <div id="host1">
+ <template id="sr1" data-mode="closed">
+ <div id="host2">
+ <template id="sr2" data-mode="closed">
+ <div id="target"></div>
+ </template>
+ </div>
+ </template>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test7);
+ let log = dispatchEventWithLog(n, n.target, new Event('my-event', { bubbles: true, composed: true }));
+ let path = ['target', 'sr2', 'host2', 'sr1', 'host1', 'test7'];
+ let path1 = ['host2', 'sr1', 'host1', 'test7'];
+ let path2 = ['host1', 'test7'];
+ assert_event_path_equals(log, [['target', 'target', null, path],
+ ['sr2', 'target', null, path],
+ ['host2', 'host2', null, path1],
+ ['sr1', 'host2', null, path1],
+ ['host1', 'host1', null, path2],
+ ['test7', 'host1', null, path2]]);
+}, 'Event Path with nested ShadowRoots: closed > closed.');
+</script>
+
+<div id="test8">
+ <div id="host1">
+ <template id="sr1" data-mode="open">
+ <slot id="slot"></slot>
+ </template>
+ <div id="target"></div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test8);
+ let log = dispatchEventWithLog(n, n.target, new Event('my-event', { bubbles: true, composed: true }));
+ let path = ['target','slot', 'sr1', 'host1', 'test8'];
+ assert_event_path_equals(log, [['target', 'target', null, path],
+ ['slot', 'target', null, path],
+ ['sr1', 'target', null, path],
+ ['host1', 'target', null, path],
+ ['test8', 'target', null, path]]);
+}, 'Event Path with a slot in an open Shadow Root.');
+</script>
+
+<div id="test9">
+ <div id="host1">
+ <template id="sr1" data-mode="closed">
+ <slot id="slot"></slot>
+ </template>
+ <div id="target"></div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test9);
+ let log = dispatchEventWithLog(n, n.target, new Event('my-event', { bubbles: true, composed: true }));
+ let path = ['target', 'slot', 'sr1', 'host1', 'test9'];
+ let path1 = ['target', 'host1', 'test9'];
+ assert_event_path_equals(log, [['target', 'target', null, path1],
+ ['slot', 'target', null, path],
+ ['sr1', 'target', null, path],
+ ['host1', 'target', null, path1],
+ ['test9', 'target', null, path1]]);
+}, 'Event Path with a slot in a closed Shadow Root.');
+</script>
+
+<div id="test10">
+ <div id="host1">
+ <template id="sr1" data-mode="open">
+ <div id="host2">
+ <template id="sr2" data-mode="open">
+ <slot id="slot2"></slot>
+ </template>
+ <slot id="slot1"></slot>
+ </div>
+ </template>
+ <div id="target"></div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test10);
+ let log = dispatchEventWithLog(n, n.target, new Event('my-event', { bubbles: true, composed: true }));
+ let path = ['target','slot1', 'slot2', 'sr2', 'host2', 'sr1', 'host1', 'test10'];
+ assert_event_path_equals(log, [['target', 'target', null, path],
+ ['slot1', 'target', null, path],
+ ['slot2', 'target', null, path],
+ ['sr2', 'target', null, path],
+ ['host2', 'target', null, path],
+ ['sr1', 'target', null, path],
+ ['host1', 'target', null, path],
+ ['test10', 'target', null, path]]);
+}, 'Event Path with slots in nested ShadowRoots: open > open.');
+</script>
+
+<div id="test11">
+ <div id="host1">
+ <template id="sr1" data-mode="closed">
+ <div id="host2">
+ <template id="sr2" data-mode="closed">
+ <slot id="slot2"></slot>
+ </template>
+ <slot id="slot1"></slot>
+ </div>
+ </template>
+ <div id="target"></div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test11);
+ let log = dispatchEventWithLog(n, n.target, new Event('my-event', { bubbles: true, composed: true }));
+ let path = ['target', 'slot1', 'slot2', 'sr2', 'host2', 'sr1', 'host1', 'test11'];
+ let path1 = ['target', 'slot1', 'host2', 'sr1', 'host1', 'test11'];
+ let path2 = ['target', 'host1', 'test11'];
+ assert_event_path_equals(log, [['target', 'target', null, path2],
+ ['slot1', 'target', null, path1],
+ ['slot2', 'target', null, path],
+ ['sr2', 'target', null, path],
+ ['host2', 'target', null, path1],
+ ['sr1', 'target', null, path1],
+ ['host1', 'target', null, path2],
+ ['test11', 'target', null, path2]]);
+}, 'Event Path with slots in nested ShadowRoots: closed > closed.');
+</script>
diff --git a/testing/web-platform/tests/shadow-dom/event-composed.html b/testing/web-platform/tests/shadow-dom/event-composed.html
new file mode 100644
index 000000000..2d6a5e365
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/event-composed.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<title>Shadow DOM: Event composed</title>
+<meta name="author" title="Hayato Ito" href="mailto:hayato@google.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/shadow-dom.js"></script>
+<div id=host>
+ <template id=shadowRoot data-mode=open>
+ <div id=target></div>
+ </template>
+</div>
+<script>
+test(() => {
+ const e = new Event('test');
+ assert_equals(e.composed, false);
+}, 'A new events composed value should be set to false by default.');
+
+test(() => {
+ const e = new Event('test', { composed: true });
+ assert_equals(e.composed, true);
+}, 'Users should be able to set a composed value.');
+
+function assertScoped(event) {
+ let nodes = createTestTree(host);
+ let log = dispatchEventWithLog(nodes, nodes.target, event);
+ let expectedPath = ['target', 'shadowRoot'];
+ assert_event_path_equals(log,
+ [['target', 'target', null, expectedPath],
+ ['shadowRoot', 'target', null, expectedPath]]);
+}
+
+function assertComposed(event) {
+ let nodes = createTestTree(host);
+ let log = dispatchEventWithLog(nodes, nodes.target, event);
+ let expectedPath = ['target', 'shadowRoot', 'host'];
+ assert_event_path_equals(log,
+ [['target', 'target', null, expectedPath],
+ ['shadowRoot', 'target', null, expectedPath],
+ ['host', 'host', null, expectedPath]]);
+}
+
+test(() => {
+ assertScoped(new Event('test', { bubbles: true }));
+}, 'An event should be scoped by default');
+
+test(() => {
+ assertComposed(new Event('test', { bubbles: true, composed: true }));
+}, 'An event should not be scoped if composed is specified');
+
+test(() => {
+ assertScoped(new MouseEvent('click', { bubbles: true }));
+}, 'A synthetic MouseEvent should be scoped by default');
+
+test(() => {
+ assertComposed(new MouseEvent('click', { bubbles: true, composed: true }));
+}, 'A synthetic MouseEvent with composed=true should not be scoped');
+
+test(() => {
+ assertScoped(new FocusEvent('focus', { bubbles: true }));
+}, 'A synthetic FocusEvent should be scoped by default');
+
+test(() => {
+ assertComposed(new FocusEvent('focus', { bubbles: true, composed: true }));
+}, 'A synthetic FocusEvent with composed=true should not be scoped');
+
+function assertUAComposed(eventType, callback) {
+ let nodes = createTestTree(host);
+ let log = dispatchUAEventWithLog(nodes, nodes.target, eventType, callback);
+ let expectedPath = ['target', 'shadowRoot', 'host'];
+ assert_event_path_equals(log,
+ [['target', 'target', null, expectedPath],
+ ['shadowRoot', 'target', null, expectedPath],
+ ['host', 'host', null, expectedPath]]);
+}
+
+test(() => {
+ assertUAComposed('click', (target) => { target.click(); });
+}, 'A UA click event should not be scoped');
+
+// TODO(hayato): Test other UIEvents.
+</script>
diff --git a/testing/web-platform/tests/shadow-dom/event-inside-shadow-tree.html b/testing/web-platform/tests/shadow-dom/event-inside-shadow-tree.html
new file mode 100644
index 000000000..cacd966b3
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/event-inside-shadow-tree.html
@@ -0,0 +1,148 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Shadow DOM: Firing an event inside a shadow tree</title>
+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+<meta name="assert" content="The event path calculation algorithm must be used to determine event path">
+<link rel="help" href="https://w3c.github.io/webcomponents/spec/shadow/#event-paths">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+function dispatchEventWithLog(target, event) {
+ var log = [];
+
+ for (var node = target; node; node = node.parentNode || node.host) {
+ node.addEventListener(event.type, (function (event) {
+ log.push([this, event.target]);
+ }).bind(node));
+ }
+
+ target.dispatchEvent(event);
+
+ return log;
+}
+
+function createShadowRootWithGrandChild(mode) {
+ var host = document.createElement('div');
+ var root = host.attachShadow({mode: mode});
+
+ var parent = document.createElement('span');
+ root.appendChild(parent);
+
+ var target = document.createElement('b');
+ parent.appendChild(target);
+ return {target: target, parent: parent, root: root, host: host};
+}
+
+function testEventInDetachedShadowTree(mode) {
+ test(function () {
+ var shadow = createShadowRootWithGrandChild(mode);
+
+ log = dispatchEventWithLog(shadow.target, new Event('foo', {composed: true, bubbles: true}));
+
+ assert_array_equals(log.length, 4, 'EventPath must contain [target, parent, shadow root, shadow host]');
+ assert_array_equals(log[0], [shadow.target, shadow.target], 'EventPath[0] must be the target');
+ assert_array_equals(log[1], [shadow.parent, shadow.target], 'EventPath[1] must be the parent of the target');
+ assert_array_equals(log[2], [shadow.root, shadow.target], 'EventPath[2] must be the shadow root');
+ assert_array_equals(log[3], [shadow.host, shadow.host], 'EventPath[3] must be the shadow host');
+
+ }, 'Firing an event inside a grand child of a detached ' + mode + ' mode shadow tree');
+}
+
+testEventInDetachedShadowTree('open');
+testEventInDetachedShadowTree('closed');
+
+function testEventInShadowTreeInsideDocument(mode) {
+ test(function () {
+ var shadow = createShadowRootWithGrandChild(mode);
+ document.body.appendChild(shadow.host);
+
+ log = dispatchEventWithLog(shadow.target, new Event('foo', {composed: true, bubbles: true}));
+
+ assert_array_equals(log.length, 7, 'EventPath must contain [target, parent, shadow root, shadow host, body, html, document]');
+ assert_array_equals(log[0], [shadow.target, shadow.target], 'EventPath[0] must be the target');
+ assert_array_equals(log[1], [shadow.parent, shadow.target], 'EventPath[1] must be the parent of the target');
+ assert_array_equals(log[2], [shadow.root, shadow.target], 'EventPath[2] must be the shadow root');
+ assert_array_equals(log[3], [shadow.host, shadow.host], 'EventPath[3] must be the shadow host');
+ assert_array_equals(log[4], [document.body, shadow.host], 'EventPath[4] must be the body element (parent of shadow host)');
+ assert_array_equals(log[5], [document.documentElement, shadow.host], 'EventPath[5] must be the html element');
+ assert_array_equals(log[6], [document, shadow.host], 'EventPath[6] must be the document node');
+
+ }, 'Firing an event inside a grand child of an in-document ' + mode + ' mode shadow tree');
+}
+
+testEventInShadowTreeInsideDocument('open');
+testEventInShadowTreeInsideDocument('closed');
+
+function createNestedShadowRoot(innerMode, outerMode) {
+ var outerHost = document.createElement('div');
+ var outerRoot = outerHost.attachShadow({mode: outerMode});
+
+ var outerChild = document.createElement('p');
+ outerRoot.appendChild(outerChild);
+
+ var innerHost = document.createElement('span');
+ outerChild.appendChild(innerHost);
+
+ var innerRoot = innerHost.attachShadow({mode: innerMode});
+ var innerChild = document.createElement('span');
+ innerRoot.appendChild(innerChild);
+
+ return {target: innerChild, innerRoot: innerRoot, innerHost: innerHost, outerChild: outerChild, outerRoot: outerRoot, outerHost: outerHost};
+}
+
+function testEventInDetachedNestedShadowTree(innerMode, outerMode) {
+ test(function () {
+ var shadow = createNestedShadowRoot(innerMode, outerMode);
+
+ log = dispatchEventWithLog(shadow.target, new Event('bar', {composed: true, bubbles: true}));
+
+ assert_array_equals(log.length, 6, 'EventPath must contain [target, inner root, inner host, parent, outer root, outer host]');
+ assert_array_equals(log[0], [shadow.target, shadow.target], 'EventPath[0] must be the target');
+ assert_array_equals(log[1], [shadow.innerRoot, shadow.target], 'EventPath[1] must be the inner shadow root');
+ assert_array_equals(log[2], [shadow.innerHost, shadow.innerHost], 'EventPath[2] must be the inner shadow host');
+ assert_array_equals(log[3], [shadow.outerChild, shadow.innerHost], 'EventPath[3] must be the parent of the inner shadow host');
+ assert_array_equals(log[4], [shadow.outerRoot, shadow.innerHost], 'EventPath[4] must be the outer shadow root');
+ assert_array_equals(log[5], [shadow.outerHost, shadow.outerHost], 'EventPath[5] must be the outer shadow host');
+
+ }, 'Firing an event inside a detached ' + innerMode + ' mode shadow tree inside ' + outerMode + ' mode shadow tree');
+}
+
+testEventInDetachedNestedShadowTree('open', 'open');
+testEventInDetachedNestedShadowTree('open', 'closed');
+testEventInDetachedNestedShadowTree('closed', 'open');
+testEventInDetachedNestedShadowTree('closed', 'closed');
+
+function testEventInNestedShadowTreeInsideDocument(innerMode, outerMode) {
+ test(function () {
+ var shadow = createNestedShadowRoot(innerMode, outerMode);
+ document.body.appendChild(shadow.outerHost);
+
+ log = dispatchEventWithLog(shadow.target, new Event('bar', {composed: true, bubbles: true}));
+
+ assert_array_equals(log.length, 6, 'EventPath must contain [target, inner root, inner host, parent, outer root, outer host]');
+ assert_array_equals(log[0], [shadow.target, shadow.target], 'EventPath[0] must be the target');
+ assert_array_equals(log[1], [shadow.innerRoot, shadow.target], 'EventPath[1] must be the inner shadow root');
+ assert_array_equals(log[2], [shadow.innerHost, shadow.innerHost], 'EventPath[2] must be the inner shadow host');
+ assert_array_equals(log[3], [shadow.outerChild, shadow.innerHost], 'EventPath[3] must be the parent of the inner shadow host');
+ assert_array_equals(log[4], [shadow.outerRoot, shadow.innerHost], 'EventPath[4] must be the outer shadow root');
+ assert_array_equals(log[5], [shadow.outerHost, shadow.outerHost], 'EventPath[5] must be the outer shadow host');
+ assert_array_equals(log[6], [document.body, shadow.outerHost], 'EventPath[6] must be the body element');
+ assert_array_equals(log[7], [document.documentElement, shadow.outerHost], 'EventPath[7] must be the html element');
+ assert_array_equals(log[8], [document, shadow.outerHost], 'EventPath[8] must be the document node');
+
+ }, 'Firing an event inside an in-document ' + innerMode + ' mode shadow tree inside ' + outerMode + ' mode shadow tree');
+}
+
+testEventInNestedShadowTreeInsideDocument('open', 'open');
+testEventInNestedShadowTreeInsideDocument('open', 'closed');
+testEventInNestedShadowTreeInsideDocument('closed', 'open');
+testEventInNestedShadowTreeInsideDocument('closed', 'closed');
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/event-inside-slotted-node.html b/testing/web-platform/tests/shadow-dom/event-inside-slotted-node.html
new file mode 100644
index 000000000..f7d98bf7a
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/event-inside-slotted-node.html
@@ -0,0 +1,258 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Shadow DOM: Firing an event inside a node assigned to a slot</title>
+ <meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+ <meta name="assert" content="The event path calculation algorithm must be used to determine event path">
+ <link rel="help" href="https://w3c.github.io/webcomponents/spec/shadow/#event-paths">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+ <div id="log"></div>
+ <script>
+
+ function dispatchEventWithLog(shadow, event) {
+ var log = [];
+
+ var attachedNodes = [];
+ for (var nodeKey in shadow) {
+ var startingNode = shadow[nodeKey];
+ for (var node = startingNode; node; node = node.parentNode) {
+ if (attachedNodes.indexOf(node) >= 0)
+ continue;
+ attachedNodes.push(node);
+ node.addEventListener(event.type, (function (event) {
+ log.push([this, event.target]);
+ }).bind(node));
+ }
+ }
+
+ shadow.target.dispatchEvent(event);
+
+ return log;
+ }
+
+ function element(name, children, className) {
+ var element = document.createElement(name);
+ if (className)
+ element.className = className;
+ if (children) {
+ for (var child of children)
+ element.appendChild(child);
+ }
+ return element;
+ }
+
+ function attachShadow(host, mode, children) {
+ var shadowRoot = host.attachShadow({mode: mode});
+ if (children) {
+ for (var child of children)
+ shadowRoot.appendChild(child);
+ }
+ return shadowRoot;
+ }
+
+ function createShadowHostWithAssignedGrandChild(mode) {
+ var host = element('div', [
+ element('b', [
+ element('i')
+ ])
+ ]);
+
+ var root = attachShadow(host, mode, [
+ element('span', [
+ element('slot')
+ ])
+ ]);
+
+ return {target: host.querySelector('i'), targetParent: host.querySelector('b'), host: host,
+ slot: root.querySelector('slot'), slotParent: root.querySelector('span'), root: root};
+ }
+
+ function testEventInDetachedShadowHostDescendant(mode) {
+ test(function () {
+ var shadow = createShadowHostWithAssignedGrandChild(mode);
+
+ log = dispatchEventWithLog(shadow, new Event('foo', {bubbles: true, composed: true}));
+
+ assert_equals(log.length, 6, 'EventPath must contain [target, target parent, slot, slot parent, shadow root, shadow host]');
+ assert_array_equals(log[0], [shadow.target, shadow.target], 'EventPath[0] must be the target');
+ assert_array_equals(log[1], [shadow.targetParent, shadow.target], 'EventPath[1] must be the parent of the target');
+ assert_array_equals(log[2], [shadow.slot, shadow.target], 'EventPath[2] must be the slot');
+ assert_array_equals(log[3], [shadow.slotParent, shadow.target], 'EventPath[3] must be the parent of the slot');
+ assert_array_equals(log[4], [shadow.root, shadow.target], 'EventPath[4] must be the shadow root');
+ assert_array_equals(log[5], [shadow.host, shadow.target], 'EventPath[5] must be the shadow host');
+
+ }, 'Firing an event inside a grand child of a detached ' + mode + ' mode shadow host');
+ }
+
+ testEventInDetachedShadowHostDescendant('open');
+ testEventInDetachedShadowHostDescendant('closed');
+
+ function testEventInShadowHostDescendantInsideDocument(mode) {
+ test(function () {
+ var shadow = createShadowHostWithAssignedGrandChild(mode);
+ document.body.appendChild(shadow.host);
+
+ log = dispatchEventWithLog(shadow, new Event('foo', {bubbles: true, composed: true}));
+
+ assert_equals(log.length, 9, 'EventPath must contain [target, target parent, slot, slot parent, shadow root, shadow host, body, html, document]');
+ assert_array_equals(log[0], [shadow.target, shadow.target], 'EventPath[0] must be the target');
+ assert_array_equals(log[1], [shadow.targetParent, shadow.target], 'EventPath[1] must be the parent of the target');
+ assert_array_equals(log[2], [shadow.slot, shadow.target], 'EventPath[2] must be the slot');
+ assert_array_equals(log[3], [shadow.slotParent, shadow.target], 'EventPath[3] must be the parent of the slot');
+ assert_array_equals(log[4], [shadow.root, shadow.target], 'EventPath[4] must be the shadow root');
+ assert_array_equals(log[5], [shadow.host, shadow.target], 'EventPath[5] must be the shadow host');
+ assert_array_equals(log[6], [document.body, shadow.target], 'EventPath[6] must be the body element');
+ assert_array_equals(log[7], [document.documentElement, shadow.target], 'EventPath[7] must be the html element');
+ assert_array_equals(log[8], [document, shadow.target], 'EventPath[8] must be the html element');
+
+ }, 'Firing an event inside a grand child of an in-document ' + mode + ' mode shadow host');
+ }
+
+ testEventInShadowHostDescendantInsideDocument('open');
+ testEventInShadowHostDescendantInsideDocument('closed');
+
+ function createNestedShadowTreesWithSlots(innerMode, outerUpperMode, outerLowerMode) {
+ var upperHost = element('upper-host', [
+ element('p', [
+ element('lower-host', [
+ element('a')
+ ])
+ ])
+ ]);
+
+ var upperShadow = attachShadow(upperHost, outerUpperMode, [
+ element('b', [
+ element('slot', [], 'upper-slot')
+ ])
+ ]);
+
+ var lowerHost = upperHost.querySelector('lower-host');
+ var lowerShadow = attachShadow(lowerHost, outerLowerMode, [
+ element('em', [
+ element('inner-host', [
+ element('span', [
+ element('slot', [], 'lower-slot')
+ ])
+ ])
+ ])
+ ]);
+
+ innerShadow = attachShadow(lowerShadow.querySelector('inner-host'), innerMode, [
+ element('i', [
+ element('slot', [], 'inner-slot')
+ ])
+ ]);
+
+ return {
+ host: upperHost,
+ target: upperHost.querySelector('a'),
+ upperShadow: upperShadow,
+ upperSlot: upperShadow.querySelector('slot'),
+ lowerShadow: lowerShadow,
+ lowerSlot: lowerShadow.querySelector('slot'),
+ innerShadow: innerShadow,
+ innerSlot: innerShadow.querySelector('slot'),
+ };
+ }
+
+ /*
+ upper-host (14) -- (upperShadow; 13)
+ + p (10) + b (12)
+ | + slot (upperSlot; 11)
+ + lower-host (9) -- (lowerShadow; 8)
+ + a (target; 0) + em (7)
+ + inner-host (6) -------- (innerShadow; 5)
+ + span (2) + i (4)
+ + slot (lowerSlot; 1) + slot (innerSlot; 3)
+ */
+
+ function testEventUnderTwoShadowRoots(outerUpperMode, outerLowerMode, innerMode) {
+ test(function () {
+ var shadow = createNestedShadowTreesWithSlots(innerMode, outerUpperMode, outerLowerMode);
+
+ log = dispatchEventWithLog(shadow, new Event('foo', {bubbles: true, composed: true}));
+
+ assert_equals(log.length, 15, 'EventPath must contain 15 targets');
+
+ assert_array_equals(log[0], [shadow.target, shadow.target], 'EventPath[0] must be the target');
+ assert_array_equals(log[1], [shadow.lowerSlot, shadow.target], 'EventPath[1] must be the slot inside the lower shadow tree');
+ assert_array_equals(log[2], [shadow.lowerSlot.parentNode, shadow.target], 'EventPath[2] must be the parent of the slot inside the lower shadow tree');
+ assert_array_equals(log[3], [shadow.innerSlot, shadow.target], 'EventPath[3] must be the slot inside the shadow tree inside the lower shadow tree');
+ assert_array_equals(log[4], [shadow.innerSlot.parentNode, shadow.target], 'EventPath[4] must be the child of the inner shadow root');
+ assert_array_equals(log[5], [shadow.innerShadow, shadow.target], 'EventPath[5] must be the inner shadow root');
+ assert_array_equals(log[6], [shadow.innerShadow.host, shadow.target], 'EventPath[6] must be the host of the inner shadow tree');
+ assert_array_equals(log[7], [shadow.lowerShadow.firstChild, shadow.target], 'EventPath[7] must be the parent of the inner shadow host');
+ assert_array_equals(log[8], [shadow.lowerShadow, shadow.target], 'EventPath[8] must be the lower shadow root');
+ assert_array_equals(log[9], [shadow.lowerShadow.host, shadow.target], 'EventPath[9] must be the lower shadow host');
+ assert_array_equals(log[10], [shadow.host.firstChild, shadow.target], 'EventPath[10] must be the parent of the grand parent of the target');
+ assert_array_equals(log[11], [shadow.upperSlot, shadow.target], 'EventPath[11] must be the slot inside the upper shadow tree');
+ assert_array_equals(log[12], [shadow.upperSlot.parentNode, shadow.target], 'EventPath[12] must be the parent of the slot inside the upper shadow tree');
+ assert_array_equals(log[13], [shadow.upperShadow, shadow.target], 'EventPath[13] must be the upper shadow root');
+ assert_array_equals(log[14], [shadow.host, shadow.target], 'EventPath[14] must be the host');
+
+ }, 'Firing an event on a node with two ancestors with a detached ' + outerUpperMode + ' and ' + outerLowerMode
+ + ' shadow trees with an inner ' + innerMode + ' shadow tree');
+ }
+
+ testEventUnderTwoShadowRoots('open', 'open', 'open');
+ testEventUnderTwoShadowRoots('open', 'open', 'closed');
+ testEventUnderTwoShadowRoots('open', 'closed', 'open');
+ testEventUnderTwoShadowRoots('open', 'closed', 'closed');
+ testEventUnderTwoShadowRoots('closed', 'open', 'open');
+ testEventUnderTwoShadowRoots('closed', 'open', 'closed');
+ testEventUnderTwoShadowRoots('closed', 'closed', 'open');
+ testEventUnderTwoShadowRoots('closed', 'closed', 'closed');
+
+ /*
+ upper-host (11) -- (upperShadow; 10)
+ + p (7) + b (9)
+ | + slot (upperSlot; 8)
+ + lower-host (6) -- (lowerShadow; 5)
+ + a + em (4)
+ + inner-host (3) -- (innerShadow; 2)
+ + span + i (1)
+ + slot + slot (innerSlot, target; 0)
+ */
+
+ function testEventInsideNestedShadowsUnderAnotherShadow(outerUpperMode, outerLowerMode, innerMode) {
+ test(function () {
+ var shadow = createNestedShadowTreesWithSlots(innerMode, outerUpperMode, outerLowerMode);
+ shadow.deepestNodeInLightDOM = shadow.target; // Needed for dispatchEventWithLog to attach event listeners.
+ shadow.target = shadow.innerSlot;
+
+ log = dispatchEventWithLog(shadow, new Event('foo', {bubbles: true, composed: true}));
+
+ assert_equals(log.length, 12, 'EventPath must contain 12 targets');
+
+ assert_array_equals(log[0], [shadow.target, shadow.target], 'EventPath[0] must be the target');
+ assert_array_equals(log[1], [shadow.target.parentNode, shadow.target], 'EventPath[1] must be the parent of the target');
+ assert_array_equals(log[2], [shadow.innerShadow, shadow.target], 'EventPath[2] must be the inner shadow root');
+ assert_array_equals(log[3], [shadow.innerShadow.host, shadow.innerShadow.host], 'EventPath[3] must be the inner shadow host');
+ assert_array_equals(log[4], [shadow.lowerShadow.firstChild, shadow.innerShadow.host], 'EventPath[4] must be the parent of the inner shadow host');
+ assert_array_equals(log[5], [shadow.lowerShadow, shadow.innerShadow.host], 'EventPath[5] must be the lower (but outer) shadow root');
+ assert_array_equals(log[6], [shadow.lowerShadow.host, shadow.lowerShadow.host], 'EventPath[6] must be the lower (but outer) shadow root');
+ assert_array_equals(log[7], [shadow.host.firstChild, shadow.lowerShadow.host], 'EventPath[7] must be the slot inside the upper shadow tree');
+ assert_array_equals(log[8], [shadow.upperSlot, shadow.lowerShadow.host], 'EventPath[8] must be the slot inside the upper shadow tree');
+ assert_array_equals(log[9], [shadow.upperSlot.parentNode, shadow.lowerShadow.host], 'EventPath[9] must be the parent of the slot inside the upper shadow tree');
+ assert_array_equals(log[10], [shadow.upperShadow, shadow.lowerShadow.host], 'EventPath[10] must be the upper shadow root');
+ assert_array_equals(log[11], [shadow.upperShadow.host, shadow.lowerShadow.host], 'EventPath[11] must be the host');
+
+ }, 'Firing an event on a node with two ancestors with a detached ' + outerUpperMode + ' and ' + outerLowerMode
+ + ' shadow trees with an inner ' + innerMode + ' shadow tree');
+ }
+
+ testEventInsideNestedShadowsUnderAnotherShadow('open', 'open', 'open');
+ testEventInsideNestedShadowsUnderAnotherShadow('open', 'open', 'closed');
+ testEventInsideNestedShadowsUnderAnotherShadow('open', 'closed', 'open');
+ testEventInsideNestedShadowsUnderAnotherShadow('open', 'closed', 'closed');
+ testEventInsideNestedShadowsUnderAnotherShadow('closed', 'open', 'open');
+ testEventInsideNestedShadowsUnderAnotherShadow('closed', 'open', 'closed');
+ testEventInsideNestedShadowsUnderAnotherShadow('closed', 'closed', 'open');
+ testEventInsideNestedShadowsUnderAnotherShadow('closed', 'closed', 'closed');
+
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/event-with-related-target.html b/testing/web-platform/tests/shadow-dom/event-with-related-target.html
new file mode 100644
index 000000000..ad74e72b2
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/event-with-related-target.html
@@ -0,0 +1,256 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Shadow DOM: Firing an event with relatedTarget inside a shadow tree</title>
+ <meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+ <meta name="assert" content="The retargeting algorithm is used to determine relative targets">
+ <link rel="help" href="https://w3c.github.io/webcomponents/spec/shadow/#retargeting-relatedtarget">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="resources/event-path-test-helpers.js"></script>
+</head>
+<body>
+ <div id="log"></div>
+ <script>
+
+ /*
+ -SR: ShadowRoot -S: Slot target: (~) relatedTarget: [~] *: indicates start digit: event path order
+ A ----------------------------------------------- A-SR
+ + B ----------- B-SR (4) + A1 --- A1-SR
+ + C + B1 (3) [*; 0-4] --- B1-SR (2) + A2-S + A1a
+ + D --- D-SR + B1a (*; 0) + B1b [1,2] --- B1b-SR
+ + D1 + B1c-S (1) + B1b1
+ + B1b2
+ */
+ function testEventAtB1aWithB1a(mode) {
+ test(function () {
+ var nodes = createTestTree(mode);
+
+ log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: nodes.B1}));
+
+ assert_array_equals(log.eventPath,
+ ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR'], 'The event path must be correct.');
+ assert_array_equals(log.relatedTargets,
+ ['B1', 'B1', 'B1', 'B1', 'B1'], 'The related targets must be correct.');
+
+ }, 'Firing an event at B1a with relatedNode at B1 with ' + mode + ' mode shadow trees');
+ }
+
+ testEventAtB1aWithB1a('open');
+ testEventAtB1aWithB1a('closed');
+
+ /*
+ -SR: ShadowRoot -S: Slot target: (~) relatedTarget: [~] *: indicates start digit: event path order
+ A ------------------------------------------------- A-SR
+ + B ----------- B-SR (4) + A1 --- A1-SR
+ + C + B1 (3) [0,3-4] --- B1-SR (2) + A2-S + A1a
+ + D --- D-SR + B1a (*; 0) + B1b [1,2] --- B1b-SR
+ + D1 + B1c-S (1) + B1b1 [*]
+ + B1b2
+ */
+ function testEventAtB1aWithB1b1(mode) {
+ test(function () {
+ var nodes = createTestTree(mode);
+
+ log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: nodes.B1b1}));
+
+ assert_array_equals(log.eventPath,
+ ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR'], 'The event path must be correct.');
+ assert_array_equals(log.relatedTargets,
+ ['B1', 'B1b', 'B1b', 'B1', 'B1'], 'The related targets must be correct.');
+
+ }, 'Firing an event at B1a with relatedNode at B1b1 with ' + mode + ' mode shadow trees');
+ }
+
+ testEventAtB1aWithB1b1('open');
+ testEventAtB1aWithB1b1('closed');
+
+ /*
+ -SR: ShadowRoot -S: Slot target: (~) relatedTarget: [~] *: indicates start digit: event path order
+ A -------------------------------------------------- A-SR
+ + B ------------- B-SR (5) + A1 --- A1-SR
+ + C + B1 (4) ------- B1-SR (3) + A2-S + A1a
+ + D --- D-SR + B1a [*; 0-5] + B1b (2) --- B1b-SR (1)
+ + D1 + B1c-S + B1b1 (*; 0)
+ + B1b2
+ */
+ function testEventAtB1b1WithB1a(mode) {
+ test(function () {
+ var nodes = createTestTree(mode);
+
+ log = dispatchEventWithLog(nodes, nodes.B1b1, new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: nodes.B1a}));
+
+ assert_array_equals(log.eventPath,
+ ['B1b1', 'B1b-SR', 'B1b', 'B1-SR', 'B1', 'B-SR'], 'The event path must be correct.');
+ assert_array_equals(log.relatedTargets,
+ ['B1a', 'B1a', 'B1a', 'B1a', 'B1a', 'B1a'], 'The related targets must be correct.');
+
+ }, 'Firing an event at B1b1 with relatedNode at B1a with ' + mode + ' mode shadow trees');
+ }
+
+ testEventAtB1b1WithB1a('open');
+ testEventAtB1b1WithB1a('closed');
+
+ /*
+ -SR: ShadowRoot -S: Slot target: (~) relatedTarget: [~] *: indicates start digit: event path order
+ A (8) -------------------------------------------------- A-SR (7)
+ + B (5) -------------- B-SR (4) + A1 -------- A1-SR
+ + C + B1 (3) [*; 0-4] --- B1-SR (2) + A2-S (6) + A1a
+ + D [0-8] --- D-SR + B1a (*; 0) + B1b ------ B1b-SR
+ + D1 [*] + B1c-S (1) + B1b1
+ + B1b2
+ */
+ function testEventAtB1aWithD1(mode) {
+ test(function () {
+ var nodes = createTestTree(mode);
+
+ log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: nodes.D1}));
+
+ assert_array_equals(log.eventPath,
+ ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR', 'B', 'A2-S', 'A-SR', 'A'], 'The event path must be correct.');
+ assert_array_equals(log.relatedTargets,
+ ['D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D'], 'The related targets must be correct.');
+
+ }, 'Firing an event at B1a with relatedNode at D1 with ' + mode + ' mode shadow trees');
+ }
+
+ testEventAtB1aWithD1('open');
+ testEventAtB1aWithD1('closed');
+
+ /*
+ -SR: ShadowRoot -S: Slot target: (~) relatedTarget: [~] *: indicates start digit: event path order
+ A (6) ----------------------------------- A-SR (5)
+ + B (3) [0] ----------- B-SR + A1 ------ A1-SR
+ + C + B1 ----- B1-SR + A2-S (4) + A1a
+ + D (2) --- D-SR (1) + B1a [*] + B1b --- B1b-SR
+ + D1 (*; 0) + B1c-S + B1b1
+ + B1b2
+ */
+ function testEventAtD1WithB1a(mode) {
+ test(function () {
+ var nodes = createTestTree(mode);
+
+ log = dispatchEventWithLog(nodes, nodes.D1, new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: nodes.B1a}));
+
+ assert_array_equals(log.eventPath,
+ ['D1', 'D-SR', 'D', 'B', 'A2-S', 'A-SR', 'A'], 'The event path must be correct.');
+ assert_array_equals(log.relatedTargets,
+ ['B', 'B', 'B', 'B', 'B', 'B', 'B'], 'The related targets must be correct.');
+
+ }, 'Firing an event at D1 with relatedNode at B1a with ' + mode + ' mode shadow trees');
+ }
+
+ testEventAtD1WithB1a('open');
+ testEventAtD1WithB1a('closed');
+
+ /*
+ -SR: ShadowRoot -S: Slot target: (~) relatedTarget: [~] *: indicates start digit: event path order
+ A (8) [0-5,8] ---------------------------------------- A-SR (7)
+ + B (5) ------- B-SR (4) + A1 [6,7] --- A1-SR
+ + C + B1 (3) ----- B1-SR (2) + A2-S (6) + A1a [*]
+ + D --- D-SR + B1a (*; 0) + B1b ------- B1b-SR
+ + D1 + B1c-S (1) + B1b1
+ + B1b2
+ */
+ function testEventAtB1aWithA1a(mode) {
+ test(function () {
+ var nodes = createTestTree(mode);
+
+ log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: nodes.A1a}));
+
+ assert_array_equals(log.eventPath,
+ ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR', 'B', 'A2-S', 'A-SR', 'A'], 'The event path must be correct.');
+ assert_array_equals(log.relatedTargets,
+ ['A', 'A', 'A', 'A', 'A', 'A', 'A1', 'A1', 'A'], 'The related targets must be correct.');
+
+ }, 'Firing an event at B1a with relatedNode at A1a with ' + mode + ' mode shadow trees');
+ }
+
+ testEventAtB1aWithA1a('open');
+ testEventAtB1aWithA1a('closed');
+
+ /*
+ -SR: ShadowRoot -S: Slot target: (~) relatedTarget: [~] *: indicates start digit: event path order
+ A (4) ----------------------------------------- A-SR (3)
+ + B [0-4] ----- B-SR + A1 (2) --- A1-SR (1)
+ + C + B1 ------- B1-SR + A2-S + A1a (*; 0)
+ + D --- D-SR + B1a [*] + B1b --- B1b-SR
+ + D1 + B1c-S + B1b1
+ + B1b2
+ */
+ function testEventAtA1aWithB1a(mode) {
+ test(function () {
+ var nodes = createTestTree(mode);
+
+ log = dispatchEventWithLog(nodes, nodes.A1a, new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: nodes.B1a}));
+
+ assert_array_equals(log.eventPath,
+ ['A1a', 'A1-SR', 'A1', 'A-SR', 'A'], 'The event path must be correct.');
+ assert_array_equals(log.relatedTargets,
+ ['B', 'B', 'B', 'B', 'B'], 'The related targets must be correct.');
+
+ }, 'Firing an event at B1a with relatedNode at A1a with ' + mode + ' mode shadow trees');
+ }
+
+ testEventAtA1aWithB1a('open');
+ testEventAtA1aWithB1a('closed');
+
+ /*
+ -SR: ShadowRoot -S: Slot target: (~) relatedTarget: [~] *: indicates start digit: event path order
+ A (8) ----------------------------------- A-SR (7)
+ + B (5) ----- B-SR (4) + A2-S (6)
+ + C + B1 (3) ----- B1-SR (2)
+ + D --- D-SR + B1a (*; 0) + B1b ------- B1b-SR
+ + D1 + B1c-S (1) + B1b1
+ + B1b2
+ A1 [0-6] --- A1-SR
+ + A1a [*]
+ */
+ function testEventAtB1aWithDetachedA1a(mode) {
+ test(function () {
+ var nodes = createTestTree(mode);
+
+ nodes['A-SR'].removeChild(nodes.A1);
+ log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: nodes.A1a}));
+
+ assert_array_equals(log.eventPath,
+ ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR', 'B', 'A2-S', 'A-SR', 'A'], 'The event path must be correct.');
+ assert_array_equals(log.relatedTargets,
+ ['A1', 'A1', 'A1', 'A1', 'A1', 'A1', 'A1', 'A1', 'A1'], 'The related targets must be correct.');
+
+ }, 'Firing an event at B1a with relatedNode at A1a with ' + mode + ' mode shadow trees');
+ }
+
+ testEventAtB1aWithDetachedA1a('open');
+ testEventAtB1aWithDetachedA1a('closed');
+
+ /*
+ -SR: ShadowRoot -S: Slot target: (~) relatedTarget: [~] *: indicates start digit: event path order
+ A ----------------------------------- A-SR
+ + B [0-3] ----- B-SR + A2-S
+ + C + B1 -------- B1-SR
+ + D --- D-SR + B1a [*] + B1b --- B1b-SR
+ + D1 + B1c-S + B1b1
+ + B1b2
+ A1 (2) --- A1-SR (1)
+ + A1a (*; 0)
+ */
+ function testEventAtA1aWithDetachedB1a(mode) {
+ test(function () {
+ var nodes = createTestTree(mode);
+
+ nodes['A-SR'].removeChild(nodes.A1);
+ log = dispatchEventWithLog(nodes, nodes.A1a, new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: nodes.B1a}));
+
+ assert_array_equals(log.eventPath, ['A1a', 'A1-SR', 'A1'], 'The event path must be correct.');
+ assert_array_equals(log.relatedTargets, ['B', 'B', 'B' ], 'The related targets must be correct.');
+
+ }, 'Firing an event at B1a with relatedNode at A1a with ' + mode + ' mode shadow trees');
+ }
+
+ testEventAtA1aWithDetachedB1a('open');
+ testEventAtA1aWithDetachedB1a('closed');
+
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/leaktests/get-elements.html b/testing/web-platform/tests/shadow-dom/leaktests/get-elements.html
new file mode 100644
index 000000000..2ce916a65
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/leaktests/get-elements.html
@@ -0,0 +1,174 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta name='author' title='Google' href='http://www.google.com'>
+<meta name='assert' content='getElement* API in document should not leak any node in shadow tree.'>
+<link rel='help' href='https://w3c.github.io/webcomponents/spec/shadow/'>
+<script src='/resources/testharness.js'></script>
+<script src='/resources/testharnessreport.js'></script>
+</head>
+<body>
+
+<!-- This template will be filled in '#doc', '#host-open', and '#host-closed' below -->
+<template id='domtree-template'>
+ <span id='foo'></span>
+ <div class='bar'></div>
+ <form name='baz'></form>
+ <my-element></my-element>
+</template>
+
+<div id='doc'>
+ <div id='host-open'></div>
+ <div id='host-closed'></div>
+</div>
+
+</body>
+<script>
+'use strict';
+
+function fillTemplate(root, prefix) {
+ var tmpl = document.getElementById('domtree-template');
+ root.appendChild(document.importNode(tmpl.content, true));
+ for (var i = 0; i < root.childNodes.length; ++i) {
+ var el = root.childNodes[i];
+ if (el.nodeType != 1)
+ continue;
+ el.setAttribute('label', prefix + el.tagName.toLowerCase());
+ }
+
+ root.appendChild(document.createElementNS('http://www.w3.org/2000/svg', 'linearGradient'));
+}
+
+// Construct subtree with 'doc-*' ids.
+var doc = document.getElementById('doc');
+fillTemplate(doc, 'doc-');
+
+// Construct shadow subtree with 'shadow-*' ids.
+var hostOpen = document.getElementById('host-open');
+var shadowOpen = hostOpen.attachShadow({mode: 'open'});
+fillTemplate(shadowOpen, 'shadow-open-');
+
+var hostClosed = document.getElementById('host-closed');
+var shadowClosed = hostClosed.attachShadow({mode: 'closed'});
+fillTemplate(shadowClosed, 'shadow-closed-');
+
+test(function() {
+ // getElementById() (NonElementParentNode)
+ assert_equals(document.querySelectorAll('#foo').length, 1);
+ assert_equals(document.getElementById('foo').getAttribute('label'), 'doc-span');
+ assert_equals(document.querySelector('#foo').getAttribute('label'), 'doc-span');
+
+ assert_equals(doc.querySelectorAll('#foo').length, 1);
+ assert_equals(doc.querySelector('#foo').getAttribute('label'), 'doc-span');
+
+ assert_equals(hostOpen.querySelectorAll('#foo').length, 0);
+
+ assert_equals(shadowOpen.querySelectorAll('#foo').length, 1);
+ assert_equals(shadowOpen.getElementById('foo').getAttribute('label'), 'shadow-open-span');
+ assert_equals(shadowOpen.querySelector('#foo').getAttribute('label'), 'shadow-open-span');
+
+ assert_equals(hostClosed.querySelectorAll('#foo').length, 0);
+
+ assert_equals(shadowClosed.querySelectorAll('#foo').length, 1);
+ assert_equals(shadowClosed.getElementById('foo').getAttribute('label'), 'shadow-closed-span');
+ assert_equals(shadowClosed.querySelector('#foo').getAttribute('label'), 'shadow-closed-span');
+}, 'getElementsById() should not leak nodes in shadow tree');
+
+test(function() {
+ // getElementsByClassName() (Element, Document)
+ assert_equals(document.getElementsByClassName('bar').length, 1);
+ assert_equals(document.getElementsByClassName('bar')[0].getAttribute('label'), 'doc-div');
+ assert_equals(document.getElementsByClassName('bar').length, 1);
+ assert_equals(document.getElementsByClassName('bar')[0].getAttribute('label'), 'doc-div');
+ assert_equals(document.querySelectorAll('.bar').length, 1);
+
+ assert_equals(doc.querySelectorAll('.bar').length, 1);
+ assert_equals(doc.getElementsByClassName('bar')[0].getAttribute('label'), 'doc-div');
+
+ assert_array_equals(hostOpen.querySelectorAll('.bar').length, 0);
+
+ assert_equals(shadowOpen.querySelectorAll('.bar').length, 1);
+ assert_equals(shadowOpen.querySelectorAll('.bar')[0].getAttribute('label'), 'shadow-open-div');
+
+ assert_array_equals(hostClosed.querySelectorAll('.bar').length, 0);
+
+ assert_equals(shadowClosed.querySelectorAll('.bar').length, 1);
+ assert_equals(shadowClosed.querySelectorAll('.bar')[0].getAttribute('label'), 'shadow-closed-div');
+}, 'getElementsByClassName() should not leak nodes in shadow tree');
+
+test(function() {
+ // getElementsByName (Document)
+ assert_equals(document.getElementsByName('baz').length, 1);
+ assert_equals(document.getElementsByName('baz')[0].getAttribute('label'), 'doc-form');
+ assert_equals(document.getElementsByName('baz').length, 1);
+ assert_equals(document.getElementsByName('baz')[0].getAttribute('label'), 'doc-form');
+ assert_equals(document.querySelectorAll('[name=baz]').length, 1);
+
+ assert_equals(doc.querySelectorAll('[name=baz]').length, 1);
+
+ assert_array_equals(hostOpen.querySelectorAll('[name=baz]').length, 0);
+ assert_equals(shadowOpen.querySelectorAll('[name=baz]').length, 1);
+ assert_equals(shadowOpen.querySelectorAll('[name=baz]')[0].getAttribute('label'), 'shadow-open-form');
+
+ assert_array_equals(hostClosed.querySelectorAll('[name=baz]').length, 0);
+ assert_equals(shadowClosed.querySelectorAll('[name=baz]').length, 1);
+ assert_equals(shadowClosed.querySelectorAll('[name=baz]')[0].getAttribute('label'), 'shadow-closed-form');
+}, 'getElementsByName() should not leak nodes in shadow tree');
+
+test(function() {
+ // getElementsByTagName (Element, Document)
+ assert_equals(document.getElementsByTagName('my-element').length, 1);
+ assert_equals(document.getElementsByTagName('my-element')[0].getAttribute('label'), 'doc-my-element');
+ assert_equals(document.getElementsByTagName('my-element').length, 1);
+ assert_equals(document.getElementsByTagName('my-element')[0].getAttribute('label'), 'doc-my-element');
+ assert_equals(document.querySelectorAll('my-element').length, 1);
+
+ assert_equals(doc.querySelectorAll('my-element').length, 1);
+ assert_equals(doc.getElementsByTagName('my-element')[0].getAttribute('label'), 'doc-my-element');
+
+ assert_array_equals(hostOpen.querySelectorAll('my-element').length, 0);
+ // ShadowRoot isn't an Element, does not have getElementsByTagName().
+ assert_equals(shadowOpen.querySelectorAll('my-element').length, 1);
+ assert_equals(shadowOpen.querySelectorAll('my-element')[0].getAttribute('label'), 'shadow-open-my-element');
+
+ assert_array_equals(hostClosed.querySelectorAll('my-element').length, 0);
+ assert_equals(shadowClosed.querySelectorAll('my-element').length, 1);
+ assert_equals(shadowClosed.querySelectorAll('my-element')[0].getAttribute('label'), 'shadow-closed-my-element');
+}, 'getElementsByTagName() should not leak nodes in shadow tree');
+
+test(function() {
+ // getElementsByTagNameNS (Element, Document)
+ assert_equals(document.getElementsByTagName('lineargradient').length, 0);
+ assert_equals(document.getElementsByTagNameNS('*', 'lineargradient').length, 0);
+ assert_equals(document.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'lineargradient').length, 0);
+ assert_equals(document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'lineargradient').length, 0);
+
+ assert_equals(document.getElementsByTagName('linearGradient').length, 1);
+ assert_equals(document.getElementsByTagNameNS('*', 'linearGradient').length, 1);
+ assert_equals(document.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'linearGradient').length, 1);
+ assert_equals(document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'linearGradient').length, 0);
+
+ assert_equals(doc.getElementsByTagName('lineargradient').length, 0);
+ assert_equals(doc.getElementsByTagNameNS('*', 'lineargradient').length, 0);
+ assert_equals(doc.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'lineargradient').length, 0);
+ assert_equals(doc.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'lineargradient').length, 0);
+
+ assert_equals(doc.getElementsByTagName('linearGradient').length, 1);
+ assert_equals(doc.getElementsByTagNameNS('*', 'linearGradient').length, 1);
+ assert_equals(doc.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'linearGradient').length, 1);
+ assert_equals(doc.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'linearGradient').length, 0);
+
+ assert_equals(hostOpen.getElementsByTagName('linearGradient').length, 0);
+ assert_equals(hostOpen.getElementsByTagNameNS('*', 'linearGradient').length, 0);
+ assert_equals(hostOpen.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'linearGradient').length, 0);
+ assert_equals(hostOpen.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'linearGradient').length, 0);
+
+ assert_equals(hostClosed.getElementsByTagName('linearGradient').length, 0);
+ assert_equals(hostClosed.getElementsByTagNameNS('*', 'linearGradient').length, 0);
+ assert_equals(hostClosed.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'linearGradient').length, 0);
+ assert_equals(hostClosed.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'linearGradient').length, 0);
+
+ // ShadowRoot isn't an Element, does not have getElementsByTagNameNS().
+}, 'getElementsByTagNameNS() should not leak nodes in shadow tree');
+</script>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/leaktests/html-collection.html b/testing/web-platform/tests/shadow-dom/leaktests/html-collection.html
new file mode 100644
index 000000000..d15656971
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/leaktests/html-collection.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta name='author' title='Google' href='http://www.google.com'>
+<meta name='assert' content='document attributes that returns HTMLCollection should not expose nodes in shadow tree.'>
+<link rel='help' href='https://w3c.github.io/webcomponents/spec/shadow/'>
+<script src='/resources/testharness.js'></script>
+<script src='/resources/testharnessreport.js'></script>
+</head>
+<body>
+<template id='collection-template'>
+ <img>
+ <embed></embed>
+ <applet></applet>
+ <object type='application/x-java-applet'></object>
+ <a href='http://example.com'></a>
+ <a name='test'></a>
+ <form name='test'></form>
+ <script></script>
+</template>
+<div id='doc'></div>
+<div id='host-open'></div>
+<div id='host-closed'></div>
+</body>
+<script>
+'use strict';
+
+function fillTemplate(root, prefix) {
+ var tmpl = document.getElementById('collection-template');
+ root.appendChild(document.importNode(tmpl.content, true));
+ for (var i = 0; i < root.childNodes.length; ++i) {
+ var el = root.childNodes[i];
+ if (el.nodeType != 1)
+ continue;
+ el.id = prefix + el.tagName.toLowerCase();
+ }
+}
+
+// Construct subtree with 'doc-*' ids.
+var doc = document.getElementById('doc');
+fillTemplate(doc, 'doc-');
+
+// Construct shadow subtree with 'shadow-*' ids.
+var host = document.getElementById('host-open');
+var shadow = host.attachShadow({mode: 'open'});
+fillTemplate(shadow, 'shadow-open-');
+
+host = document.getElementById('host-closed');
+shadow = host.attachShadow({mode: 'closed'});
+fillTemplate(shadow, 'shadow-closed-');
+
+function testCollection(collection) {
+ var elements = document[collection];
+ assert_greater_than(elements.length, 0, 'document.' + collection + ' should have at least 1 element.');
+ for (var i = 0; i < elements.length; ++i) {
+ if (elements[i].id) {
+ assert_equals(elements[i].id.indexOf('shadow-'), -1, 'document.' + collection + ' should not contain elements in shadow tree.');
+ }
+ }
+}
+
+var testParams = [
+ ['document.scripts should not contain shadow nodes', 'scripts'],
+ ['document.all should not contain shadow nodes', 'all'],
+ ['document.forms should not contain shadow nodes', 'forms'],
+ ['document.images should not contain shadow nodes', 'images'],
+ ['document.links should not contain shadow nodes', 'links'],
+ ['document.anchors should not contain shadow nodes', 'anchors'],
+ ['document.embeds should not contain shadow nodes', 'embeds'],
+ ['document.plugins should not contain shadow nodes', 'plugins'],
+ ['document.applets should not contain shadow nodes', 'applets']];
+
+generate_tests(testCollection, testParams);
+
+</script>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/leaktests/window-frames.html b/testing/web-platform/tests/shadow-dom/leaktests/window-frames.html
new file mode 100644
index 000000000..5ba2531ff
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/leaktests/window-frames.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta name='author' title='Google' href='http://www.google.com'>
+<meta name='assert' content='Shadow DOM should not leak via window.frames.'>
+<link rel='help' href='https://w3c.github.io/webcomponents/spec/shadow/'>
+<script src='/resources/testharness.js'></script>
+<script src='/resources/testharnessreport.js'></script>
+</head>
+<body>
+<div id='log'></div>
+<iframe src='about:blank' name='mainFrame1'></iframe>
+<div id='host-open'></div>
+<div id='host-closed'></div>
+</body>
+<script>
+'use strict';
+
+var host_open = document.getElementById('host-open');
+var root_open = host_open.attachShadow({mode: 'open'});
+root_open.innerHTML = '<iframe src="about:blank" name="shadowFrame1"></iframe>';
+
+var host_closed = document.getElementById('host-closed');
+var root_closed = host_closed.attachShadow({mode: 'closed'});
+root_closed.innerHTML = '<iframe src="about:blank" name="shadowFrame2"></iframe>';
+
+test(() => {
+ assert_equals(window.frames.length, 1, 'window.frames should return only frames in document.');
+ assert_equals(window.frames[0].name, 'mainFrame1', 'window.frames[0] should be mainFrame1.');
+ assert_equals(window.frames['mainFrame1'], window.frames[0], 'window.frames[\'mainFrame1\'] should be equal to mainFrame1.');
+ assert_equals(window.frames['shadowFrame1'], undefined, 'shadowFrame1 should not leak.');
+ assert_equals(window.frames['shadowFrame2'], undefined, 'shadowFrame2 should not leak.');
+
+}, 'window.frames should not leak frames in Shadow DOM.');
+</script>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/resources/Document-prototype-currentScript-helper.js b/testing/web-platform/tests/shadow-dom/resources/Document-prototype-currentScript-helper.js
new file mode 100644
index 000000000..c25693cdb
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/resources/Document-prototype-currentScript-helper.js
@@ -0,0 +1 @@
+executeExternalScript();
diff --git a/testing/web-platform/tests/shadow-dom/resources/event-path-test-helpers.js b/testing/web-platform/tests/shadow-dom/resources/event-path-test-helpers.js
new file mode 100644
index 000000000..091bcd082
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/resources/event-path-test-helpers.js
@@ -0,0 +1,93 @@
+
+function dispatchEventWithLog(shadow, target, event) {
+ var eventPath = [];
+ var relatedTargets = [];
+ var pathAtTargets = [];
+
+ var attachedNodes = [];
+ for (var nodeKey in shadow) {
+ var startingNode = shadow[nodeKey];
+ for (var node = startingNode; node; node = node.parentNode) {
+ if (attachedNodes.indexOf(node) >= 0)
+ continue;
+ attachedNodes.push(node);
+ node.addEventListener(event.type, (function (event) {
+ eventPath.push(this.label);
+ relatedTargets.push(event.relatedTarget ? event.relatedTarget.label : null);
+
+ if (!event.composedPath) // Don't fail all tests just for the lack of composedPath.
+ return;
+
+ pathAtTargets.push(event.composedPath().map(function (node) { return node.label; }));
+ }).bind(node));
+ }
+ }
+
+ target.dispatchEvent(event);
+
+ return {eventPath: eventPath, relatedTargets: relatedTargets, pathAtTargets: pathAtTargets};
+}
+
+/*
+-SR: ShadowRoot -S: Slot
+A ------------------------------- A-SR
++ B ------------ B-SR + A1 --- A1-SR
+ + C + B1 --- B1-SR + A2-S + A1a
+ + D --- D-SR + B1a + B1b --- B1b-SR
+ + D1 + B1c-S + B1b1
+ + B1b2
+*/
+function createTestTree(mode) {
+ var namedNodes = {};
+
+ function element(name) {
+ var element = document.createElement(name.indexOf('-S') > 0 ? 'slot' : 'div');
+ element.label = name;
+ namedNodes[name] = element;
+ for (var i = 1; i < arguments.length; i++) {
+ var item = arguments[i];
+ if (typeof(item) == 'function')
+ item(element);
+ else
+ element.appendChild(item);
+ }
+ return element;
+ }
+
+ function shadow(name) {
+ var children = [];
+ for (var i = 1; i < arguments.length; i++)
+ children.push(arguments[i]);
+ return function (element) {
+ var shadowRoot = element.attachShadow({mode: mode});
+ shadowRoot.label = name;
+ namedNodes[name] = shadowRoot;
+ for (var child of children)
+ shadowRoot.appendChild(child);
+ }
+ }
+
+ var host = element('A',
+ shadow('A-SR',
+ element('A1',
+ shadow('A1-SR',
+ element('A1a'))),
+ element('A2-S')
+ ),
+ element('B',
+ shadow('B-SR',
+ element('B1',
+ shadow('B1-SR',
+ element('B1b',
+ shadow('B1b-SR',
+ element('B1b1'),
+ element('B1b2'))),
+ element('B1c-S')),
+ element('B1a'))),
+ element('C'),
+ element('D',
+ shadow('D-SR',
+ element('D1')))));
+
+ return namedNodes;
+}
diff --git a/testing/web-platform/tests/shadow-dom/resources/shadow-dom-utils.js b/testing/web-platform/tests/shadow-dom/resources/shadow-dom-utils.js
new file mode 100644
index 000000000..07db34336
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/resources/shadow-dom-utils.js
@@ -0,0 +1,154 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+
+/*
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+*/
+
+"use strict";
+
+// custom element is also allowed.
+var ATTACHSHADOW_SAFELISTED_ELEMENTS = [
+ 'article',
+ 'aside',
+ 'blockquote',
+ 'body',
+ 'div',
+ 'footer',
+ 'h1',
+ 'h2',
+ 'h3',
+ 'h4',
+ 'h5',
+ 'h6',
+ 'header',
+ 'nav',
+ 'p',
+ 'section',
+ 'span'
+];
+
+var HTML5_ELEMENT_NAMES = [
+ 'a', 'abbr', 'address', 'area', 'article', 'aside', 'audio',
+ 'b', 'base', 'bdi', 'bdo', 'blockquote', 'body', 'br', 'button',
+ 'canvas', 'caption', 'cite', 'code', 'col', 'colgroup', 'command',
+ 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'div', 'dl', 'dt',
+ 'em', 'embed',
+ 'fieldset', 'figcaption', 'figure', 'footer', 'form',
+ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr',
+ 'html',
+ 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'keygen',
+ 'label', 'legend', 'li', 'link',
+ 'map', 'mark', 'menu', 'meta', 'meter',
+ 'nav', 'noscript',
+ 'object', 'ol', 'optgroup', 'option', 'output',
+ 'p', 'param', 'pre', 'progress',
+ 'q',
+ 'rp', 'rt', 'ruby',
+ 's', 'samp', 'script', 'section', 'select', 'small', 'source', 'span',
+ 'strong', 'style', 'sub',
+ 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'time',
+ 'title', 'tr', 'track',
+ 'u', 'ul',
+ 'var', 'video',
+ 'wbr'
+];
+
+function unit(f) {
+ return function () {
+ var ctx = newContext();
+ try {
+ f(ctx);
+ } finally {
+ cleanContext(ctx);
+ }
+ }
+}
+
+function step_unit(f, ctx, t) {
+ return function () {
+ var done = false;
+ try {
+ f();
+ done = true;
+ } finally {
+ if (done) {
+ t.done();
+ }
+ cleanContext(ctx);
+ }
+ }
+}
+
+function assert_nodelist_contents_equal_noorder(actual, expected, message) {
+ assert_equals(actual.length, expected.length, message);
+ var used = [];
+ for (var i = 0; i < expected.length; i++) {
+ used.push(false);
+ }
+ for (i = 0; i < expected.length; i++) {
+ var found = false;
+ for (var j = 0; j < actual.length; j++) {
+ if (used[j] == false && expected[i] == actual[j]) {
+ used[j] = true;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ assert_unreached(message + ". Fail reason: element not found: " + expected[i]);
+ }
+ }
+}
+
+//Example taken from http://www.w3.org/TR/shadow-dom/#event-retargeting-example
+function createTestMediaPlayer(d) {
+ d.body.innerHTML = '' +
+ '<div id="player">' +
+ '<input type="checkbox" id="outside-control">' +
+ '<div id="player-shadow-host">' +
+ '</div>' +
+ '</div>';
+
+ var playerShadowRoot = d.querySelector('#player-shadow-host').attachShadow({mode: 'open'});
+ playerShadowRoot.innerHTML = '' +
+ '<div id="controls">' +
+ '<button class="play-button">PLAY</button>' +
+ '<div tabindex="0" id="timeline">' +
+ '<div id="timeline-shadow-host">' +
+ '</div>' +
+ '</div>' +
+ '<div class="volume-slider-container" id="volume-slider-container">' +
+ '<div tabindex="0" class="volume-slider" id="volume-slider">' +
+ '<div id="volume-shadow-host">' +
+ '</div>' +
+ '</div>' +
+ '</div>' +
+ '</div>';
+
+ var timeLineShadowRoot = playerShadowRoot.querySelector('#timeline-shadow-host').attachShadow({mode: 'open'});
+ timeLineShadowRoot.innerHTML = '<div class="slider-thumb" id="timeline-slider-thumb"></div>';
+
+ var volumeShadowRoot = playerShadowRoot.querySelector('#volume-shadow-host').attachShadow({mode: 'open'});
+ volumeShadowRoot.innerHTML = '<div class="slider-thumb" id="volume-slider-thumb"></div>';
+
+ return {
+ 'playerShadowRoot': playerShadowRoot,
+ 'timeLineShadowRoot': timeLineShadowRoot,
+ 'volumeShadowRoot': volumeShadowRoot
+ };
+}
+
+//FIXME This call of initKeyboardEvent works for WebKit-only.
+//See https://bugs.webkit.org/show_bug.cgi?id=16735
+// and https://bugs.webkit.org/show_bug.cgi?id=13368. Add check for browser here
+function fireKeyboardEvent(doc, element, key) {
+ var event = doc.createEvent('KeyboardEvent');
+ event.initKeyboardEvent("keydown", true, true, doc.defaultView, key, 0, false, false, false, false);
+ element.dispatchEvent(event);
+}
diff --git a/testing/web-platform/tests/shadow-dom/resources/shadow-dom.js b/testing/web-platform/tests/shadow-dom/resources/shadow-dom.js
new file mode 100644
index 000000000..3e55684da
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/resources/shadow-dom.js
@@ -0,0 +1,130 @@
+function removeWhiteSpaceOnlyTextNodes(node)
+{
+ for (var i = 0; i < node.childNodes.length; i++) {
+ var child = node.childNodes[i];
+ if (child.nodeType === Node.TEXT_NODE && child.nodeValue.trim().length == 0) {
+ node.removeChild(child);
+ i--;
+ } else if (child.nodeType === Node.ELEMENT_NODE || child.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
+ removeWhiteSpaceOnlyTextNodes(child);
+ }
+ }
+ if (node.shadowRoot) {
+ removeWhiteSpaceOnlyTextNodes(node.shadowRoot);
+ }
+}
+
+function createTestTree(node) {
+
+ let ids = {};
+
+ function attachShadowFromTemplate(template) {
+ let parent = template.parentNode;
+ parent.removeChild(template);
+ let shadowRoot;
+ if (template.getAttribute('data-mode') === 'v0') {
+ // For legacy Shadow DOM
+ shadowRoot = parent.createShadowRoot();
+ } else {
+ shadowRoot = parent.attachShadow({mode: template.getAttribute('data-mode')});
+ }
+ let id = template.id;
+ if (id) {
+ shadowRoot.id = id;
+ ids[id] = shadowRoot;
+ }
+ shadowRoot.appendChild(document.importNode(template.content, true));
+ return shadowRoot;
+ }
+
+ function walk(root) {
+ if (root.id) {
+ ids[root.id] = root;
+ }
+ for (let e of Array.from(root.querySelectorAll('[id]'))) {
+ ids[e.id] = e;
+ }
+ for (let e of Array.from(root.querySelectorAll('template'))) {
+ walk(attachShadowFromTemplate(e));
+ }
+ }
+
+ walk(node.cloneNode(true));
+ return ids;
+}
+
+function dispatchEventWithLog(nodes, target, event) {
+
+ function labelFor(e) {
+ return e.id || e.tagName;
+ }
+
+ let log = [];
+ let attachedNodes = [];
+ for (let label in nodes) {
+ let startingNode = nodes[label];
+ for (let node = startingNode; node; node = node.parentNode) {
+ if (attachedNodes.indexOf(node) >= 0)
+ continue;
+ let id = node.id;
+ if (!id)
+ continue;
+ attachedNodes.push(node);
+ node.addEventListener(event.type, (e) => {
+ // Record [currentTarget, target, relatedTarget, composedPath()]
+ log.push([id,
+ labelFor(e.target),
+ e.relatedTarget ? labelFor(e.relatedTarget) : null,
+ e.composedPath().map((n) => {
+ return labelFor(n);
+ })]);
+ });
+ }
+ }
+ target.dispatchEvent(event);
+ return log;
+}
+
+// TODO(hayato): Merge this into dispatchEventWithLog
+function dispatchUAEventWithLog(nodes, target, eventType, callback) {
+
+ function labelFor(e) {
+ return e.id || e.tagName;
+ }
+
+ let log = [];
+ let attachedNodes = [];
+ for (let label in nodes) {
+ let startingNode = nodes[label];
+ for (let node = startingNode; node; node = node.parentNode) {
+ if (attachedNodes.indexOf(node) >= 0)
+ continue;
+ let id = node.id;
+ if (!id)
+ continue;
+ attachedNodes.push(node);
+ node.addEventListener(eventType, (e) => {
+ // Record [currentTarget, target, relatedTarget, composedPath()]
+ log.push([id,
+ labelFor(e.target),
+ e.relatedTarget ? labelFor(e.relatedTarget) : null,
+ e.composedPath().map((n) => {
+ return labelFor(n);
+ })]);
+ });
+ }
+ }
+ callback(target);
+ return log;
+}
+
+// This function assumes that testharness.js is available.
+function assert_event_path_equals(actual, expected) {
+ assert_equals(actual.length, expected.length);
+ for (let i = 0; i < actual.length; ++i) {
+ assert_equals(actual[i][0], expected[i][0], 'currentTarget at ' + i + ' should be same');
+ assert_equals(actual[i][1], expected[i][1], 'target at ' + i + ' should be same');
+ assert_equals(actual[i][2], expected[i][2], 'relatedTarget at ' + i + ' should be same');
+ assert_array_equals(actual[i][3], expected[i][3], 'composedPath at ' + i + ' should be same');
+ }
+}
diff --git a/testing/web-platform/tests/shadow-dom/scroll-to-the-fragment-in-shadow-tree.html b/testing/web-platform/tests/shadow-dom/scroll-to-the-fragment-in-shadow-tree.html
new file mode 100644
index 000000000..c87932eb6
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/scroll-to-the-fragment-in-shadow-tree.html
@@ -0,0 +1,127 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Shadow DOM: The indicated part of the document should not match an element inside a shadow tree</title>
+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+<meta name="assert" content="An element inside a shadow tree should not be the indicated part of the document even if its ID is exactly equal to the decoded fragid or its name attribute is exactly equal to the fragid">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/browsers.html#scroll-to-the-fragment-identifier">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<div id="testContainer"></div>
+<script>
+
+var tests = [
+ {test: async_test('The user agent scroll to the fragment when there is an element with an ID exactly equal to the decoded fragid'),
+ execute: testScrollingToElementInDocumentTree.bind(this, 'div')},
+ {test: async_test('The user agent scroll to the fragment when there is an anchor element with a name attribute exactly equal to the decoded fragid'),
+ execute: testScrollingToElementInDocumentTree.bind(this, 'a')},
+
+ {test: async_test('The user agent should not scroll to an element with an ID exactly equal to the decoded fragid in an open shadow tree'),
+ execute: testScrollingToElementInShadowTree.bind(this, 'div', 'open')},
+ {test: async_test('The user agent should not scroll to an element with an ID exactly equal to the decoded fragid in a closed shadow tree'),
+ execute: testScrollingToElementInShadowTree.bind(this, 'div', 'closed')},
+ {test: async_test('The user agent should not scroll to an anchor element with a name attribute exactly equal to the decoded fragid in an open shadow tree'),
+ execute: testScrollingToElementInShadowTree.bind(this, 'a', 'open')},
+ {test: async_test('The user agent should not scroll to an anchor element with a name attribute exactly equal to the decoded fragid in a closed shadow tree'),
+ execute: testScrollingToElementInShadowTree.bind(this, 'a', 'closed')},
+
+ {test: async_test('The user agent should scroll to an element with an ID exactly equal to the decoded fragid in the document tree'
+ + ' even if there was another element with the same ID inside an open shadow tree earlier in tree order'),
+ execute: testScrollingToElementInDocumentTreeAfterElementInShadowTreeWithSameID.bind(this, 'div', 'open')},
+ {test: async_test('The user agent should scroll to an element with an ID exactly equal to the decoded fragid in the document tree'
+ + ' even if there was another element with the same ID inside a closed shadow tree earlier in tree order'),
+ execute: testScrollingToElementInDocumentTreeAfterElementInShadowTreeWithSameID.bind(this, 'div', 'closed')},
+ {test: async_test('The user agent should scroll to an anchor element with a name attribute exactly equal to the decoded fragid in the document tree'
+ + ' even if there was another element with the same ID inside an open shadow tree earlier in tree order'),
+ execute: testScrollingToElementInDocumentTreeAfterElementInShadowTreeWithSameID.bind(this, 'a', 'open')},
+ {test: async_test('The user agent should scroll to an anchor element with a name attribute exactly equal to the decoded fragid in the document tree'
+ + ' even if there was another element with the same ID inside a closed shadow tree earlier in tree order'),
+ execute: testScrollingToElementInDocumentTreeAfterElementInShadowTreeWithSameID.bind(this, 'a', 'closed')},
+];
+
+function executeNextTest()
+{
+ window.scrollTo(0, 0);
+
+ currentFragIdSuffix++;
+ var nextTest = tests.shift();
+ if (!nextTest)
+ return;
+ setTimeout(function () {
+ nextTest.execute(nextTest.test);
+ }, 0);
+}
+
+var testContainer = document.getElementById('testContainer');
+var currentFragIdSuffix = 0;
+
+function tallElementMarkup()
+{
+ return '<div style="height: ' + (window.innerHeight * 2) + 'px"><a href="#fragid' + currentFragIdSuffix + '">Go to fragment</a></div>';
+}
+
+function targetMarkup(elementType)
+{
+ return elementType == 'div' ? ('<div id="fragid' + currentFragIdSuffix + '">hello</div>') : ('<a name="fragid' + currentFragIdSuffix + '">hello</a>');
+}
+
+function clickFirstAnchorAndRunStep(test, step)
+{
+ setTimeout(function () {
+ testContainer.querySelector('a').click();
+ setTimeout(function () {
+ test.step(step);
+ testContainer.innerHTML = '';
+ test.done();
+ executeNextTest();
+ }, 0);
+ }, 0);
+}
+
+function testScrollingToElementInDocumentTree(elementType, test)
+{
+ test.step(function () {
+ testContainer.innerHTML = tallElementMarkup() + targetMarkup(elementType);
+ assert_equals(window.pageYOffset, 0);
+ });
+ clickFirstAnchorAndRunStep(test, function () {
+ assert_not_equals(window.pageYOffset, 0);
+ });
+}
+
+function testScrollingToElementInShadowTree(elementType, mode, test)
+{
+ test.step(function () {
+ testContainer.innerHTML = tallElementMarkup() + '<div id="host"></div>';
+ var host = document.querySelector('#host');
+ var shadowRoot = host.attachShadow({mode: mode});
+ shadowRoot.innerHTML = targetMarkup(elementType);
+ assert_equals(window.pageYOffset, 0);
+ });
+ clickFirstAnchorAndRunStep(test, function () {
+ assert_equals(window.pageYOffset, 0);
+ });
+}
+
+function testScrollingToElementInDocumentTreeAfterElementInShadowTreeWithSameID(elementType, mode, test)
+{
+ test.step(function () {
+ testContainer.innerHTML = tallElementMarkup() + '<div id="host"></div>' + tallElementMarkup() + targetMarkup(elementType);
+ var host = document.querySelector('#host');
+ var shadowRoot = host.attachShadow({mode: mode});
+ shadowRoot.innerHTML = targetMarkup(elementType);
+ assert_equals(window.pageYOffset, 0);
+ });
+ clickFirstAnchorAndRunStep(test, function () {
+ assert_true(window.pageYOffset > testContainer.querySelector('#host').offsetTop);
+ });
+}
+
+executeNextTest();
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/slotchange-event.html b/testing/web-platform/tests/shadow-dom/slotchange-event.html
new file mode 100644
index 000000000..ed36bedbb
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/slotchange-event.html
@@ -0,0 +1,620 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Shadow DOM: slotchange event</title>
+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+<link rel="help" href="https://dom.spec.whatwg.org/#signaling-slot-change">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+// FIXME: Fix these test cases once https://github.com/w3c/webcomponents/issues/571 is resolved.
+
+function treeName(mode, connectedToDocument)
+{
+ return (mode == 'open' ? 'an ' : 'a ') + mode + ' shadow root '
+ + (connectedToDocument ? '' : ' not') + ' in a document';
+}
+
+function testAppendingSpanToShadowRootWithDefaultSlot(mode, connectedToDocument)
+{
+ var test = async_test('slotchange event must fire on a default slot element inside '
+ + treeName(mode, connectedToDocument));
+
+ var host;
+ var slot;
+ var eventCount = 0;
+
+ test.step(function () {
+ host = document.createElement('div');
+ if (connectedToDocument)
+ document.body.appendChild(host);
+
+ var shadowRoot = host.attachShadow({'mode': mode});
+ slot = document.createElement('slot');
+
+ slot.addEventListener('slotchange', function (event) {
+ if (event.isFakeEvent)
+ return;
+
+ test.step(function () {
+ assert_equals(event.type, 'slotchange', 'slotchange event\'s type must be "slotchange"');
+ assert_equals(event.target, slot, 'slotchange event\'s target must be the slot element');
+ assert_equals(event.relatedTarget, undefined, 'slotchange must not set relatedTarget');
+ });
+ eventCount++;
+ });
+
+ shadowRoot.appendChild(slot);
+
+ host.appendChild(document.createElement('span'));
+ host.appendChild(document.createElement('b'));
+
+ assert_equals(eventCount, 0, 'slotchange event must not be fired synchronously');
+ });
+
+ setTimeout(function () {
+ test.step(function () {
+ assert_equals(eventCount, 1, 'slotchange must be fired exactly once after the assigned nodes changed');
+
+ host.appendChild(document.createElement('i'));
+ });
+
+ setTimeout(function () {
+ test.step(function () {
+ assert_equals(eventCount, 2, 'slotchange must be fired exactly once after the assigned nodes changed');
+
+ host.appendChild(document.createTextNode('hello'));
+
+ var fakeEvent = new Event('slotchange');
+ fakeEvent.isFakeEvent = true;
+ slot.dispatchEvent(fakeEvent);
+ });
+
+ setTimeout(function () {
+ test.step(function () {
+ assert_equals(eventCount, 3, 'slotchange must be fired exactly once after the assigned nodes changed'
+ + ' event if there was a synthetic slotchange event fired');
+ });
+ test.done();
+ }, 1);
+ }, 1);
+ }, 1);
+}
+
+testAppendingSpanToShadowRootWithDefaultSlot('open', true);
+testAppendingSpanToShadowRootWithDefaultSlot('closed', true);
+testAppendingSpanToShadowRootWithDefaultSlot('open', false);
+testAppendingSpanToShadowRootWithDefaultSlot('closed', false);
+
+function testAppendingSpanToShadowRootWithNamedSlot(mode, connectedToDocument)
+{
+ var test = async_test('slotchange event must fire on a named slot element inside'
+ + treeName(mode, connectedToDocument));
+
+ var host;
+ var slot;
+ var eventCount = 0;
+
+ test.step(function () {
+ host = document.createElement('div');
+ if (connectedToDocument)
+ document.body.appendChild(host);
+
+ var shadowRoot = host.attachShadow({'mode': mode});
+ slot = document.createElement('slot');
+ slot.name = 'someSlot';
+
+ slot.addEventListener('slotchange', function (event) {
+ if (event.isFakeEvent)
+ return;
+
+ test.step(function () {
+ assert_equals(event.type, 'slotchange', 'slotchange event\'s type must be "slotchange"');
+ assert_equals(event.target, slot, 'slotchange event\'s target must be the slot element');
+ assert_equals(event.relatedTarget, undefined, 'slotchange must not set relatedTarget');
+ });
+ eventCount++;
+ });
+
+ shadowRoot.appendChild(slot);
+
+ var span = document.createElement('span');
+ span.slot = 'someSlot';
+ host.appendChild(span);
+
+ var b = document.createElement('b');
+ b.slot = 'someSlot';
+ host.appendChild(b);
+
+ assert_equals(eventCount, 0, 'slotchange event must not be fired synchronously');
+ });
+
+ setTimeout(function () {
+ test.step(function () {
+ assert_equals(eventCount, 1, 'slotchange must be fired exactly once after the assigned nodes changed');
+
+ var i = document.createElement('i');
+ i.slot = 'someSlot';
+ host.appendChild(i);
+ });
+
+ setTimeout(function () {
+ test.step(function () {
+ assert_equals(eventCount, 2, 'slotchange must be fired exactly once after the assigned nodes changed');
+
+ var em = document.createElement('em');
+ em.slot = 'someSlot';
+ host.appendChild(em);
+
+ var fakeEvent = new Event('slotchange');
+ fakeEvent.isFakeEvent = true;
+ slot.dispatchEvent(fakeEvent);
+ });
+
+ setTimeout(function () {
+ test.step(function () {
+ assert_equals(eventCount, 3, 'slotchange must be fired exactly once after the assigned nodes changed'
+ + ' event if there was a synthetic slotchange event fired');
+ });
+ test.done();
+ }, 1);
+
+ }, 1);
+ }, 1);
+}
+
+testAppendingSpanToShadowRootWithNamedSlot('open', true);
+testAppendingSpanToShadowRootWithNamedSlot('closed', true);
+testAppendingSpanToShadowRootWithNamedSlot('open', false);
+testAppendingSpanToShadowRootWithNamedSlot('closed', false);
+
+function testSlotchangeDoesNotFireWhenOtherSlotsChange(mode, connectedToDocument)
+{
+ var test = async_test('slotchange event must not fire on a slot element inside '
+ + treeName(mode, connectedToDocument)
+ + ' when another slot\'s assigned nodes change');
+
+ var host;
+ var defaultSlotEventCount = 0;
+ var namedSlotEventCount = 0;
+
+ test.step(function () {
+ host = document.createElement('div');
+ if (connectedToDocument)
+ document.body.appendChild(host);
+
+ var shadowRoot = host.attachShadow({'mode': mode});
+ var defaultSlot = document.createElement('slot');
+ defaultSlot.addEventListener('slotchange', function (event) {
+ test.step(function () {
+ assert_equals(event.target, defaultSlot, 'slotchange event\'s target must be the slot element');
+ });
+ defaultSlotEventCount++;
+ });
+
+ var namedSlot = document.createElement('slot');
+ namedSlot.name = 'slotName';
+ namedSlot.addEventListener('slotchange', function (event) {
+ test.step(function () {
+ assert_equals(event.target, namedSlot, 'slotchange event\'s target must be the slot element');
+ });
+ namedSlotEventCount++;
+ });
+
+ shadowRoot.appendChild(defaultSlot);
+ shadowRoot.appendChild(namedSlot);
+
+ host.appendChild(document.createElement('span'));
+
+ assert_equals(defaultSlotEventCount, 0, 'slotchange event must not be fired synchronously');
+ assert_equals(namedSlotEventCount, 0, 'slotchange event must not be fired synchronously');
+ });
+
+ setTimeout(function () {
+ test.step(function () {
+ assert_equals(defaultSlotEventCount, 1,
+ 'slotchange must be fired exactly once after the assigned nodes change on a default slot');
+ assert_equals(namedSlotEventCount, 0,
+ 'slotchange must not be fired on a named slot after the assigned nodes change on a default slot');
+
+ var span = document.createElement('span');
+ span.slot = 'slotName';
+ host.appendChild(span);
+ });
+
+ setTimeout(function () {
+ test.step(function () {
+ assert_equals(defaultSlotEventCount, 1,
+ 'slotchange must not be fired on a default slot after the assigned nodes change on a named slot');
+ assert_equals(namedSlotEventCount, 1,
+ 'slotchange must be fired exactly once after the assigned nodes change on a default slot');
+ });
+ test.done();
+ }, 1);
+ }, 1);
+}
+
+testSlotchangeDoesNotFireWhenOtherSlotsChange('open', true);
+testSlotchangeDoesNotFireWhenOtherSlotsChange('closed', true);
+testSlotchangeDoesNotFireWhenOtherSlotsChange('open', false);
+testSlotchangeDoesNotFireWhenOtherSlotsChange('closed', false);
+
+function testSlotchangeDoesNotFireForMutationBeforeOrAfterSlotWasPresent(mode, connectedToDocument)
+{
+ var test = async_test('slotchange event must not fire on a slot element inside '
+ + treeName(mode, connectedToDocument)
+ + ' when the shadow host was mutated before the slot was inserted or after the slot was removed');
+
+ var host;
+ var slot;
+ var eventCount = 0;
+
+ test.step(function () {
+ host = document.createElement('div');
+ if (connectedToDocument)
+ document.body.appendChild(host);
+
+ var shadowRoot = host.attachShadow({'mode': mode});
+ slot = document.createElement('slot');
+ slot.addEventListener('slotchange', function (event) {
+ test.step(function () {
+ assert_equals(event.target, slot, 'slotchange event\'s target must be the slot element');
+ });
+ eventCount++;
+ });
+
+ host.appendChild(document.createElement('span'));
+ shadowRoot.appendChild(slot);
+
+ assert_equals(eventCount, 0, 'slotchange event must not be fired synchronously');
+ });
+
+ setTimeout(function () {
+ test.step(function () {
+ assert_equals(eventCount, 0,
+ 'slotchange must not be fired on a slot element if the assigned nodes changed before the slot was inserted');
+ host.removeChild(host.firstChild);
+ });
+
+ setTimeout(function () {
+ test.step(function () {
+ assert_equals(eventCount, 1,
+ 'slotchange must be fired exactly once after the assigned nodes change on a slot while the slot element was in the tree');
+ slot.parentNode.removeChild(slot);
+ host.appendChild(document.createElement('span'));
+ });
+
+ setTimeout(function () {
+ assert_equals(eventCount, 1,
+ 'slotchange must not be fired on a slot element if the assigned nodes changed after the slot was removed');
+ test.done();
+ }, 1);
+ }, 1);
+ }, 1);
+}
+
+testSlotchangeDoesNotFireForMutationBeforeOrAfterSlotWasPresent('open', true);
+testSlotchangeDoesNotFireForMutationBeforeOrAfterSlotWasPresent('closed', true);
+testSlotchangeDoesNotFireForMutationBeforeOrAfterSlotWasPresent('open', false);
+testSlotchangeDoesNotFireForMutationBeforeOrAfterSlotWasPresent('closed', false);
+
+function testSlotchangeFiresOnTransientlyPresentSlot(mode, connectedToDocument)
+{
+ var test = async_test('slotchange event must fire on a slot element inside '
+ + treeName(mode, connectedToDocument)
+ + ' even if the slot was removed immediately after the assigned nodes were mutated');
+
+ var host;
+ var slot;
+ var anotherSlot;
+ var slotEventCount = 0;
+ var anotherSlotEventCount = 0;
+
+ test.step(function () {
+ host = document.createElement('div');
+ if (connectedToDocument)
+ document.body.appendChild(host);
+
+ var shadowRoot = host.attachShadow({'mode': mode});
+ slot = document.createElement('slot');
+ slot.name = 'someSlot';
+ slot.addEventListener('slotchange', function (event) {
+ test.step(function () {
+ assert_equals(event.target, slot, 'slotchange event\'s target must be the slot element');
+ });
+ slotEventCount++;
+ });
+
+ anotherSlot = document.createElement('slot');
+ anotherSlot.name = 'someSlot';
+ anotherSlot.addEventListener('slotchange', function (event) {
+ test.step(function () {
+ assert_equals(event.target, anotherSlot, 'slotchange event\'s target must be the slot element');
+ });
+ anotherSlotEventCount++;
+ });
+
+ shadowRoot.appendChild(slot);
+
+ var span = document.createElement('span');
+ span.slot = 'someSlot';
+ host.appendChild(span);
+
+ shadowRoot.removeChild(slot);
+ shadowRoot.appendChild(anotherSlot);
+
+ var span = document.createElement('span');
+ span.slot = 'someSlot';
+ host.appendChild(span);
+
+ shadowRoot.removeChild(anotherSlot);
+
+ assert_equals(slotEventCount, 0, 'slotchange event must not be fired synchronously');
+ assert_equals(anotherSlotEventCount, 0, 'slotchange event must not be fired synchronously');
+ });
+
+ setTimeout(function () {
+ test.step(function () {
+ assert_equals(slotEventCount, 1,
+ 'slotchange must be fired on a slot element if the assigned nodes changed while the slot was present');
+ assert_equals(anotherSlotEventCount, 1,
+ 'slotchange must be fired on a slot element if the assigned nodes changed while the slot was present');
+ });
+ test.done();
+ }, 1);
+}
+
+testSlotchangeFiresOnTransientlyPresentSlot('open', true);
+testSlotchangeFiresOnTransientlyPresentSlot('closed', true);
+testSlotchangeFiresOnTransientlyPresentSlot('open', false);
+testSlotchangeFiresOnTransientlyPresentSlot('closed', false);
+
+function testSlotchangeFiresOnInnerHTML(mode, connectedToDocument)
+{
+ var test = async_test('slotchange event must fire on a slot element inside '
+ + treeName(mode, connectedToDocument)
+ + ' when innerHTML modifies the children of the shadow host');
+
+ var host;
+ var defaultSlot;
+ var namedSlot;
+ var defaultSlotEventCount = 0;
+ var namedSlotEventCount = 0;
+
+ test.step(function () {
+ host = document.createElement('div');
+ if (connectedToDocument)
+ document.body.appendChild(host);
+
+ var shadowRoot = host.attachShadow({'mode': mode});
+ defaultSlot = document.createElement('slot');
+ defaultSlot.addEventListener('slotchange', function (event) {
+ test.step(function () {
+ assert_equals(event.target, defaultSlot, 'slotchange event\'s target must be the slot element');
+ });
+ defaultSlotEventCount++;
+ });
+
+ namedSlot = document.createElement('slot');
+ namedSlot.name = 'someSlot';
+ namedSlot.addEventListener('slotchange', function (event) {
+ test.step(function () {
+ assert_equals(event.target, namedSlot, 'slotchange event\'s target must be the slot element');
+ });
+ namedSlotEventCount++;
+ });
+ shadowRoot.appendChild(namedSlot);
+ shadowRoot.appendChild(defaultSlot);
+ host.innerHTML = 'foo <b>bar</b>';
+
+ assert_equals(defaultSlotEventCount, 0, 'slotchange event must not be fired synchronously');
+ assert_equals(namedSlotEventCount, 0, 'slotchange event must not be fired synchronously');
+ });
+
+ setTimeout(function () {
+ test.step(function () {
+ assert_equals(defaultSlotEventCount, 1,
+ 'slotchange must be fired on a slot element if the assigned nodes are changed by innerHTML');
+ assert_equals(namedSlotEventCount, 0,
+ 'slotchange must not be fired on a slot element if the assigned nodes are not changed by innerHTML');
+ host.innerHTML = 'baz';
+ });
+ setTimeout(function () {
+ test.step(function () {
+ assert_equals(defaultSlotEventCount, 2,
+ 'slotchange must be fired on a slot element if the assigned nodes are changed by innerHTML');
+ assert_equals(namedSlotEventCount, 0,
+ 'slotchange must not be fired on a slot element if the assigned nodes are not changed by innerHTML');
+ host.innerHTML = '';
+ });
+ setTimeout(function () {
+ test.step(function () {
+ assert_equals(defaultSlotEventCount, 3,
+ 'slotchange must be fired on a slot element if the assigned nodes are changed by innerHTML');
+ assert_equals(namedSlotEventCount, 0,
+ 'slotchange must not be fired on a slot element if the assigned nodes are not changed by innerHTML');
+ host.innerHTML = '<b slot="someSlot">content</b>';
+ });
+ setTimeout(function () {
+ test.step(function () {
+ assert_equals(defaultSlotEventCount, 3,
+ 'slotchange must not be fired on a slot element if the assigned nodes are not changed by innerHTML');
+ assert_equals(namedSlotEventCount, 1,
+ 'slotchange must not be fired on a slot element if the assigned nodes are changed by innerHTML');
+ host.innerHTML = '';
+ });
+ setTimeout(function () {
+ test.step(function () {
+ // FIXME: This test would fail in the current implementation because we can't tell
+ // whether a text node was removed in AllChildrenRemoved or not.
+// assert_equals(defaultSlotEventCount, 3,
+// 'slotchange must not be fired on a slot element if the assigned nodes are not changed by innerHTML');
+ assert_equals(namedSlotEventCount, 2,
+ 'slotchange must not be fired on a slot element if the assigned nodes are changed by innerHTML');
+ });
+ test.done();
+ }, 1);
+ }, 1);
+ }, 1);
+ }, 1);
+ }, 1);
+}
+
+testSlotchangeFiresOnInnerHTML('open', true);
+testSlotchangeFiresOnInnerHTML('closed', true);
+testSlotchangeFiresOnInnerHTML('open', false);
+testSlotchangeFiresOnInnerHTML('closed', false);
+
+function testSlotchangeFiresWhenNestedSlotChange(mode, connectedToDocument)
+{
+ var test = async_test('slotchange event must fire on a slot element inside '
+ + treeName(mode, connectedToDocument)
+ + ' when nested slots\'s contents change');
+
+ var outerHost;
+ var innerHost;
+ var outerSlot;
+ var innerSlot;
+ var outerSlotEventCount = 0;
+ var innerSlotEventCount = 0;
+
+ test.step(function () {
+ outerHost = document.createElement('div');
+ if (connectedToDocument)
+ document.body.appendChild(outerHost);
+
+ var outerShadow = outerHost.attachShadow({'mode': mode});
+ outerShadow.appendChild(document.createElement('span'));
+ outerSlot = document.createElement('slot');
+ outerSlot.addEventListener('slotchange', function (event) {
+ event.stopPropagation();
+ test.step(function () {
+ assert_equals(event.target, outerSlot, 'slotchange event\'s target must be the slot element');
+ });
+ outerSlotEventCount++;
+ });
+
+ innerHost = document.createElement('div');
+ innerHost.appendChild(outerSlot);
+ outerShadow.appendChild(innerHost);
+
+ var innerShadow = innerHost.attachShadow({'mode': mode});
+ innerShadow.appendChild(document.createElement('span'));
+ innerSlot = document.createElement('slot');
+ innerSlot.addEventListener('slotchange', function (event) {
+ event.stopPropagation();
+ test.step(function () {
+ assert_equals(event.target, innerSlot, 'slotchange event\'s target must be the slot element');
+ });
+ innerSlotEventCount++;
+ });
+ innerShadow.appendChild(innerSlot);
+
+ outerHost.appendChild(document.createElement('span'));
+
+ assert_equals(innerSlotEventCount, 0, 'slotchange event must not be fired synchronously');
+ assert_equals(outerSlotEventCount, 0, 'slotchange event must not be fired synchronously');
+ });
+
+ setTimeout(function () {
+ test.step(function () {
+ assert_equals(innerSlotEventCount, 1,
+ 'slotchange must be fired on a slot element if the assigned nodes changed');
+ assert_equals(outerSlotEventCount, 1,
+ 'slotchange must be fired on a slot element if the assigned nodes of an inner slot changed');
+ });
+ test.done();
+ }, 1);
+}
+
+testSlotchangeFiresWhenNestedSlotChange('open', true);
+testSlotchangeFiresWhenNestedSlotChange('closed', true);
+testSlotchangeFiresWhenNestedSlotChange('open', false);
+testSlotchangeFiresWhenNestedSlotChange('closed', false);
+
+function testSlotchangeFiresAtEndOfMicroTask(mode, connectedToDocument)
+{
+ var test = async_test('slotchange event must fire at the end of current microtask after mutation observers are invoked inside '
+ + treeName(mode, connectedToDocument) + ' when slots\'s contents change');
+
+ var outerHost;
+ var innerHost;
+ var outerSlot;
+ var innerSlot;
+ var slotchangeEvents = [];
+
+ test.step(function () {
+ outerHost = document.createElement('div');
+ if (connectedToDocument)
+ document.body.appendChild(outerHost);
+
+ var outerShadow = outerHost.attachShadow({'mode': mode});
+ outerShadow.appendChild(document.createElement('span'));
+ outerSlot = document.createElement('slot');
+ outerSlot.addEventListener('slotchange', function (event) {
+ event.stopPropagation();
+ test.step(function () {
+ assert_equals(event.target, outerSlot, 'slotchange event\'s target must be the slot element');
+ });
+ slotchangeEvents.push('outer');
+ });
+
+ innerHost = document.createElement('div');
+ innerHost.appendChild(outerSlot);
+ outerShadow.appendChild(innerHost);
+
+ var innerShadow = innerHost.attachShadow({'mode': mode});
+ innerShadow.appendChild(document.createElement('span'));
+ innerSlot = document.createElement('slot');
+ innerSlot.addEventListener('slotchange', function (event) {
+ event.stopPropagation();
+ test.step(function () {
+ assert_equals(event.target, innerSlot, 'slotchange event\'s target must be the slot element');
+ });
+ slotchangeEvents.push('inner');
+ });
+ innerShadow.appendChild(innerSlot);
+
+ outerHost.appendChild(document.createElement('span'));
+
+ assert_equals(slotchangeEvents.length, 0, 'slotchange event must not be fired synchronously');
+ });
+
+ var element = document.createElement('div');
+
+ new MutationObserver(function () {
+ test.step(function () {
+ assert_equals(slotchangeEvents.length, 0, 'slotchange event must not be fired before mutation records are delivered');
+ });
+ element.setAttribute('title', 'bar');
+ innerHost.appendChild(document.createElement('span'));
+ }).observe(element, {attributes: true, attributeFilter: ['id']});
+
+ new MutationObserver(function () {
+ test.step(function () {
+ assert_array_equals(slotchangeEvents, ['outer', 'inner'], 'slotchange event must be fired during a single compound microtask');
+ });
+ }).observe(element, {attributes: true, attributeFilter: ['title']});
+
+ element.setAttribute('id', 'foo');
+
+ setTimeout(function () {
+ test.step(function () {
+ assert_array_equals(slotchangeEvents, ['outer', 'inner', 'inner'],
+ 'a distinct slotchange event must be enqueued for changes made during a mutation observer delivery');
+ });
+ test.done();
+ }, 0);
+}
+
+testSlotchangeFiresAtEndOfMicroTask('open', true);
+testSlotchangeFiresAtEndOfMicroTask('closed', true);
+testSlotchangeFiresAtEndOfMicroTask('open', false);
+testSlotchangeFiresAtEndOfMicroTask('closed', false);
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/slotchange.html b/testing/web-platform/tests/shadow-dom/slotchange.html
new file mode 100644
index 000000000..1f94cc7be
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/slotchange.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<title>Shadow DOM: slotchange Events</title>
+<meta name="author" title="Hayato Ito" href="mailto:hayato@google.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/shadow-dom.js"></script>
+
+<div id="test1">
+ <div id="host1">
+ <template data-mode="open">
+ <slot id="s1" name="slot1"></slot>
+ </template>
+ <div id="c1" slot="slot1"></div>
+ </div>
+</div>
+
+<script>
+function doneIfSlotChange(slots, test) {
+ let fired = new Set();
+ for (let slot of slots) {
+ slot.addEventListener('slotchange', test.step_func((e) => {
+ assert_false(fired.has(slot.id));
+ fired.add(slot.id);
+ if (fired.size == slots.length) {
+ test.done();
+ }
+ }))
+ }
+}
+
+async_test((test) => {
+ let n = createTestTree(test1);
+ removeWhiteSpaceOnlyTextNodes(n.test1);
+
+ doneIfSlotChange([n.s1], test);
+
+ let d1 = document.createElement('div');
+ d1.setAttribute('slot', 'slot1');
+ n.host1.appendChild(d1);
+}, 'slotchange event: Append a child to a host.');
+
+async_test((test) => {
+ let n = createTestTree(test1);
+ removeWhiteSpaceOnlyTextNodes(n.test1);
+
+ doneIfSlotChange([n.s1], test);
+
+ n.c1.remove();
+}, 'slotchange event: Remove a child from a host.');
+
+async_test((test) => {
+ let n = createTestTree(test1);
+ removeWhiteSpaceOnlyTextNodes(n.test1);
+
+ n.c1.remove();
+
+ doneIfSlotChange([n.s1], test);
+}, 'slotchange event: Remove a child before adding an event listener.');
+
+async_test((test) => {
+ let n = createTestTree(test1);
+ removeWhiteSpaceOnlyTextNodes(n.test1);
+
+ doneIfSlotChange([n.s1], test);
+
+ n.c1.setAttribute('slot', 'slot-none');
+}, 'slotchange event: Change slot= attribute to make it un-assigned.');
+
+async_test((test) => {
+ let n = createTestTree(test1);
+ removeWhiteSpaceOnlyTextNodes(n.test1);
+
+ doneIfSlotChange([n.s1], test);
+
+ n.s1.setAttribute('name', 'slot-none');
+}, 'slotchange event: Change slot\'s name= attribute so that none is assigned.');
+</script>
+
+<div id="test2">
+ <div id="host1">
+ <template data-mode="open">
+ <slot id="s1" name="slot1"></slot>
+ </template>
+ <div id="c2" slot="slot2"></div>
+ </div>
+</div>
+
+<script>
+async_test((test) => {
+ let n = createTestTree(test2);
+ removeWhiteSpaceOnlyTextNodes(n.test2);
+
+ doneIfSlotChange([n.s1], test);
+
+ n.c2.setAttribute('slot', 'slot1');
+}, 'slotchange event: Change slot= attribute to make it assigned.');
+
+async_test((test) => {
+ let n = createTestTree(test2);
+ removeWhiteSpaceOnlyTextNodes(n.test2);
+
+ doneIfSlotChange([n.s1], test);
+
+ n.s1.setAttribute('name', 'slot2');
+}, 'slotchange event: Change slot\'s name= attribute so that a node is assigned to the slot.');
+</script>
+
+<div id="test_fallback">
+ <div id="host1">
+ <template data-mode="open">
+ <slot id="s1"></slot>
+ </template>
+ </div>
+</div>
+
+<script>
+async_test((test) => {
+ let n = createTestTree(test_fallback);
+ removeWhiteSpaceOnlyTextNodes(n.test_fallback);
+
+ doneIfSlotChange([n.s1], test);
+
+ n.s1.appendChild(document.createElement('div'));
+}, 'slotchange event: Add a fallback content.');
+</script>
+
+<div id="test_fallback2">
+ <div id="host1">
+ <template data-mode="open">
+ <slot id="s1">
+ <div id="f1"></div>
+ </slot>
+ </template>
+ </div>
+</div>
+
+<script>
+async_test((test) => {
+ let n = createTestTree(test_fallback2);
+ removeWhiteSpaceOnlyTextNodes(n.test_fallback2);
+
+ doneIfSlotChange([n.s1], test);
+
+ n.f1.remove();
+}, 'slotchange event: Remove a fallback content.');
+</script>
+
+<div id="test_fallback3">
+ <div id="host1">
+ <template data-mode="open">
+ <slot id="s2">
+ <slot id="s1">
+ <div id="f1"></div>
+ </slot>
+ </slot>
+ </template>
+ </div>
+</div>
+
+<script>
+async_test((test) => {
+ let n = createTestTree(test_fallback3);
+ removeWhiteSpaceOnlyTextNodes(n.test_fallback3);
+
+ doneIfSlotChange([n.s1, n.s2], test);
+
+ n.s1.appendChild(document.createElement('div'));
+}, 'slotchange event: Add a fallback content to nested slots.');
+
+async_test((test) => {
+ let n = createTestTree(test_fallback3);
+ removeWhiteSpaceOnlyTextNodes(n.test_fallback3);
+
+ doneIfSlotChange([n.s1, n.s2], test);
+
+ n.f1.remove();
+}, 'slotchange event: Remove a fallback content from nested slots.');
+</script>
+
+<div id="test3">
+ <div id="host1">
+ <template id="shadowroot" data-mode="open">
+ <slot id="s1" name="slot1"></slot>
+ </template>
+ <div id="c1" slot="slot1"></div>
+ </div>
+</div>
+
+<script>
+async_test((test) => {
+ let n = createTestTree(test3);
+ removeWhiteSpaceOnlyTextNodes(n.test3);
+
+ doneIfSlotChange([n.s1], test);
+
+ let slot = document.createElement('slot');
+ slot.setAttribute('name', 'slot1');
+ n.shadowroot.insertBefore(slot, n.s1);
+}, "slotchange event: Insert a slot before an existing slot.");
+</script>
+
+<div id="test4">
+ <div id="host1">
+ <template id="shadowroot" data-mode="open">
+ <slot id="s1" name="slot1"></slot>
+ <slot id="s2" name="slot1"></slot>
+ </template>
+ <div id="c1" slot="slot1"></div>
+ </div>
+</div>
+
+<script>
+async_test((test) => {
+ let n = createTestTree(test4);
+ removeWhiteSpaceOnlyTextNodes(n.test4);
+
+ doneIfSlotChange([n.s2], test);
+
+ n.s1.remove();
+}, "slotchange event: Remove a preceding slot.");
+</script>
+
+<div id="test5">
+ <div id="host1">
+ <template data-mode="open">
+ <div id="host2">
+ <template data-mode="open">
+ <slot id="s2" name="slot2"></slot>
+ </template>
+ <slot id="s1" name="slot1" slot="slot2"></slot>
+ </div>
+ </template>
+ <div id="c1" slot="slot1"></div>
+ </div>
+</div>
+
+<script>
+async_test((test) => {
+ let n = createTestTree(test5);
+ removeWhiteSpaceOnlyTextNodes(n.test5);
+
+ doneIfSlotChange([n.s1, n.s2], test);
+
+ n.c1.remove();
+}, "slotchange event: A slot is assigned to another slot.");
+</script>
+
+<div id="test6">
+ <div id="host1">
+ <template data-mode="open">
+ <div id="host2">
+ <template data-mode="open">
+ <slot id="s2" name="slot2"></slot>
+ </template>
+ <slot id="s1" name="slot1" slot="slot2"></slot>
+ </div>
+ </template>
+ </div>
+</div>
+
+<script>
+async_test((test) => {
+ let n = createTestTree(test6);
+ removeWhiteSpaceOnlyTextNodes(n.test6);
+
+ doneIfSlotChange([n.s2], test);
+
+ n.s1.remove();
+}, "slotchange event: Even if distributed nodes do not change, slotchange should be fired if assigned nodes are changed.");
+</script>
diff --git a/testing/web-platform/tests/shadow-dom/slots-fallback.html b/testing/web-platform/tests/shadow-dom/slots-fallback.html
new file mode 100644
index 000000000..8721fe920
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/slots-fallback.html
@@ -0,0 +1,221 @@
+<!DOCTYPE html>
+<title>Shadow DOM: Slots and fallback contents</title>
+<meta name="author" title="Hayato Ito" href="mailto:hayato@google.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/shadow-dom.js"></script>
+
+<div id="test1">
+ <div id="host">
+ <template data-mode="open">
+ <slot id="s1" name="slot1">
+ <div id="f1"></div>
+ </slot>
+ </template>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test1);
+ removeWhiteSpaceOnlyTextNodes(n.test1);
+
+ assert_equals(n.f1.assignedSlot, null);
+
+ assert_array_equals(n.s1.assignedNodes(), []);
+ assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.f1]);
+}, 'Slots fallback: Basic.');
+</script>
+
+<div id="test2">
+ <div id="host">
+ <template data-mode="open">
+ <slot id="s1" name="slot1">
+ <slot id="s2" name="slot2">
+ <div id="f1"></div>
+ </slot>
+ </slot>
+ </template>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test2);
+ removeWhiteSpaceOnlyTextNodes(n.test2);
+
+ assert_equals(n.f1.assignedSlot, null);
+
+ assert_array_equals(n.s1.assignedNodes(), []);
+ assert_array_equals(n.s2.assignedNodes(), []);
+
+ assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.f1]);
+ assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.f1]);
+}, 'Slots fallback: Slots in Slots.');
+</script>
+
+<div id="test3">
+ <div id="host">
+ <template data-mode="open">
+ <slot id="s1" name="slot1">
+ <slot id="s2" name="slot2">
+ <div id="f1"></div>
+ </slot>
+ </slot>
+ </template>
+ <div id="c1" slot="slot1"></div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test3);
+ removeWhiteSpaceOnlyTextNodes(n.test3);
+
+ assert_equals(n.c1.assignedSlot, n.s1);
+ assert_equals(n.f1.assignedSlot, null);
+
+ assert_array_equals(n.s1.assignedNodes(), [n.c1]);
+ assert_array_equals(n.s2.assignedNodes(), []);
+
+ assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
+ assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.f1]);
+}, 'Slots fallback: Fallback contents should not be used if a node is assigned.');
+</script>
+
+<div id="test4">
+ <div id="host">
+ <template data-mode="open">
+ <slot id="s1" name="slot1">
+ <slot id="s2" name="slot2">
+ <div id="f1"></div>
+ </slot>
+ </slot>
+ </template>
+ <div id="c1" slot="slot2"></div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test4);
+ removeWhiteSpaceOnlyTextNodes(n.test4);
+
+ assert_equals(n.c1.assignedSlot, n.s2);
+ assert_equals(n.f1.assignedSlot, null);
+
+ assert_array_equals(n.s1.assignedNodes(), []);
+ assert_array_equals(n.s2.assignedNodes(), [n.c1]);
+
+ assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
+ assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1]);
+}, 'Slots fallback: Slots in Slots: Assinged nodes should be used as fallback contents of another slot');
+</script>
+
+<div id="test5">
+ <div id="host1">
+ <template data-mode="open">
+ <div id="host2">
+ <template data-mode="open">
+ <slot id="s4" name="slot4">
+ <slot id="s3" name="slot3">
+ <div id="f3"></div>
+ </slot>
+ <div id="f4"></div>
+ </slot>
+ </template>
+ <slot id="s2" name="slot2" slot="slot3">
+ <slot id="s1" name="slot1">
+ <div id="f1"></div>
+ </slot>
+ <div id="f2"></div>
+ </slot>
+ </div>
+ </template>
+ <div id="c1" slot="slot1"></div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test5);
+ removeWhiteSpaceOnlyTextNodes(n.test5);
+
+ assert_array_equals(n.s1.assignedNodes(), [n.c1]);
+ assert_array_equals(n.s2.assignedNodes(), []);
+ assert_array_equals(n.s3.assignedNodes(), [n.s2]);
+ assert_array_equals(n.s4.assignedNodes(), []);
+
+ assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
+ assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1, n.f2]);
+ assert_array_equals(n.s3.assignedNodes({ flatten: true }), [n.c1, n.f2]);
+ assert_array_equals(n.s4.assignedNodes({ flatten: true }), [n.c1, n.f2, n.f4]);
+}, 'Slots fallback: Complex case.');
+
+test(() => {
+ let n = createTestTree(test5);
+ removeWhiteSpaceOnlyTextNodes(n.test5);
+
+ let d1 = document.createElement('div');
+ n.s2.appendChild(d1);
+
+ assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
+ assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1, n.f2, d1]);
+ assert_array_equals(n.s3.assignedNodes({ flatten: true }), [n.c1, n.f2, d1]);
+ assert_array_equals(n.s4.assignedNodes({ flatten: true }), [n.c1, n.f2, d1, n.f4]);
+}, 'Slots fallback: Mutation. Append fallback contents.');
+
+test(() => {
+ let n = createTestTree(test5);
+ removeWhiteSpaceOnlyTextNodes(n.test5);
+
+ n.f2.remove();
+
+ assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
+ assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1]);
+ assert_array_equals(n.s3.assignedNodes({ flatten: true }), [n.c1]);
+ assert_array_equals(n.s4.assignedNodes({ flatten: true }), [n.c1, n.f4]);
+}, 'Slots fallback: Mutation. Remove fallback contents.');
+
+test(() => {
+ let n = createTestTree(test5);
+ removeWhiteSpaceOnlyTextNodes(n.test5);
+
+ let d2 = document.createElement('div');
+ d2.setAttribute('slot', 'slot2');
+ n.host1.appendChild(d2);
+
+ assert_array_equals(n.s2.assignedNodes(), [d2]);
+ assert_array_equals(n.s2.assignedNodes({ flatten: true }), [d2]);
+ assert_array_equals(n.s3.assignedNodes({ flatten: true }), [d2]);
+ assert_array_equals(n.s4.assignedNodes({ flatten: true }), [d2, n.f4]);
+}, 'Slots fallback: Mutation. Assign a node to a slot so that fallback contens are no longer used.');
+
+test(() => {
+ let n = createTestTree(test5);
+ removeWhiteSpaceOnlyTextNodes(n.test5);
+
+ n.c1.remove();
+
+ assert_array_equals(n.s1.assignedNodes(), []);
+
+ assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.f1]);
+ assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.f1, n.f2]);
+ assert_array_equals(n.s3.assignedNodes({ flatten: true }), [n.f1, n.f2]);
+ assert_array_equals(n.s4.assignedNodes({ flatten: true }), [n.f1, n.f2, n.f4]);
+}, 'Slots fallback: Mutation. Remove an assigned node from a slot so that fallback contens will be used.');
+
+test(() => {
+ let n = createTestTree(test5);
+ removeWhiteSpaceOnlyTextNodes(n.test5);
+
+ n.s1.remove();
+
+ assert_array_equals(n.s1.assignedNodes(), []);
+
+ assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.f1]);
+ assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.f2]);
+ assert_array_equals(n.s3.assignedNodes({ flatten: true }), [n.f2]);
+ assert_array_equals(n.s4.assignedNodes({ flatten: true }), [n.f2, n.f4]);
+}, 'Slots fallback: Mutation. Remove a slot which is a fallback content of another slot.');
+</script>
diff --git a/testing/web-platform/tests/shadow-dom/slots.html b/testing/web-platform/tests/shadow-dom/slots.html
new file mode 100644
index 000000000..67e1589ed
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/slots.html
@@ -0,0 +1,508 @@
+<!DOCTYPE html>
+<title>Shadow DOM: Slots and assignments</title>
+<meta name="author" title="Hayato Ito" href="mailto:hayato@google.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/shadow-dom.js"></script>
+
+<div id="test_basic">
+ <div id="host">
+ <template data-mode="open">
+ <slot id="s1" name="slot1"></slot>
+ </template>
+ <div id="c1" slot="slot1"></div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test_basic);
+ removeWhiteSpaceOnlyTextNodes(n.test_basic);
+
+ assert_equals(n.c1.assignedSlot, n.s1);
+ assert_array_equals(n.s1.assignedNodes(), [n.c1]);
+}, 'Slots: Basic.');
+</script>
+
+<div id="test_basic_closed">
+ <div id="host">
+ <template data-mode="closed">
+ <slot id="s1" name="slot1"></slot>
+ </template>
+ <div id="c1" slot="slot1"></div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test_basic_closed);
+ removeWhiteSpaceOnlyTextNodes(n.test_basic_closed);
+
+ assert_equals(n.c1.assignedSlot, null);
+ assert_array_equals(n.s1.assignedNodes(), [n.c1]);
+}, 'Slots: Slots in closed.');
+</script>
+
+<div id="test_slot_not_in_shadow">
+ <slot id="s1"></slot>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test_slot_not_in_shadow);
+ removeWhiteSpaceOnlyTextNodes(n.test_slot_not_in_shadow);
+
+ assert_array_equals(n.s1.assignedNodes(), []);
+}, 'Slots: Slots not in a shadow tree.');
+</script>
+
+<div id="test_slot_not_in_shadow_2">
+ <slot id="s1">
+ <div id="c1"></div>
+ </slot>
+ <slot id="s2">
+ <div id="c2"></div>
+ <slot id="s3">
+ <div id="c3_1"></div>
+ <div id="c3_2"></div>
+ </slot>
+ </slot>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test_slot_not_in_shadow_2);
+ removeWhiteSpaceOnlyTextNodes(n.test_slot_not_in_shadow_2);
+
+ assert_equals(n.c1.assignedSlot, null);
+ assert_equals(n.c2.assignedSlot, null);
+ assert_equals(n.c3_1.assignedSlot, null);
+ assert_equals(n.c3_2.assignedSlot, null);
+
+ assert_array_equals(n.s1.assignedNodes(), []);
+ assert_array_equals(n.s2.assignedNodes(), []);
+ assert_array_equals(n.s3.assignedNodes(), []);
+
+ assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
+ assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c2, n.c3_1, n.c3_2]);
+ assert_array_equals(n.s3.assignedNodes({ flatten: true }), [n.c3_1, n.c3_2]);
+}, 'Slots: Distributed nooes for Slots not in a shadow tree.');
+</script>
+
+<div id="test_slot_name_matching">
+ <div id="host">
+ <template data-mode="open">
+ <slot id="s1" name="slot1"></slot>
+ <slot id="s2" name="slot2"></slot>
+ <slot id="s3" name="xxx"></slot>
+ </template>
+ <div id="c1" slot="slot1"></div>
+ <div id="c2" slot="slot2"></div>
+ <div id="c3" slot="yyy"></div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test_slot_name_matching);
+ removeWhiteSpaceOnlyTextNodes(n.test_slot_name_matching);
+
+ assert_equals(n.c1.assignedSlot, n.s1);
+ assert_equals(n.c2.assignedSlot, n.s2);
+ assert_equals(n.c3.assignedSlot, null);
+}, 'Slots: Name matching');
+</script>
+
+<div id="test_no_direct_host_child">
+ <div id="host">
+ <template data-mode="open">
+ <slot id="s1" name="slot1"></slot>
+ <slot id="s2" name="slot1"></slot>
+ </template>
+ <div id="c1" slot="slot1"></div>
+ <div id="c2" slot="slot1"></div>
+ <div>
+ <div id="c3" slot="slot1"></div>
+ </div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test_no_direct_host_child);
+ removeWhiteSpaceOnlyTextNodes(n.test_no_direct_host_child);
+
+ assert_equals(n.c1.assignedSlot, n.s1);
+ assert_equals(n.c2.assignedSlot, n.s1);
+ assert_equals(n.c3.assignedSlot, null);
+
+ assert_array_equals(n.s1.assignedNodes(), [n.c1, n.c2]);
+}, 'Slots: No direct host child.');
+</script>
+
+<div id="test_default_slot">
+ <div id="host">
+ <template data-mode="open">
+ <slot id="s1" name="slot1"></slot>
+ <slot id="s2"></slot>
+ <slot id="s3"></slot>
+ </template>
+ <div id="c1"></div>
+ <div id="c2" slot=""></div>
+ <div id="c3" slot="foo"></div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test_default_slot);
+ removeWhiteSpaceOnlyTextNodes(n.test_default_slot);
+
+ assert_equals(n.c1.assignedSlot, n.s2);
+ assert_equals(n.c2.assignedSlot, n.s2);
+ assert_equals(n.c3.assignedSlot, null);
+}, 'Slots: Default Slot.');
+</script>
+
+<div id="test_slot_in_slot">
+ <div id="host">
+ <template data-mode="open">
+ <slot id="s1" name="slot1">
+ <slot id="s2" name="slot2"></slot>
+ </slot>
+ </template>
+ <div id="c1" slot="slot2"></div>
+ <div id="c2" slot="slot1"></div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test_slot_in_slot);
+ removeWhiteSpaceOnlyTextNodes(n.test_slot_in_slot);
+
+ assert_equals(n.c1.assignedSlot, n.s2);
+ assert_equals(n.c2.assignedSlot, n.s1);
+}, 'Slots: Slot in Slot does not matter in assignment.');
+</script>
+
+<div id="test_slot_is_assigned_to_slot">
+ <div id="host1">
+ <template data-mode="open">
+ <div id="host2">
+ <template data-mode="open">
+ <slot id="s2" name="slot2"></slot>
+ </template>
+ <slot id="s1" name="slot1" slot="slot2"></slot>
+ </div>
+ </template>
+ <div id="c1" slot="slot1"></div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test_slot_is_assigned_to_slot);
+ removeWhiteSpaceOnlyTextNodes(n.test_slot_is_assigned_to_slot);
+
+ assert_equals(n.c1.assignedSlot, n.s1);
+ assert_equals(n.s1.assignedSlot, n.s2);
+
+ assert_array_equals(n.s1.assignedNodes(), [n.c1]);
+ assert_array_equals(n.s2.assignedNodes(), [n.s1]);
+
+ assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
+ assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1]);
+}, 'Slots: Slot is assigned to another slot');
+</script>
+
+<div id="test_open_closed">
+ <div id="host1">
+ <template data-mode="open">
+ <div id="host2">
+ <template data-mode="closed">
+ <slot id="s2" name="slot2"></slot>
+ </template>
+ <slot id="s1" name="slot1" slot="slot2"></slot>
+ </div>
+ </template>
+ <div id="c1" slot="slot1"></div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test_open_closed);
+ removeWhiteSpaceOnlyTextNodes(n.test_open_closed);
+
+ assert_equals(n.c1.assignedSlot, n.s1);
+ assert_equals(n.s1.assignedSlot, null,
+ 'A slot in a closed shadow tree should not be accessed via assignedSlot');
+
+ assert_array_equals(n.s1.assignedNodes(), [n.c1]);
+ assert_array_equals(n.s2.assignedNodes(), [n.s1]);
+
+ assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
+ assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1]);
+}, 'Slots: Open > Closed.');
+</script>
+
+<div id="test_closed_closed">
+ <div id="host1">
+ <template data-mode="closed">
+ <div id="host2">
+ <template data-mode="closed">
+ <slot id="s2" name="slot2"></slot>
+ </template>
+ <slot id="s1" name="slot1" slot="slot2"></slot>
+ </div>
+ </template>
+ <div id="c1" slot="slot1"></div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test_closed_closed);
+ removeWhiteSpaceOnlyTextNodes(n.test_closed_closed);
+
+ assert_equals(n.c1.assignedSlot, null,
+ 'A slot in a closed shadow tree should not be accessed via assignedSlot');
+ assert_equals(n.s1.assignedSlot, null,
+ 'A slot in a closed shadow tree should not be accessed via assignedSlot');
+
+ assert_array_equals(n.s1.assignedNodes(), [n.c1]);
+ assert_array_equals(n.s2.assignedNodes(), [n.s1]);
+
+ assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
+ assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1]);
+}, 'Slots: Closed > Closed.');
+</script>
+
+<div id="test_closed_open">
+ <div id="host1">
+ <template data-mode="closed">
+ <div id="host2">
+ <template data-mode="open">
+ <slot id="s2" name="slot2"></slot>
+ </template>
+ <slot id="s1" name="slot1" slot="slot2"></slot>
+ </div>
+ </template>
+ <div id="c1" slot="slot1"></div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test_closed_open);
+ removeWhiteSpaceOnlyTextNodes(n.test_closed_open);
+
+ assert_equals(n.c1.assignedSlot, null,
+ 'A slot in a closed shadow tree should not be accessed via assignedSlot');
+ assert_equals(n.s1.assignedSlot, n.s2);
+
+ assert_array_equals(n.s1.assignedNodes(), [n.c1]);
+ assert_array_equals(n.s2.assignedNodes(), [n.s1]);
+
+ assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
+ assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c1]);
+}, 'Slots: Closed > Open.');
+</script>
+
+<div id="test_complex">
+ <div id="host1">
+ <template data-mode="open">
+ <div id="host2">
+ <template data-mode="open">
+ <slot id="s5" name="slot5"></slot>
+ <slot id="s6" name="slot6"></slot>
+ <slot id="s7"></slot>
+ <slot id="s8" name="slot8"></slot>
+ </template>
+ <slot id="s1" name="slot1" slot="slot5"></slot>
+ <slot id="s2" name="slot2" slot="slot6"></slot>
+ <slot id="s3"></slot>
+ <slot id="s4" name="slot4" slot="slot-none"></slot>
+ <div id="c5" slot="slot5"></div>
+ <div id="c6" slot="slot6"></div>
+ <div id="c7"></div>
+ <div id="c8" slot="slot-none"></div>
+ </div>
+ </template>
+ <div id="c1" slot="slot1"></div>
+ <div id="c2" slot="slot2"></div>
+ <div id="c3"></div>
+ <div id="c4" slot="slot-none"></div>
+ </div>
+</div>
+
+<script>
+test(() => {
+ let n = createTestTree(test_complex);
+ removeWhiteSpaceOnlyTextNodes(n.test_complex);
+
+ assert_equals(n.c1.assignedSlot, n.s1);
+ assert_equals(n.c2.assignedSlot, n.s2);
+ assert_equals(n.c3.assignedSlot, n.s3);
+ assert_equals(n.c4.assignedSlot, null);
+
+ assert_equals(n.s1.assignedSlot, n.s5);
+ assert_equals(n.s2.assignedSlot, n.s6);
+ assert_equals(n.s3.assignedSlot, n.s7);
+ assert_equals(n.s4.assignedSlot, null);
+
+ assert_equals(n.c5.assignedSlot, n.s5);
+ assert_equals(n.c6.assignedSlot, n.s6);
+ assert_equals(n.c7.assignedSlot, n.s7);
+ assert_equals(n.c8.assignedSlot, null);
+
+ assert_array_equals(n.s1.assignedNodes(), [n.c1]);
+ assert_array_equals(n.s2.assignedNodes(), [n.c2]);
+ assert_array_equals(n.s3.assignedNodes(), [n.c3]);
+ assert_array_equals(n.s4.assignedNodes(), []);
+ assert_array_equals(n.s5.assignedNodes(), [n.s1, n.c5]);
+ assert_array_equals(n.s6.assignedNodes(), [n.s2, n.c6]);
+ assert_array_equals(n.s7.assignedNodes(), [n.s3, n.c7]);
+ assert_array_equals(n.s8.assignedNodes(), []);
+
+ assert_array_equals(n.s1.assignedNodes({ flatten: true }), [n.c1]);
+ assert_array_equals(n.s2.assignedNodes({ flatten: true }), [n.c2]);
+ assert_array_equals(n.s3.assignedNodes({ flatten: true }), [n.c3]);
+ assert_array_equals(n.s4.assignedNodes({ flatten: true }), []);
+ assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c1, n.c5]);
+ assert_array_equals(n.s6.assignedNodes({ flatten: true }), [n.c2, n.c6]);
+ assert_array_equals(n.s7.assignedNodes({ flatten: true }), [n.c3, n.c7]);
+ assert_array_equals(n.s8.assignedNodes({ flatten: true }), []);
+}, 'Slots: Complex case: Basi line.');
+
+test(() => {
+ let n = createTestTree(test_complex);
+ removeWhiteSpaceOnlyTextNodes(n.test_complex);
+
+ let d1 = document.createElement('div');
+ d1.setAttribute('slot', 'slot1');
+ n.host1.appendChild(d1);
+
+ assert_array_equals(n.s1.assignedNodes(), [n.c1, d1]);
+ assert_equals(d1.assignedSlot, n.s1);
+
+ assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c1, d1, n.c5]);
+}, 'Slots: Mutation: appendChild.');
+
+test(() => {
+ let n = createTestTree(test_complex);
+ removeWhiteSpaceOnlyTextNodes(n.test_complex);
+
+ n.c1.setAttribute('slot', 'slot-none');
+
+ assert_array_equals(n.s1.assignedNodes(), []);
+ assert_equals(n.c1.assignedSlot, null);
+
+ assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c5]);
+}, 'Slots: Mutation: Change slot= attribute 1.');
+
+test(() => {
+ let n = createTestTree(test_complex);
+ removeWhiteSpaceOnlyTextNodes(n.test_complex);
+
+ n.c1.setAttribute('slot', 'slot2');
+
+ assert_array_equals(n.s1.assignedNodes(), []);
+ assert_array_equals(n.s2.assignedNodes(), [n.c1, n.c2]);
+ assert_equals(n.c1.assignedSlot, n.s2);
+
+ assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c5]);
+ assert_array_equals(n.s6.assignedNodes({ flatten: true }), [n.c1, n.c2, n.c6]);
+}, 'Slots: Mutation: Change slot= attribute 2.');
+
+test(() => {
+ let n = createTestTree(test_complex);
+ removeWhiteSpaceOnlyTextNodes(n.test_complex);
+
+ n.c4.setAttribute('slot', 'slot1');
+
+ assert_array_equals(n.s1.assignedNodes(), [n.c1, n.c4]);
+ assert_equals(n.c4.assignedSlot, n.s1);
+
+ assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c1, n.c4, n.c5]);
+}, 'Slots: Mutation: Change slot= attribute 3.');
+
+test(() => {
+ let n = createTestTree(test_complex);
+ removeWhiteSpaceOnlyTextNodes(n.test_complex);
+
+ n.c1.remove();
+
+ assert_array_equals(n.s1.assignedNodes(), []);
+ assert_equals(n.c1.assignedSlot, null);
+
+ assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c5]);
+}, 'Slots: Mutation: Remove a child.');
+
+test(() => {
+ let n = createTestTree(test_complex);
+ removeWhiteSpaceOnlyTextNodes(n.test_complex);
+
+ let slot = document.createElement('slot');
+ slot.setAttribute('name', 'slot1');
+ n.host2.appendChild(slot);
+
+ assert_array_equals(slot.assignedNodes(), []);
+}, 'Slots: Mutation: Add a slot: after.');
+
+test(() => {
+ let n = createTestTree(test_complex);
+ removeWhiteSpaceOnlyTextNodes(n.test_complex);
+
+ let slot = document.createElement('slot');
+ slot.setAttribute('name', 'slot1');
+ n.host2.insertBefore(slot, n.s1);
+
+ assert_array_equals(slot.assignedNodes(), [n.c1]);
+ assert_equals(n.c1.assignedSlot, slot);
+
+ assert_array_equals(n.s7.assignedNodes(), [slot, n.s3, n.c7]);
+ assert_array_equals(n.s7.assignedNodes({ flatten: true }), [n.c1, n.c3, n.c7]);
+}, 'Slots: Mutation: Add a slot: before.');
+
+test(() => {
+ let n = createTestTree(test_complex);
+ removeWhiteSpaceOnlyTextNodes(n.test_complex);
+
+ n.s1.remove();
+
+ assert_array_equals(n.s1.assignedNodes(), []);
+ assert_equals(n.c1.assignedSlot, null);
+
+ assert_array_equals(n.s5.assignedNodes(), [n.c5]);
+ assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c5]);
+}, 'Slots: Mutation: Remove a slot.');
+
+test(() => {
+ let n = createTestTree(test_complex);
+ removeWhiteSpaceOnlyTextNodes(n.test_complex);
+
+ n.s1.setAttribute('name', 'slot2');
+
+ assert_array_equals(n.s1.assignedNodes(), [n.c2]);
+ assert_equals(n.c1.assignedSlot, null);
+ assert_equals(n.c2.assignedSlot, n.s1);
+
+ assert_array_equals(n.s5.assignedNodes(), [n.s1, n.c5]);
+ assert_array_equals(n.s5.assignedNodes({ flatten: true }), [n.c2, n.c5]);
+}, 'Slots: Mutation: Change slot name= attribute.');
+
+test(() => {
+ let n = createTestTree(test_complex);
+ removeWhiteSpaceOnlyTextNodes(n.test_complex);
+
+ n.s1.setAttribute('slot', 'slot6');
+
+ assert_array_equals(n.s1.assignedNodes(), [n.c1]);
+
+ assert_array_equals(n.s5.assignedNodes(), [n.c5]);
+ assert_array_equals(n.s6.assignedNodes(), [n.s1, n.s2, n.c6]);
+ assert_array_equals(n.s6.assignedNodes({ flatten: true }), [n.c1, n.c2, n.c6]);
+}, 'Slots: Mutation: Change slot slot= attribute.');
+</script>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/LICENSE b/testing/web-platform/tests/shadow-dom/untriaged/LICENSE
new file mode 100644
index 000000000..531fac43a
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/LICENSE
@@ -0,0 +1,107 @@
+Copyright 2012, Google Inc.
+All rights reserved.
+
+Licensed under the W3C Test Suite License (the "License"); you may not
+use this software except in compliance with the License. You may
+obtain a copy of the License at
+
+ http://www.w3.org/Consortium/Legal/2008/04-testsuite-license.html
+
+Alternatively, this software may be distributed under the terms of the
+W3C 3-clause BSD License. You may obtain a copy of the W3C 3-clause
+BSD License at
+
+ http://www.w3.org/Consortium/Legal/2008/03-bsd-license.html
+
+
+W3C Test Suite Licence
+
+This document, Test Suites and other documents that link to this
+statement are provided by the copyright holders under the following
+license: By using and/or copying this document, or the W3C document
+from which this statement is linked, you (the licensee) agree that you
+have read, understood, and will comply with the following terms and
+conditions:
+
+Permission to copy, and distribute the contents of this document, or
+the W3C document from which this statement is linked, in any medium
+for any purpose and without fee or royalty is hereby granted, provided
+that you include the following on ALL copies of the document, or
+portions thereof, that you use:
+
+ 1. A link or URL to the original W3C document.
+ 2. The pre-existing copyright notice of the original author, or if
+it doesn't exist, a notice (hypertext is preferred, but a textual
+representation is permitted) of the form: "Copyright ©
+[$date-of-document] World Wide Web Consortium, (Massachusetts
+Institute of Technology, European Research Consortium for Informatics
+and Mathematics, Keio University) and others. All Rights
+Reserved. http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html"
+ 3. If it exists, the STATUS of the W3C document. When space
+permits, inclusion of the full text of this NOTICE should be
+provided. We request that authorship attribution be provided in any
+software, documents, or other items or products that you create
+pursuant to the implementation of the contents of this document, or
+any portion thereof.
+
+No right to create modifications or derivatives of W3C documents is
+granted pursuant to this license. However, if additional requirements
+(documented in the Copyright FAQ) are satisfied, the right to create
+modifications or derivatives is sometimes granted by the W3C to
+individuals complying with those requirements.
+
+If a Test Suite distinguishes the test harness (or, framework for
+navigation) and the actual tests, permission is given to remove or
+alter the harness or navigation if the Test Suite in question allows
+to do so. The tests themselves shall NOT be changed in any way.
+
+The name and trademarks of W3C and other copyright holders may NOT be
+used in advertising or publicity pertaining to this document or other
+documents that link to this statement without specific, written prior
+permission. Title to copyright in this document will at all times
+remain with copyright holders. Permission is given to use the
+trademarked string W3C within claims of performance concerning W3C
+Specifications or features described therein, and there only, if the
+test suite so authorizes.
+
+THIS WORK IS PROVIDED BY W3C, MIT, ERCIM, KEIO UNIVERSITY, THE
+COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL W3C, MIT, ERCIM, KEIO UNIVERSITY, THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+
+W3C 3-clause BSD License
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of works must retain the original copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the original
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of the W3C nor the names of its contributors may
+be used to endorse or promote products derived from this work without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/README b/testing/web-platform/tests/shadow-dom/untriaged/README
new file mode 100644
index 000000000..5b7572bda
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/README
@@ -0,0 +1,2 @@
+This directory contains tests that have been written before the slot proposal had been adopted by the spec.
+These tests need to be triaged, fixed, and merged back into shadow-dom directory.
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-element-interface/attributes/test-006.html b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-element-interface/attributes/test-006.html
new file mode 100644
index 000000000..7b5a08d3c
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-element-interface/attributes/test-006.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_10_02_01_06</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#shadow-aware-attributes">
+<meta name="assert" content="Extensions to Element Interface: shadowRoot of type ShadowRoot">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(function () {
+
+ var d = newHTMLDocument();
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+
+ assert_equals(host.shadowRoot, null, 'attribute shadowRoot must return null if no shadow tree is accesible');
+
+
+}, 'A_10_02_01_06_T01');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-element-interface/methods/test-001.html b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-element-interface/methods/test-001.html
new file mode 100644
index 000000000..d226c5918
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-element-interface/methods/test-001.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_10_02_02_01</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#shadow-aware-methods">
+<meta name="assert" content="Extensions to Element Interface: attachShadow method creates new instance of Shadow root object">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(function () {
+
+ var d = newHTMLDocument();
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+
+ var s = host.attachShadow({mode: 'open'});
+
+ assert_true(s instanceof ShadowRoot, 'attachShadow() method should create new instance ' +
+ 'of ShadowRoot object');
+
+}, 'A_10_02_02_01_T01');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-element-interface/methods/test-002.html b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-element-interface/methods/test-002.html
new file mode 100644
index 000000000..40e527c8f
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-element-interface/methods/test-002.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_10_02_02_02</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#shadow-aware-methods">
+<meta name="assert" content="Extensions to Element Interface: attachShadow method">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../../html/resources/common.js"></script>
+<script src="../../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+
+ var span = d.createElement('span');
+ span.innerHTML = 'Some text';
+ host.appendChild(span);
+
+ var s = host.attachShadow({mode: 'open'});
+
+ // span should become invisible as shadow root content
+ assert_equals(span.offsetTop, 0, 'attachShadow() method should establish ' +
+ 'the context object as the shadow host of the ShadowRoot object');
+
+}), 'A_10_02_02_02_T01');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-event-interface/event-path-001.html b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-event-interface/event-path-001.html
new file mode 100644
index 000000000..455ee40c3
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/extensions-to-event-interface/event-path-001.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test - event path</title>
+<link rel="author" title="Kazuhito Hokamura" href="mailto:k.hokamura@gmail.com">
+<link rel="help" href="https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#extensions-to-event">
+<meta name="assert" content="Extensions to Event Interface: event.composedPath() cross the shadow boundary">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+<script src="../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+var t = async_test('event.composedPath() cross the shadow boundary');
+
+t.step(unit(function(ctx) {
+ var doc = newRenderedHTMLDocument(ctx);
+ var host = doc.createElement('div');
+
+ var shadowRoot = host.attachShadow({mode: 'open'});
+ var child = doc.createElement('div');
+
+ doc.body.appendChild(host);
+ shadowRoot.appendChild(child);
+
+ child.addEventListener('click', t.step_func(function(e) {
+ assert_equals(e.composedPath().length, 7, 'composedPath().length');
+ assert_equals(e.composedPath()[0], child, 'composedPath()[0] should be child');
+ assert_equals(e.composedPath()[1], shadowRoot, 'composedPath()[1] should be shadowRoot');
+ assert_equals(e.composedPath()[2], host, 'composedPath()[2] should be host');
+ assert_equals(e.composedPath()[3], doc.body, 'composedPath()[3] should be body');
+ assert_equals(e.composedPath()[4], doc.documentElement, 'composedPath()[4] should be html');
+ assert_equals(e.composedPath()[5], doc, 'composedPath()[5] should be document');
+ assert_equals(e.composedPath()[6], ctx.iframes[0].contentWindow, 'composedPath()[6] should be window');
+
+ t.done();
+ }));
+
+ var event = doc.createEvent('HTMLEvents');
+ event.initEvent('click', true, false);
+ child.dispatchEvent(event);
+}));
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/activeElement-confirm-return-null.html b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/activeElement-confirm-return-null.html
new file mode 100644
index 000000000..f0c55ff01
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/activeElement-confirm-return-null.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: Confirm activeElement return null</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="author" title="Masaya Iseki" href="mailto:iseki.m.aa@gmail.com">
+<link rel="help" href="http://w3c.github.io/webcomponents/spec/shadow/#attributes">
+<meta name="assert" content="ShadowRoot Object: confirm activeElement return null">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../../html/resources/common.js"></script>
+<script src="../../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+ var s = host.attachShadow({mode: 'open'});
+
+ assert_equals(s.activeElement, null, 'activeElement attribute of the ShadowRoot must return null if there\'s no focused element');
+
+}), 'confirm activeElement return null');
+
+
+test(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+ var s = host.attachShadow({mode: 'open'});
+
+ var inp = d.createElement('input');
+ d.body.appendChild(inp);
+
+ inp.focus();
+
+ assert_equals(s.activeElement, null, 'activeElement attribute of the ShadowRoot must return null if there\'s no focused element in the shadow tree');
+
+}), 'confirm activeElement return null when there is other element in body');
+
+
+test(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+ var s = host.attachShadow({mode: 'open'});
+
+ var inp = d.createElement('input');
+ d.body.appendChild(inp);
+
+ var inp2 = d.createElement('input');
+ s.appendChild(inp2);
+
+ inp.focus();
+
+ assert_equals(s.activeElement, null, 'activeElement attribute of the ShadowRoot must return null if there\'s no focused element in the shadow tree');
+
+}), 'confirm activeElement return null when focus on the element in the outer shadow tree');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-007.html b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-007.html
new file mode 100644
index 000000000..b7f1f5c2d
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-007.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_10_01_01_03_01</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#shadow-root-attributes">
+<meta name="assert" content="ShadowRoot Object: readonly attribute Element? activeElement; actual value">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../../html/resources/common.js"></script>
+<script src="../../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ host.setAttribute('id', 'shRoot');
+ d.body.appendChild(host);
+ var s = host.attachShadow({mode: 'open'});
+
+ var inp = d.createElement('input');
+ inp.setAttribute('type', 'text');
+ inp.setAttribute('id', 'inpId');
+ inp.setAttribute('value', 'Some text');
+ s.appendChild(inp);
+
+ inp.focus();
+
+ assert_true(s.activeElement != null, 'Point 1: activeElement attribute of the ShadowRoot ' +
+ 'must return the currently focused element in the shadow tree');
+ assert_equals(s.activeElement.tagName, 'INPUT', 'Point 2: activeElement attribute of the ShadowRoot ' +
+ 'must return the currently focused element in the shadow tree');
+
+}), 'A_10_01_01_03_01_T01');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-009.html b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-009.html
new file mode 100644
index 000000000..db02a42c3
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-009.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_10_01_01_04_01</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#shadow-root-attributes">
+<meta name="assert" content="ShadowRoot Object: innerHTML of type DOMString; Test getter">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../../html/resources/common.js"></script>
+<script src="../../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+ var s = host.attachShadow({mode: 'open'});
+
+ var span = d.createElement('span');
+ span.innerHTML = 'Some text';
+ s.appendChild(span);
+
+ assert_equals(s.innerHTML.toLowerCase(), '<span>some text</span>',
+ 'Wrong value of ShadowRoot innerHTML attribute');
+
+}), 'A_10_01_01_04_01_T01');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-010.html b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-010.html
new file mode 100644
index 000000000..2248d6898
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-010.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_10_01_01_04_02</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#shadow-root-attributes">
+<meta name="assert" content="ShadowRoot Object: innerHTML of type DOMString; Test setter">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../../html/resources/common.js"></script>
+<script src="../../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+ var s = host.attachShadow({mode: 'open'});
+
+ var span = d.createElement('span');
+ span.innerHTML = 'Some text';
+ s.appendChild(span);
+
+ s.innerHTML = '<input type="text"><div>new text</div>';
+
+ assert_equals(s.innerHTML.toLowerCase(), '<input type="text"><div>new text</div>',
+ 'Wrong value of ShadowRoot innerHTML attribute');
+
+}), 'A_10_01_01_04_02_T01_01');
+
+
+test(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+ var s = host.attachShadow({mode: 'open'});
+
+ var span = d.createElement('span');
+ span.setAttribute('id', 'spanId');
+ span.innerHTML = 'Some text';
+ s.appendChild(span);
+
+ s.innerHTML = '<input type="text" id="inputId"><div id="divId">new text</div>';
+
+ assert_equals(s.querySelector('#spanId'), null, 'Point 1:innerHTML attribute must replace all content of ' +
+ 'the ShadowRoot object');
+
+ assert_true(s.querySelector('#inputId') != null, 'Point 2:innerHTML attribute must replace all content of ' +
+ 'the ShadowRoot object');
+ assert_equals(s.querySelector('#inputId').getAttribute('id'), 'inputId',
+ 'Point 3:innerHTML attribute must replace all content of the ShadowRoot object');
+
+ assert_true(s.querySelector('#divId') != null, 'Point 3:innerHTML attribute must replace all content of ' +
+ 'the ShadowRoot object');
+ assert_equals(s.querySelector('#divId').getAttribute('id'), 'divId',
+ 'Point 4:innerHTML attribute must replace all content of the ShadowRoot object');
+}), 'A_10_01_01_04_02_T01_02');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-011.html b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-011.html
new file mode 100644
index 000000000..48d22926c
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-011.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_10_01_01_05_01</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#shadow-root-attributes">
+<meta name="assert" content="ShadowRoot Object: styleSheets of type StyleSheetList, readonly">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../../html/resources/common.js"></script>
+<script src="../../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+ var s = host.attachShadow({mode: 'open'});
+
+ assert_true(s.styleSheets != null, 'ShadowRoot styleSheets attribute shouldn\'t be null');
+ assert_equals(s.styleSheets.length, 0, 'attribute must return the shadow root style sheets only');
+
+}), 'A_10_01_01_05_01_T01');
+
+
+test(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+ var s = host.attachShadow({mode: 'open'});
+
+ var style = d.createElement('style');
+ s.appendChild(style);
+
+ assert_true(s.styleSheets != null, 'ShadowRoot styleSheets attribute shouldn\'t be null');
+ assert_equals(s.styleSheets.length, 1, 'attribute must return the shadow root style sheets');
+
+}), 'A_10_01_01_05_01_T02');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-012.html b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-012.html
new file mode 100644
index 000000000..e87443cb5
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-012.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_10_01_01_06</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#shadow-root-attributes">
+<meta name="assert" content="ShadowRoot Object: The nodeType attribute of a ShadowRoot instance must return DOCUMENT_FRAGMENT_NODE">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../../html/resources/common.js"></script>
+<script src="../../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+ var s = host.attachShadow({mode: 'open'});
+
+ assert_equals(s.nodeType, 11, 'The nodeType attribute of a ShadowRoot ' +
+ 'instance must return DOCUMENT_FRAGMENT_NODE');
+
+}), 'A_10_01_01_06_T01');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-013.html b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-013.html
new file mode 100644
index 000000000..6086ed179
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-013.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_10_01_01_07</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#shadow-root-attributes">
+<meta name="assert" content="ShadowRoot Object: The nodeName attribute of a ShadowRoot instance must return "#document-fragment".">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../../html/resources/common.js"></script>
+<script src="../../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+ var s = host.attachShadow({mode: 'open'});
+
+ assert_equals(s.nodeName, '#document-fragment', 'The nodeName attribute of a ShadowRoot instance ' +
+ 'must return "#document-fragment".');
+
+}), 'A_10_01_01_07_T01');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-001.html b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-001.html
new file mode 100644
index 000000000..56f89dd3d
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-001.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_10_01_02_01</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#shadow-root-methods">
+<meta name="assert" content="ShadowRoot Object: HTMLElement getElementById(DOMString elementId) method">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(function () {
+
+ var d = newHTMLDocument();
+
+ var el = d.createElement('div');
+ d.body.appendChild(el);
+
+ var s = el.attachShadow({mode: 'open'});
+
+ var child = d.createElement('span');
+ child.setAttribute('id', 'span_id');
+ s.appendChild(child);
+
+ assert_true(s.getElementById('span_id') != null, 'Point 1: ShadowRoot getElementById() ' +
+ 'method should return child element');
+ assert_equals(s.getElementById('span_id').getAttribute('id'), 'span_id', 'Point 2: ' +
+ 'ShadowRoot getElementById() method should return child element');
+
+}, 'A_10_01_02_01_T01');
+
+
+
+test(function () {
+
+ var d = newHTMLDocument();
+
+ var el = d.createElement('div');
+ d.body.appendChild(el);
+
+ var s = el.attachShadow({mode: 'open'});
+
+ assert_true(s.getElementById('span_id') == null, ' ShadowRoot getElementById() ' +
+ 'method should return null if matching element not found');
+
+}, 'A_10_01_02_01_T02');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-004.html b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-004.html
new file mode 100644
index 000000000..1cd62c4a5
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-004.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_10_01_02_04</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#shadow-root-methods">
+<meta name="assert" content="ShadowRoot Object: Selection? getSelection() method">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../../html/resources/common.js"></script>
+<script src="../../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(unit(function (ctx) {
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+ var s = host.attachShadow({mode: 'open'});
+
+ var span = d.createElement('span');
+ span.innerHTML = 'Some text';
+ s.appendChild(span);
+
+ var range = d.createRange();
+ range.setStart(span.firstChild, 0);
+ range.setEnd(span.firstChild, 3);
+
+ var selection = s.getSelection();
+ selection.removeAllRanges();
+ selection.addRange(range);
+
+ var sl = s.getSelection();
+ assert_equals(sl.toString(), 'Som', 'The getSelection() method of the shadow root object must return ' +
+ 'the current selection in this shadow tree');
+
+}), 'A_10_01_02_04_T01');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-006.html b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-006.html
new file mode 100644
index 000000000..38229ebba
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-006.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_10_01_02_06_01</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#shadow-root-methods">
+<meta name="assert" content="ShadowRoot Object: Element? elementFromPoint(float x, float y) method">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(function () {
+
+ var d = newHTMLDocument();
+
+ var el = d.createElement('div');
+ d.body.appendChild(el);
+
+ try {
+ el.elementFromPoint(1, 1);
+ assert_true(false, 'TypeMismatchError should be thrown');
+ } catch(e) {
+ assert_true(e instanceof TypeError, 'Wrong error type');
+ }
+
+}, 'A_10_01_02_06_01_T01');
+
+// Added test for checking if elementFromPoint() method is existing on Shadowroot.
+test(function () {
+
+ var d = newHTMLDocument();
+
+ var el = d.createElement('div');
+
+ var s = el.attachShadow({mode: 'open'});
+ d.body.appendChild(el);
+
+ if (typeof(s) == 'undefined' || typeof (s.elementFromPoint(1, 1)) != 'object') {
+ assert_true(false, 'Shadowroot doesn\'t have elementFromPoint() method.' );
+ }
+
+}, 'A_10_01_02_06_01_T02');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-007.html b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-007.html
new file mode 100644
index 000000000..fc29b256f
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-007.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_10_01_02_06_02</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#shadow-root-methods">
+<meta name="assert" content="ShadowRoot Object: Element? elementFromPoint(float x, float y) method">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(function () {
+
+ var d = newHTMLDocument();
+
+ var el = d.createElement('div');
+ d.body.appendChild(el);
+
+ var s = el.attachShadow({mode: 'open'});
+
+ var span = d.createElement('span');
+ span.innerHTML = 'Some text';
+ s.appendChild(span);
+
+ assert_equals(s.elementFromPoint(-1, 1), null, 'If x argument of elementFromPoint(x, y) is less ' +
+ 'than zero then method shold return null');
+
+}, 'A_10_01_02_06_02_T01');
+
+
+test(function () {
+
+ var d = newHTMLDocument();
+
+ var el = d.createElement('div');
+ d.body.appendChild(el);
+
+ var s = el.attachShadow({mode: 'open'});
+
+ var span = d.createElement('span');
+ span.innerHTML = 'Some text';
+ s.appendChild(span);
+
+ assert_equals(s.elementFromPoint(1, -1), null, 'If y argument of elementFromPoint(x, y) is less ' +
+ 'than zero then method shold return null');
+
+}, 'A_10_01_02_06_02_T02');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-010.html b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-010.html
new file mode 100644
index 000000000..c183962d7
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-010.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_10_01_02_09</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="https://dom.spec.whatwg.org/#dom-node-clonenode">
+<meta name="assert" content="If context object is a shadow root, throw a NotSupportedError exception.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../../html/resources/common.js"></script>
+<script src="../../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(unit(function (ctx) {
+ var d = newRenderedHTMLDocument(ctx);
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+ var s = host.attachShadow({mode: 'open'});
+
+ try {
+ s.cloneNode();
+ assert_true(false, 'Invoking the cloneNode() method on a ShadowRoot instance must always ' +
+ 'throw a NotSupportedError (code 9) exception.');
+ } catch (e) {
+ assert_equals(e.code, 9, 'Wrong exception type');
+ assert_equals(e.name, 'NotSupportedError', 'Wrong exception name');
+ }
+}), 'A_10_01_02_09_T01');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/events/event-dispatch/test-002.html b/testing/web-platform/tests/shadow-dom/untriaged/events/event-dispatch/test-002.html
new file mode 100644
index 000000000..8ea42cad7
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/events/event-dispatch/test-002.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_05_05_02</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#event-dispatch">
+<meta name="assert" content="Event Dispatch: The MouseEvent relatedTarget attribute must return the adjusted related target">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+<script src="../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+var A_05_05_02_T01 = async_test('A_05_05_02_T01');
+
+A_05_05_02_T01.step(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var invoked = false;
+
+ roots = createTestMediaPlayer(d);
+
+ //expected result of what relative target should be see
+ //see at http://www.w3.org/TR/shadow-dom/#event-retargeting-example
+
+ //For #volume-shadow-root adjusted related target #volume-shadow-root
+ roots.volumeShadowRoot.addEventListener('mouseover',
+ A_05_05_02_T01.step_func(function(event) {
+ invoked = true;
+ assert_true(event.relatedTarget === roots.volumeShadowRoot,
+ 'Wrong relatedTarget');
+ }), false);
+
+
+
+
+ var evt = document.createEvent("MouseEvents");
+ evt.initMouseEvent("mouseover", true, false, window,
+ 0, 10, 10, 10, 10, false, false, false, false, 0, roots.volumeShadowRoot);
+
+ roots.volumeShadowRoot.querySelector('#volume-slider-thumb').dispatchEvent(evt);
+ assert_true(invoked, 'Event listener was not invoked');
+ A_05_05_02_T01.done();
+}));
+
+//TODO (sgrekhov) Add tests for other nodes from http://www.w3.org/TR/shadow-dom/#event-retargeting-example
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/events/event-dispatch/test-003.html b/testing/web-platform/tests/shadow-dom/untriaged/events/event-dispatch/test-003.html
new file mode 100644
index 000000000..78b76de7d
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/events/event-dispatch/test-003.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_05_05_03</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="https://w3c.github.io/webcomponents/spec/shadow/#event-path-trimming">
+<meta name="assert" content="Event Path Trimming: In cases where both relatedTarget and target of a trusted event are part of the same shadow tree, the conforming UAs must stop events at the shadow root to avoid the appearance of spurious mouseover and mouseout events firing from the same node.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+<script src="../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+var A_05_05_03_T01 = async_test('A_05_05_03_T01');
+
+A_05_05_03_T01.step(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ host.setAttribute('id', 'host');
+ d.body.appendChild(host);
+
+ //Shadow root to play with
+ var s = host.attachShadow({mode: 'open'});
+ s.id = 'shadow';
+
+ var input1 = d.createElement('input');
+ input1.setAttribute('id', 'input1');
+ s.appendChild(input1);
+
+ var input2 = d.createElement('input');
+ input2.setAttribute('id', 'input2');
+ s.appendChild(input2);
+
+ input1.addEventListener('focusin', A_05_05_03_T01.step_func(function(event) {
+ assert_equals(event.composedPath().length, 7);
+ assert_equals(event.composedPath()[0].id, 'input1');
+ assert_equals(event.composedPath()[1].id, 'shadow');
+ assert_equals(event.composedPath()[2].id, 'host');
+ assert_equals(event.composedPath()[3].tagName, 'BODY');
+ assert_equals(event.composedPath()[4].tagName, 'HTML');
+ assert_equals(event.composedPath()[5], d);
+ assert_equals(event.composedPath()[6], ctx.iframes[0].contentWindow);
+ }), false);
+
+ input2.addEventListener('focusin', A_05_05_03_T01.step_func(function(event) {
+ assert_equals(event.composedPath().length, 2);
+ assert_equals(event.composedPath()[0].id, 'input2');
+ assert_equals(event.composedPath()[1].id, 'shadow');
+ A_05_05_03_T01.done();
+ }), false);
+
+ // Expected event path for #input1:
+ // <input>, #shadow-root, <div>, <body>, <html>, #document, window
+ input1.focus();
+
+ // Causes a "focusin" event, from #input1 to #input2
+ // In this case, original relatedTarget is #input1, and original target
+ // is #input2.
+ // It should be viewed outside the shadow as "target == relatedTarget"
+ // after event retargeting, therefore, event.composedPath() above the shadow
+ // host will be trimmed.
+ // Expected event path for #input2:
+ // <input>, #shadow-root
+ input2.focus();
+}));
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/events/event-retargeting/test-001.html b/testing/web-platform/tests/shadow-dom/untriaged/events/event-retargeting/test-001.html
new file mode 100644
index 000000000..227d9e18b
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/events/event-retargeting/test-001.html
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_05_01_01</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#event-retargeting">
+<meta name="assert" content="Event Retargeting:test that event.target is retargeted when event crosses shadow boundary and vice versa">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+var A_05_01_01_T1 = async_test('A_05_01_01_T1');
+
+A_05_01_01_T1.step(function () {
+ var iframe = document.createElement('iframe');
+ iframe.src = '../../resources/blank.html';
+ document.body.appendChild(iframe);
+
+ iframe.onload = A_05_01_01_T1.step_func(function () {
+
+ try {
+ var d = iframe.contentDocument;
+ var div = d.createElement('div');
+ d.body.appendChild(div);
+
+ var s = div.attachShadow({mode: 'open'});
+
+ var div2 = d.createElement('div');
+ s.appendChild(div2);
+
+ var inp = d.createElement('input');
+ inp.setAttribute('type', 'text');
+ inp.setAttribute('id', 'inpid');
+ div2.appendChild(inp);
+
+ div2.addEventListener('click', A_05_01_01_T1.step_func(function (event) {
+ assert_equals(event.target.tagName, 'INPUT', 'Information about target of the event that ' +
+ 'doesn\'t cross the shadow boundaries should not be adjusted');
+ }), false);
+
+ var event = d.createEvent('HTMLEvents');
+ event.initEvent ("click", true, false);
+ inp.dispatchEvent(event);
+ } finally {
+ iframe.parentNode.removeChild(iframe);
+ }
+ A_05_01_01_T1.done();
+ });
+});
+
+
+
+var A_05_01_01_T2 = async_test('A_05_01_01_T2');
+
+A_05_01_01_T2.step(function () {
+ var iframe = document.createElement('iframe');
+ iframe.src = '../../resources/blank.html';
+ document.body.appendChild(iframe);
+
+ iframe.onload = A_05_01_01_T2.step_func(function () {
+
+ try {
+ var d = iframe.contentDocument;
+
+ var div = d.createElement('div');
+ d.body.appendChild(div);
+
+ var s = div.attachShadow({mode: 'open'});
+
+ var div2 = d.createElement('div');
+ s.appendChild(div2);
+
+ var inp = d.createElement('input');
+ inp.setAttribute('type', 'text');
+ inp.setAttribute('id', 'inpid');
+ div2.appendChild(inp);
+
+ div.addEventListener('click', A_05_01_01_T2.step_func(function (event) {
+ assert_equals(event.target.tagName, 'DIV', 'Information about event target crossing ' +
+ 'the shadow boundaries should be adjusted');
+ }), false);
+
+ var event = d.createEvent('HTMLEvents');
+ event.initEvent ("click", true, false);
+ inp.dispatchEvent(event);
+ } finally {
+ iframe.parentNode.removeChild(iframe);
+ }
+ A_05_01_01_T2.done();
+ });
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/events/event-retargeting/test-003.html b/testing/web-platform/tests/shadow-dom/untriaged/events/event-retargeting/test-003.html
new file mode 100644
index 000000000..5e1d9bb32
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/events/event-retargeting/test-003.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_05_01_03</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#event-retargeting">
+<meta name="assert" content="Event Retargeting:Event retargeting for fallback content">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+<script src="../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+var A_05_01_03_T01 = async_test('A_05_01_03_T01');
+
+A_05_01_03_T01.step(unit(function (ctx) {
+ var d = newRenderedHTMLDocument(ctx);
+
+ d.body.innerHTML = '' +
+ '<div id="main">' +
+ '<div id="shadow-root">' +
+ '<span>1</span>' +
+ '<span>2</span>' +
+ '<span>3</span>' +
+ '</div>' +
+ '</div>';
+
+ var ul = d.querySelector('#shadow-root');
+ var s = ul.attachShadow({mode: 'open'});
+
+ //make shadow subtree
+ var div = document.createElement('div');
+ div.innerHTML = '<slot name="shadow"><span id="flbk">Fallback item</span></slot>';
+ s.appendChild(div);
+
+ d.body.addEventListener('click', A_05_01_03_T01.step_func(function (event) {
+ assert_equals(event.target.getAttribute('id'), 'shadow-root', 'Information about ' +
+ 'event target crossing the shadow boundaries should be adjusted for the fallback ' +
+ 'content');
+ }), false);
+
+ var event = d.createEvent('HTMLEvents');
+ event.initEvent ("click", true, false);
+ s.querySelector('#flbk').dispatchEvent(event);
+
+ A_05_01_03_T01.done();
+}));
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-focus-events/test-001.html b/testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-focus-events/test-001.html
new file mode 100644
index 000000000..296346bf1
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-focus-events/test-001.html
@@ -0,0 +1,322 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_05_03_01</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#retargeting-focus-events">
+<meta name="assert" content="Retargeting focus events:The focus, DOMFocusIn, blur, and DOMFocusOut events must be treated in the same way as events with a relatedTarget, where the corresponding node that is losing focus as a result of target gaining focus or the node that is gaining focus, and thus causing the blurring of target acts as the related target">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+<script src="../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+//blur and focus events are not bubbling. So this test tests only DOMFocusIn and DOMFocusOut
+//which do bubble
+
+//test DOMFocusOut event
+var A_05_03_01_T01 = async_test('A_05_03_01_T01');
+
+A_05_03_01_T01.step(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ host.setAttribute('style', 'height:50%; width:100%');
+ host.setAttribute('id', 'host');
+ d.body.appendChild(host);
+
+ //Shadow root to play with
+ var s = host.attachShadow({mode: 'open'});
+
+ var inp1 = d.createElement('input');
+ inp1.setAttribute('id', 'inp1');
+ inp1.setAttribute('type', 'checkbox');
+ s.appendChild(inp1);
+
+ var inp2 = d.createElement('input');
+ inp2.setAttribute('id', 'inp2');
+ inp2.setAttribute('type', 'checkbox');
+ d.body.appendChild(inp2);
+
+ s.addEventListener('DOMFocusOut', A_05_03_01_T01.step_func(function(event) {
+ assert_equals(event.target.getAttribute('id'), 'inp1', 'Inside shadow tree: Wrong target');
+ }), false);
+
+ d.body.addEventListener('DOMFocusOut', A_05_03_01_T01.step_func(function(event) {
+ assert_equals(event.target.getAttribute('id'), 'host', 'Inside shadow tree: Wrong target');
+ }), false);
+
+ inp1.focus();
+ inp2.focus();
+
+ A_05_03_01_T01.done();
+}));
+
+
+//test DOMFocusIn event
+var A_05_03_01_T02 = async_test('A_05_03_01_T02');
+
+A_05_03_01_T02.step(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ host.setAttribute('style', 'height:50%; width:100%');
+ host.setAttribute('id', 'host');
+ d.body.appendChild(host);
+
+ //Shadow root to play with
+ var s = host.attachShadow({mode: 'open'});
+
+ var inp1 = d.createElement('input');
+ inp1.setAttribute('id', 'inp1');
+ inp1.setAttribute('type', 'checkbox');
+ s.appendChild(inp1);
+
+ var inp2 = d.createElement('input');
+ inp2.setAttribute('id', 'inp2');
+ inp2.setAttribute('type', 'checkbox');
+ d.body.appendChild(inp2);
+
+ inp2.focus();
+
+ s.addEventListener('DOMFocusIn', A_05_03_01_T02.step_func(function(event) {
+ assert_equals(event.target.getAttribute('id'), 'inp1', 'Inside shadoe tree: Wrong target');
+ }), false);
+
+ d.body.addEventListener('DOMFocusIn', A_05_03_01_T02.step_func(function(event) {
+ assert_equals(event.target.getAttribute('id'), 'host', 'Outside shadow tree: Wrong target');
+ }), false);
+
+ inp1.focus();
+
+ A_05_03_01_T02.done();
+}));
+
+
+//gaining and loosing focus elements are in the same tree.
+//DOMFocusIn event should be stopped at shadow boundary
+var A_05_03_01_T03 = async_test('A_05_03_01_T03');
+
+
+A_05_03_01_T03.step(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ host.setAttribute('style', 'height:50%; width:100%');
+ host.setAttribute('id', 'host');
+ d.body.appendChild(host);
+
+ //Shadow root to play with
+ var s = host.attachShadow({mode: 'open'});
+
+ var inp1 = d.createElement('input');
+ inp1.setAttribute('id', 'inp1');
+ inp1.setAttribute('type', 'checkbox');
+ s.appendChild(inp1);
+
+ var inp2 = d.createElement('input');
+ inp2.setAttribute('id', 'inp2');
+ inp2.setAttribute('type', 'checkbox');
+ s.appendChild(inp2);
+
+ inp1.focus();
+
+ d.body.addEventListener('DOMFocusIn', A_05_03_01_T03.step_func(function(event) {
+ assert_true(false, 'Event should be stopped at Shadow boundary');
+ }), false);
+
+ inp2.focus();
+
+ A_05_03_01_T03.done();
+}));
+
+
+
+
+//gaining and loosing focus elements are in the same tree.
+//DOMFocusOut event should be stopped at shadow boundary
+var A_05_03_01_T04 = async_test('A_05_03_01_T04');
+
+A_05_03_01_T04.step(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ host.setAttribute('style', 'height:50%; width:100%');
+ host.setAttribute('id', 'host');
+ d.body.appendChild(host);
+
+ //Shadow root to play with
+ var s = host.attachShadow({mode: 'open'});
+
+ var inp1 = d.createElement('input');
+ inp1.setAttribute('id', 'inp1');
+ inp1.setAttribute('type', 'checkbox');
+ s.appendChild(inp1);
+
+ var inp2 = d.createElement('input');
+ inp2.setAttribute('id', 'inp2');
+ inp2.setAttribute('type', 'checkbox');
+ s.appendChild(inp2);
+
+ inp1.focus();
+
+ d.body.addEventListener('DOMFocusOut', A_05_03_01_T04.step_func(function(event) {
+ assert_true(false, 'Event should be stopped at Shadow boundary');
+ }), false);
+
+ inp2.focus();
+
+ A_05_03_01_T04.done();
+}));
+
+
+
+
+//Retargeting shouldn't occur for DOM tree nodes distributed
+//among insertion point. Check DOMFocusOut
+var A_05_03_01_T05 = async_test('A_05_03_01_T05');
+
+A_05_03_01_T05.step(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ host.setAttribute('id', 'host');
+ d.body.appendChild(host);
+
+ var inp1 = d.createElement('input');
+ inp1.setAttribute('id', 'inp1');
+ inp1.setAttribute('type', 'checkbox');
+ inp1.setAttribute('slot', 'slot1');
+ host.appendChild(inp1);
+
+ var inp2 = d.createElement('input');
+ inp2.setAttribute('id', 'inp2');
+ inp2.setAttribute('type', 'checkbox');
+ inp2.setAttribute('slot', 'slot2');
+ host.appendChild(inp2);
+
+ var inp3 = d.createElement('input');
+ inp3.setAttribute('id', 'inp3');
+ inp3.setAttribute('type', 'checkbox');
+ inp3.setAttribute('slot', 'slot1');
+ host.appendChild(inp3);
+
+
+ //Shadow root to play with
+ var s = host.attachShadow({mode: 'open'});
+
+ var shadowDiv = document.createElement('div');
+ shadowDiv.innerHTML = '<slot name="slot1"></slot>';
+ s.appendChild(shadowDiv);
+
+ //element outside the shadow tree
+ var inp4 = d.createElement('input');
+ inp4.setAttribute('id', 'inp4');
+ inp4.setAttribute('type', 'checkbox');
+ inp4.setAttribute('slot', 'slot1');
+ d.body.appendChild(inp4);
+
+ inp1.focus();
+
+ s.addEventListener('DOMFocusOut', A_05_03_01_T05.step_func(function(event) {
+ assert_equals(event.target.getAttribute('id'), 'inp1', 'Inside shadow tree: ' +
+ 'Event for nodes, distributed ' +
+ 'agains insertion points shouldn\'t be retargeted');
+ }), false);
+
+
+ d.body.addEventListener('DOMFocusOut', A_05_03_01_T05.step_func(function(event) {
+ assert_equals(event.target.getAttribute('id'), 'inp1', 'Outside shadow tree: ' +
+ 'Event for nodes, distributed ' +
+ 'agains insertion points shouldn\'t be retargeted');
+ }), false);
+
+ inp4.focus();
+
+ A_05_03_01_T05.done();
+}));
+
+
+//Retargeting shouldn't occur for DOM tree nodes distributed
+//among insertion points. Check DOMFocusIn
+var A_05_03_01_T06 = async_test('A_05_03_01_T06');
+
+A_05_03_01_T06.step(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ host.setAttribute('id', 'host');
+ d.body.appendChild(host);
+
+ var inp1 = d.createElement('input');
+ inp1.setAttribute('id', 'inp1');
+ inp1.setAttribute('type', 'checkbox');
+ inp1.setAttribute('slot', 'slot1');
+ host.appendChild(inp1);
+
+ var inp2 = d.createElement('input');
+ inp2.setAttribute('id', 'inp2');
+ inp2.setAttribute('type', 'checkbox');
+ inp2.setAttribute('slot', 'slot2');
+ host.appendChild(inp2);
+
+ var inp3 = d.createElement('input');
+ inp3.setAttribute('id', 'inp3');
+ inp3.setAttribute('type', 'checkbox');
+ inp3.setAttribute('slot', 'slot1');
+ host.appendChild(inp3);
+
+
+ //Shadow root to play with
+ var s = host.attachShadow({mode: 'open'});
+
+ var shadowDiv = document.createElement('div');
+ shadowDiv.innerHTML = '<slot name="slot1"></slot>';
+ s.appendChild(shadowDiv);
+
+ //element outside the shadow tree
+ var inp4 = d.createElement('input');
+ inp4.setAttribute('id', 'inp4');
+ inp4.setAttribute('type', 'checkbox');
+ inp4.setAttribute('slot', 'slot1');
+ d.body.appendChild(inp4);
+
+ inp4.focus();
+
+ s.addEventListener('DOMFocusIn', A_05_03_01_T06.step_func(function(event) {
+ assert_equals(event.target.getAttribute('id'), 'inp1', 'Inside shadow tree: ' +
+ 'Event for nodes, distributed ' +
+ 'agains insertion points shouldn\'t be retargeted');
+ }), false);
+
+
+ d.body.addEventListener('DOMFocusIn', A_05_03_01_T05.step_func(function(event) {
+ assert_equals(event.target.getAttribute('id'), 'inp1', 'Outside shadow tree: ' +
+ 'Event for nodes, distributed ' +
+ 'agains insertion points shouldn\'t be retargeted');
+ }), false);
+
+ inp1.focus();
+
+ A_05_03_01_T06.done();
+}));
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-focus-events/test-002.html b/testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-focus-events/test-002.html
new file mode 100644
index 000000000..0e22dd6fb
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-focus-events/test-002.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_05_03_02</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#retargeting-focus-events">
+<meta name="assert" content="Retargeting focus events:The blur event must be treated in the same way as events with a relatedTarget, where the node that is gaining focus causing the blurring of target acts as the related target">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+<script src="../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+//test blur event
+var A_05_03_02_T01 = async_test('A_05_03_02_T01');
+
+
+A_05_03_02_T01.step(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var invoked = false;
+
+ var roots = createTestMediaPlayer(d);
+
+ roots.playerShadowRoot.querySelector('.volume-slider').focus();
+
+ //expected result of what relative target should be see
+ //see at http://www.w3.org/TR/shadow-dom/#event-retargeting-example
+
+ //For #volume-slider relative target is #volume-slider
+ roots.playerShadowRoot.querySelector('.volume-slider').addEventListener('blur',
+ A_05_03_02_T01.step_func(function(event) {
+ invoked = true;
+ assert_equals(event.target.getAttribute('id'), 'volume-slider',
+ 'Wrong target');
+ }), false);
+
+ // move focus out of shadow tree. blur should be fired
+ d.querySelector('#outside-control').focus();
+
+ assert_true(invoked, 'Event listener was not invoked');
+
+ A_05_03_02_T01.done();
+}));
+
+
+//TODO (sgrekhov) add test for the case when related target differs from the
+//node on which event listener is invoked
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-focus-events/test-003.html b/testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-focus-events/test-003.html
new file mode 100644
index 000000000..19e4b9967
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-focus-events/test-003.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_05_03_03</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#retargeting-focus-events">
+<meta name="assert" content="Retargeting focus events:The focus event must be treated in the same way as events with a relatedTarget, where the corresponding node that is losing focus as a result of target gaining focus or the node that is gaining focus">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+<script src="../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+//test focus event
+var A_05_03_03_T01 = async_test('A_05_03_03_T01');
+
+
+A_05_03_03_T01.step(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var invoked = false;
+
+ var roots = createTestMediaPlayer(d);
+
+ d.querySelector('#outside-control').focus();
+
+ //expected result of what relative target should be see
+ //see at http://www.w3.org/TR/shadow-dom/#event-retargeting-example
+
+ //For #volume-slider relative target is #volume-slider
+ roots.playerShadowRoot.querySelector('.volume-slider').addEventListener('focus',
+ A_05_03_03_T01.step_func(function(event) {
+ invoked = true;
+ assert_equals(event.target.getAttribute('id'), 'volume-slider',
+ 'Wrong target');
+ }), false);
+
+ roots.playerShadowRoot.querySelector('.volume-slider').focus();
+
+ assert_true(invoked, 'Event listener was not invoked');
+
+ A_05_03_03_T01.done();
+}));
+
+
+//TODO (sgrekhov) add test for the case when related target differs from the
+//node on which event listener is invoked
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-relatedtarget/test-001.html b/testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-relatedtarget/test-001.html
new file mode 100644
index 000000000..ef9a24113
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-relatedtarget/test-001.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_05_02_01</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-201305214#retargeting-related-target">
+<meta name="assert" content="Retargeting relatedTarget:Event retargeting is a process of computing relative targets for each ancestor of the node at which the event is dispatched. A relative target is a DOM node that most accurately represents the target of a dispatched event at a given ancestor while maintaining the upper boundary encapsulation.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+<script src="../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+var A_05_02_01_T01 = async_test('A_05_02_01_T1');
+
+A_05_02_01_T01.step(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ host.setAttribute('style', 'height:100%; width:100%');
+ host.setAttribute('id', 'host');
+ d.body.appendChild(host);
+
+ //Shadow root to play with
+ var s = host.attachShadow({mode: 'open'});
+
+ var div1 = d.createElement('div');
+ div1.setAttribute('style', 'height:40px; width:100%');
+ div1.setAttribute('id', 'div1');
+ s.appendChild(div1);
+
+ var div2 = d.createElement('div');
+ div2.setAttribute('style', 'height:40px; width:100%');
+ div2.setAttribute('id', 'div2');
+ s.appendChild(div2);
+
+ s.addEventListener('mouseover', A_05_02_01_T01.step_func(function(event) {
+ assert_equals(event.relatedTarget.getAttribute('id'), 'div1', 'Wrong relatedTarget');
+ }), false);
+
+ d.body.addEventListener('mouseover', A_05_02_01_T01.step_func(function(event) {
+ assert_true(false, 'Event must be stopped at Shadow boundary');
+ }), false);
+
+
+ var evt = document.createEvent("MouseEvents");
+ evt.initMouseEvent("mouseover", true, false, window,
+ 0, 10, 10, 10, 10, false, false, false, false, 0, div1);
+
+ div2.dispatchEvent(evt);
+
+
+ A_05_02_01_T01.done();
+}));
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-relatedtarget/test-002.html b/testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-relatedtarget/test-002.html
new file mode 100644
index 000000000..22be13713
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-relatedtarget/test-002.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_05_02_02</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-201305214#retargeting-related-target">
+<meta name="assert" content="Retargeting relatedTarget:For a given node, the relatedTarget must be changed to its ancestor (or self) that is in the same shadow tree as the node">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+<script src="../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+var A_05_02_02_T01 = async_test('A_05_02_02_T01');
+
+A_05_02_02_T01.step(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ host.setAttribute('style', 'height:50%; width:100%');
+ host.setAttribute('id', 'host');
+ d.body.appendChild(host);
+
+ //Shadow root to play with
+ var s = host.attachShadow({mode: 'open'});
+
+ var div1 = d.createElement('div');
+ div1.setAttribute('style', 'height:100%; width:100%');
+ div1.setAttribute('id', 'div1');
+ s.appendChild(div1);
+
+ var div2 = d.createElement('div');
+ div2.setAttribute('style', 'height:100%; width:100%');
+ div2.setAttribute('id', 'div2');
+ d.body.appendChild(div2);
+
+ d.body.addEventListener('mouseover', A_05_02_02_T01.step_func(function(event) {
+ assert_equals(event.relatedTarget.getAttribute('id'), 'host', 'Wrong related target');
+ }), false);
+
+
+ var evt = document.createEvent("MouseEvents");
+ evt.initMouseEvent("mouseover", true, false, window,
+ 0, 10, 10, 10, 10, false, false, false, false, 0, div1);
+
+ div2.dispatchEvent(evt);
+
+ A_05_02_02_T01.done();
+}));
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-relatedtarget/test-003.html b/testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-relatedtarget/test-003.html
new file mode 100644
index 000000000..3e8d6709e
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/events/retargeting-relatedtarget/test-003.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_05_02_03</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="https://w3c.github.io/webcomponents/spec/shadow/#event-relatedtarget-retargeting">
+<meta name="assert" content="The value of the Event object's relatedTarget attribute must be the result of the retargeting algorithm with the event's currentTarget and relatedTarget as input. The result is called a relative related target.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+<script src="../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+var A_05_02_03_T01 = async_test('A_05_02_03_T01');
+
+A_05_02_03_T01.step(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ host.setAttribute('style', 'height:50%; width:100%');
+ host.setAttribute('id', 'host');
+ d.body.appendChild(host);
+
+ //Shadow root to play with
+ var s = host.attachShadow({mode: 'open'});
+
+ var div1 = d.createElement('div');
+ div1.setAttribute('style', 'height:100%; width:100%');
+ div1.setAttribute('id', 'div1');
+ s.appendChild(div1);
+
+ host.addEventListener('mouseover', A_05_02_03_T01.step_func(function(event) {
+ assert_unreached('Event listeners shouldn\'t be invoked if relative target and relative related target are the same');
+ }), false);
+
+ var evt = new MouseEvent("mouseover",
+ { relatedTarget: div1, relatedTargetScoped: true });
+ div1.dispatchEvent(evt);
+
+ A_05_02_03_T01.done();
+}));
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/events/test-001.html b/testing/web-platform/tests/shadow-dom/untriaged/events/test-001.html
new file mode 100644
index 000000000..4e56c4051
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/events/test-001.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_05_00_01</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#events">
+<meta name="assert" content="Events:The mutation event types must never be dispatched in a shadow DOM subtree.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+var A_05_00_01_T1 = async_test('A_05_00_01_T1');
+
+A_05_00_01_T1.step(function () {
+ var iframe = document.createElement('iframe');
+ iframe.src = '../resources/blank.html';
+ document.body.appendChild(iframe);
+
+ iframe.onload = A_05_00_01_T1.step_func(function () {
+
+ try {
+ var d = iframe.contentDocument;
+
+ var div = d.createElement('div');
+ d.body.appendChild(div);
+
+ var s = div.attachShadow({mode: 'open'});
+
+ var div2 = d.createElement('div');
+ s.appendChild(div2);
+
+ var inp = d.createElement('input');
+ inp.setAttribute('type', 'text');
+ inp.setAttribute('id', 'inpid');
+ div2.appendChild(inp);
+
+ div2.addEventListener('DOMAttrModified', A_05_00_01_T1.step_func(function (event) {
+ assert_true(false, 'The mutation event types must never be dispatched in a shadow DOM subtree');
+ }), false);
+ /*
+ var attr = inp.getAttributeNode ("value");
+ var event = d.createEvent('MutationEvent');
+ event.initMutationEvent ("DOMAttrModified", true, true, attr, null, 'new value', "value", MutationEvent.MODIFICATION);
+ inp.dispatchEvent(event);
+ */
+ inp.value = 'new value';
+ inp.setAttribute ("newAttr" , "firstValue");
+ inp.setAttribute ("newAttr" , "secondValue");
+ inp.removeAttribute ("newAttr");
+ } finally {
+ iframe.parentNode.removeChild(iframe);
+ }
+ A_05_00_01_T1.done();
+ });
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/html-elements-in-shadow-trees/html-forms/test-001.html b/testing/web-platform/tests/shadow-dom/untriaged/html-elements-in-shadow-trees/html-forms/test-001.html
new file mode 100644
index 000000000..c8cfeceee
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/html-elements-in-shadow-trees/html-forms/test-001.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_08_02_01</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#html-forms">
+<meta name="assert" content="HTML Elements in shadow trees: Form elements and form-associated elements in shadow tree are not accessible using document DOM object's tree accessors">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+//test form-associated elements
+test(function () {
+ var d = newHTMLDocument();
+
+ var form = d.createElement('form');
+ form.setAttribute('id', 'form_id');
+ d.body.appendChild(form);
+
+ var div = d.createElement('div');
+ d.body.appendChild(div);
+ var s = div.attachShadow({mode: 'open'});
+
+
+ HTML5_FORM_ASSOCIATED_ELEMENTS.forEach(function (tagName) {
+
+ var el = d.createElement(tagName);
+ el.setAttribute('form', 'form_id');
+ el.setAttribute('id', tagName + '_id');
+ s.appendChild(el);
+
+ assert_equals(d.querySelector('#' + tagName + '_id'), null, 'Form-associated element ' + tagName +
+ ' in shadow tree must not be accessible using owner\'s document tree accessors');
+ });
+}, 'A_08_02_01_T01');
+
+
+//test form elements
+test(function () {
+ var d = newHTMLDocument();
+
+ var form = d.createElement('form');
+ d.body.appendChild(form);
+
+ var div = d.createElement('div');
+ form.appendChild(div);
+ s = div.attachShadow({mode: 'open'});
+
+ HTML5_FORM_ASSOCIATED_ELEMENTS.forEach(function (tagName) {
+
+ var el = d.createElement(tagName);
+ el.setAttribute('id', tagName + '_id');
+ s.appendChild(el);
+
+ assert_equals(d.querySelector('#' + tagName + '_id'), null, 'Form element ' + tagName +
+ ' in shadow tree must not be accessible using owner\'s document tree accessors');
+ });
+}, 'A_08_02_01_T02');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/html-elements-in-shadow-trees/html-forms/test-002.html b/testing/web-platform/tests/shadow-dom/untriaged/html-elements-in-shadow-trees/html-forms/test-002.html
new file mode 100644
index 000000000..2d063c06a
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/html-elements-in-shadow-trees/html-forms/test-002.html
@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_08_02_02</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#html-forms">
+<meta name="assert" content="HTML Elements in shadow trees: Form elements and form-associated elements in shadow tree must be accessible using shadow tree accessors">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+//test form-associated elements
+test(function () {
+ var d = newHTMLDocument();
+
+ var form = d.createElement('form');
+ form.setAttribute('id', 'form_id');
+ d.body.appendChild(form);
+
+ var div = d.createElement('div');
+ d.body.appendChild(div);
+ var s = div.attachShadow({mode: 'open'});
+
+
+ HTML5_FORM_ASSOCIATED_ELEMENTS.forEach(function (tagName) {
+
+ var el = d.createElement(tagName);
+ el.setAttribute('form', 'form_id');
+ el.setAttribute('id', tagName + '_id');
+ s.appendChild(el);
+
+ assert_true(s.querySelector('#' + tagName + '_id') != null, 'Form-associated element ' + tagName +
+ ' in shadow tree must be accessible shadow tree accessors');
+ assert_equals(s.querySelector('#' + tagName + '_id').getAttribute('id'), tagName + '_id',
+ 'Form-associated element ' + tagName + ' in shadow tree must be accessible shadow tree accessors');
+ });
+}, 'A_08_02_02_T01');
+
+
+//test form elements
+test(function () {
+ var d = newHTMLDocument();
+
+ var form = d.createElement('form');
+ d.body.appendChild(form);
+
+ var div = d.createElement('div');
+ form.appendChild(div);
+ var s = div.attachShadow({mode: 'open'});
+
+ HTML5_FORM_ASSOCIATED_ELEMENTS.forEach(function (tagName) {
+
+ var el = d.createElement(tagName);
+ el.setAttribute('id', tagName + '_id');
+ s.appendChild(el);
+
+ assert_true(s.querySelector('#' + tagName + '_id') != null, 'Form-associated element ' + tagName +
+ ' in shadow tree must be accessible shadow tree accessors');
+ assert_equals(s.querySelector('#' + tagName + '_id').getAttribute('id'), tagName + '_id',
+ 'Form element ' + tagName + ' in shadow tree must be accessible shadow tree accessors');
+ });
+}, 'A_08_02_02_T02');
+
+
+//test distributed form elements
+test(function () {
+ var d = newHTMLDocument();
+
+ HTML5_FORM_ASSOCIATED_ELEMENTS.forEach(function (tagName) {
+
+ var form = d.createElement('form');
+ d.body.appendChild(form);
+
+ var div = d.createElement('div');
+ form.appendChild(div);
+
+ var el = d.createElement(tagName);
+ el.setAttribute('id', tagName + '_id');
+ el.setAttribute('slot', tagName + '_slot');
+ div.appendChild(el);
+
+ var s = div.attachShadow({mode: 'open'});
+ s.innerHTML = '<slot name="' + tagName + '_slot"></slot>';
+
+ assert_true(s.querySelector('#' + tagName + '_id') == null, 'Distributed form-associated element ' + tagName +
+ ' in shadow tree must not be accessible shadow tree accessors');
+ });
+}, 'A_08_02_02_T03');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/html-elements-in-shadow-trees/html-forms/test-003.html b/testing/web-platform/tests/shadow-dom/untriaged/html-elements-in-shadow-trees/html-forms/test-003.html
new file mode 100644
index 000000000..0bc92e11d
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/html-elements-in-shadow-trees/html-forms/test-003.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_08_02_03</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="https://w3c.github.io/webcomponents/spec/shadow/#inertness-of-html-elements-in-a-shadow-tree">
+<meta name="assert" content="HTML Elements in shadow trees: form should not submit elements in shadow tree">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+var A_08_02_03_T01 = async_test('A_08_02_03_T01', { timeout: 5000 });
+
+var checkIframeContent = A_08_02_03_T01.step_func(function () {
+ // remember value to check before cleaning the context (it'll destroy the iframe)
+ var valueToCheck = A_08_02_03_T01.iframe.contentWindow.document.URL;
+ cleanContext(A_08_02_03_T01.ctx);
+
+ assert_true(valueToCheck.indexOf('inp1=value1') > 0,
+ 'html form should submit all of its fields');
+
+ // Form data crossing shadow boundary should not be submitted.
+ // https://github.com/w3c/webcomponents/issues/65
+ assert_equals(valueToCheck.indexOf('inp2=value2'), -1,
+ 'html form should not submit fields in the shadow tree');
+
+ A_08_02_03_T01.done();
+});
+
+
+A_08_02_03_T01.step(function () {
+
+ A_08_02_03_T01.ctx = newContext();
+ var d = newRenderedHTMLDocument(A_08_02_03_T01.ctx);
+
+ //create iframe
+ var iframe = document.createElement('iframe');
+ A_08_02_03_T01.iframe = iframe;
+
+ iframe.src = '../../resources/blank.html';
+ iframe.setAttribute('name', 'targetIframe');
+ d.body.appendChild(iframe);
+
+ // create form
+ var form = d.createElement('form');
+ form.setAttribute('target', 'targetIframe');
+ form.setAttribute('method', 'GET');
+ form.setAttribute('action', '../../resources/blank.html');
+ d.body.appendChild(form);
+
+ // create shadow root
+ var root = d.createElement('div');
+ form.appendChild(root);
+ var s = root.attachShadow({mode: 'open'});
+
+ var input1 = d.createElement('input');
+ input1.setAttribute('type', 'text');
+ input1.setAttribute('name', 'inp1');
+ input1.setAttribute('value', 'value1');
+ form.appendChild(input1);
+
+ var input2 = d.createElement('input');
+ input2.setAttribute('type', 'text');
+ input2.setAttribute('name', 'inp2');
+ input2.setAttribute('value', 'value2');
+ s.appendChild(input2);
+
+ // submit the form
+ form.submit();
+
+ // set timeout to give the iframe time to load content
+ setTimeout(checkIframeContent, 2000);
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/html-elements-in-shadow-trees/inert-html-elements/test-001.html b/testing/web-platform/tests/shadow-dom/untriaged/html-elements-in-shadow-trees/inert-html-elements/test-001.html
new file mode 100644
index 000000000..33bdf69d1
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/html-elements-in-shadow-trees/inert-html-elements/test-001.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_08_01_01</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#inert-html-elements">
+<meta name="assert" content="HTML Elements in shadow trees: base element must behave as inert, or not part of the document tree">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+var A_08_01_01_T01 = async_test('A_08_01_01_T01', { timeout: 5000 });
+
+A_08_01_01_T01.checkIframeContent = A_08_01_01_T01.step_func(function () {
+ //remember value to check before cleaning the context (it'll destroy the iframe)
+ var valueToCheck = A_08_01_01_T01.iframe.contentWindow;
+ cleanContext(A_08_01_01_T01.ctx);
+
+ assert_equals(valueToCheck, null,
+ 'base html element ih a shadow tree must beahve like inert one');
+
+ A_08_01_01_T01.done();
+});
+
+
+A_08_01_01_T01.step(function () {
+
+ A_08_01_01_T01.ctx = newContext();
+ var d = newRenderedHTMLDocument(A_08_01_01_T01.ctx);
+
+ //create iframe
+ var iframe = document.createElement('iframe');
+
+ iframe.src = '../../resources/blank.html';
+ iframe.setAttribute('name', 'targetIframe');
+ d.body.appendChild(iframe);
+
+ A_08_01_01_T01.iframe = iframe;
+
+ // create a link
+ var link = d.createElement('a');
+ link.setAttribute('href', '../../resources/bobs_page.html');
+ link.innerHTML = 'the link';
+ d.body.appendChild(link);
+
+ //create Shadow root
+ var root = d.createElement('div');
+ d.body.appendChild(root);
+ var s = root.attachShadow({mode: 'open'});
+
+ // create base element, set iframe as a target
+ var base = d.createElement('base');
+ base.setAttribute('target', 'targetIframe');
+ s.appendChild(base);
+
+ //click the link
+ link.click();
+
+ //Expected: base should be inert therefore document d
+ // should be reloaded, so iframe context shouldn't be affected
+
+ // set timeout to give the iframe time to load content
+ setTimeout('A_08_01_01_T01.checkIframeContent()', 2000);
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/html-elements-in-shadow-trees/inert-html-elements/test-002.html b/testing/web-platform/tests/shadow-dom/untriaged/html-elements-in-shadow-trees/inert-html-elements/test-002.html
new file mode 100644
index 000000000..2263cd612
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/html-elements-in-shadow-trees/inert-html-elements/test-002.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_08_01_02</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#inert-html-elements">
+<meta name="assert" content="HTML Elements in shadow trees: link element must behave as inert not as part of the document tree">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+<script src="../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ var link = d.createElement('link');
+ link.setAttribute('rel', 'stylesheet');
+
+ //create Shadow root
+ var root = d.createElement('div');
+ d.body.appendChild(root);
+ var s = root.attachShadow({mode: 'open'});
+
+ s.appendChild(link);
+
+ assert_equals(d.styleSheets.length, 0, 'link element must behave as inert not as part of the document tree');
+
+
+}), 'A_08_01_02_T01');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/resources/blank.html b/testing/web-platform/tests/shadow-dom/untriaged/resources/blank.html
new file mode 100644
index 000000000..5469aa6d0
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/resources/blank.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<html>
+<head></head>
+<body></body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/resources/bobs_page.html b/testing/web-platform/tests/shadow-dom/untriaged/resources/bobs_page.html
new file mode 100644
index 000000000..92dfb0d3c
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/resources/bobs_page.html
@@ -0,0 +1,35 @@
+<html>
+<head>
+</head>
+<body>
+ <ul class='stories'>
+ <li id='li1'><a href='#1'>Link1</a></li>
+ <li id='li2' title="li2"><a href='#2'>Link 2</a></li>
+ <li id='li3' class='shadow'><a href='#3'>Link 3 Shadow</a></li>
+ <li id='li4' class='shadow2'><a href='#4'>Link 4 Shadow 2</a></li>
+ <li id='li5'><a id="a5" class="shadow" href='#5'>Link 5</a></li>
+ <li id='li6' class='shadow'><a href='#5'>Link 6 Shadow</a></li>
+ </ul>
+ <div id="divid" class='breaking'>
+ <span id='spandex'>Some text</span>
+ <ul id="ul2">
+ <li id='li11'>Item 11</li>
+ <li id='li12'>Item 12</li>
+ <li id='li13' class='shadow'>Item 13 Shadow</li>
+ <li id='li14' class='shadow2'>Item 14 Shadow 2</li>
+ <li id='li15'>Item 15</li>
+ <li id='li16' class='shadow'>Item 16 Shadow</li>
+ </ul>
+ </div>
+ <div id="links-wrapper">
+ <a href='#10' id='link10'>Link 10</a>
+ <a href='#11' id='link11'>Link 11</a>
+ </div>
+ <div id="inputs-wrapper">
+ <input type='text' id='inp1' disabled/>
+ <input type='text' id='inp2'/>
+ <input type='checkbox' id='chb1' checked>
+ <input type='checkbox' id='chb2'>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/nested-shadow-trees/nested_tree_reftest-ref.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/nested-shadow-trees/nested_tree_reftest-ref.html
new file mode 100644
index 000000000..3050cefe9
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/nested-shadow-trees/nested_tree_reftest-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" >
+ <title>Shadow DOM Test Ref file - Tests nested shadow tree.</title>
+ <link rel="author" title="shingo.miyazawa" href="mailto:kumatronik@gmail.com" >
+ <script src="../../../../html/resources/common.js"></script>
+ <meta name="assert" content="nested shadow tree style is valid." >
+ <style>
+ #host {
+ width: 100px;
+ height: 100px;
+ background-color: red;
+ }
+ </style>
+ </head>
+ <body>
+ <p>The test passes if there is a green square. Test failed if there is a red square.</p>
+ <div id='host'>
+ <div id="sub" style="width: 100%;height:100%;">
+ <div style="width:100%; height:100%;background-color: green;"></div>
+ </div>
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/nested-shadow-trees/nested_tree_reftest.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/nested-shadow-trees/nested_tree_reftest.html
new file mode 100644
index 000000000..8d02227fc
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/nested-shadow-trees/nested_tree_reftest.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" >
+ <title>Shadow DOM Test - Tests nested shadow tree.</title>
+ <link rel="match" href="nested_tree_reftest-ref.html" >
+ <link rel="author" title="shingo.miyazawa" href="mailto:kumatronik@gmail.com" >
+ <link rel="help" href="https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#nested-shadow-trees" >
+ <script src="../../../../html/resources/common.js"></script>
+ <meta name="assert" content="nested shadow tree style is valid." >
+ <style>
+ #host {
+ width: 100px;
+ height: 100px;
+ background-color: red;
+ }
+ </style>
+ </head>
+ <body>
+ <p>The test passes if there is a green square. Test failed if there is a red square.</p>
+ <div id='host'>
+ </div>
+ <script>
+ var shadowRoot = document.getElementById('host').attachShadow({mode: 'open'});
+ shadowRoot.innerHTML = '<div id="sub" style="width: 100%;height:100%;"></div>';
+ var nestedRoot = shadowRoot.getElementById('sub').attachShadow({mode: 'open'});
+ nestedRoot.innerHTML = '<div style="width:100%; height:100%;background-color: green;"></div>';
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/reprojection/reprojection-001-ref.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/reprojection/reprojection-001-ref.html
new file mode 100644
index 000000000..98c7a609c
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/reprojection/reprojection-001-ref.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<meta charset="utf-8">
+<title>Shadow DOM Test: Basic reprojection (reference)</title>
+<link rel="author" title="Anna Ogawa" href="mailto:anna.ogawa.0219@gmail.com">
+<link rel="author" title="Hayato Ito" href="mailto:hayato@google.com">
+<style>
+.pass { color: green; }
+</style>
+</head>
+<body>
+<p>You should see green text saying "Apple" and "Orange" below.</p>
+<div id="host">
+ <div id="host2">
+ <div>Hello a Shadow Root2.</div>
+ <div>
+ Hello a Shadow Root.
+ <div class="pass">Apple.</div>
+ <div class="pass">Orange.</div>
+ <div>Banana.</div>
+ </div>
+ </div>
+</div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/reprojection/reprojection-001.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/reprojection/reprojection-001.html
new file mode 100644
index 000000000..8bd2bb6f6
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/reprojection/reprojection-001.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<meta charset="utf-8">
+<title>Shadow DOM Test - Tests a reprojection.</title>
+<link rel="match" href="reprojection-001-ref.html">
+<link rel="author" title="Anna Ogawa" href="mailto:anna.ogawa.0219@gmail.com">
+<link rel="author" title="Hayato Ito" href="mailto:hayato@google.com">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#reprojection">
+<meta name="assert" content="a node is distributed into more than one insertion point.">
+<script src="../../../../html/resources/common.js"></script>
+<style>
+.pass { color: green; }
+</style>
+</head>
+<body>
+<p>You should see green text saying "Apple" and "Orange" below.</p>
+<div id="host">
+ <div class="pass">Apple.</div>
+ <div class="pass">Orange.</div>
+</div>
+<script>
+ var shadowRoot = host.attachShadow({mode: 'open'});
+ shadowRoot.innerHTML = '<div id="host2">Hello a Shadow Root.<slot></slot><div>Banana.</div></div>';
+ var host2 = shadowRoot.getElementById("host2");
+ var shadowRoot2 = host2.attachShadow({mode: 'open'});
+ shadowRoot2.innerHTML = '<div>Hello a Shadow Root2.</div><div><slot></slot></div>';
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/shadow-root-001-ref.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/shadow-root-001-ref.html
new file mode 100644
index 000000000..d80fcccbf
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/shadow-root-001-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: Basic shadow root (reference)</title>
+<link rel="author" title="Hayato Ito" href="mailto:hayato@google.com">
+<link rel="author" title="Yuta Kitamura" href="mailto:yutak@google.com">
+<style>
+p { color: black; }
+div { color: green; }
+</style>
+</head>
+<body>
+<p>You should see green text saying "PASS" below.</p>
+<div>PASS</div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/shadow-root-001.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/shadow-root-001.html
new file mode 100644
index 000000000..67843b067
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/shadow-root-001.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: Basic shadow root</title>
+<link rel="match" href="shadow-root-001-ref.html">
+<link rel="author" title="Hayato Ito" href="mailto:hayato@google.com">
+<link rel="author" title="Yuta Kitamura" href="mailto:yutak@google.com">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#shadow-trees">
+<meta name="assert" content="When a shadow root is attached, the shadow tree is rendered.">
+<script src="../../../html/resources/common.js"></script>
+<style>
+p { color: black; }
+* { color: red; }
+</style>
+</head>
+<body>
+<p>You should see green text saying "PASS" below.</p>
+<div id="host">FAIL</div>
+<script>
+var shadowRoot = window.host.attachShadow({mode: 'open'});
+shadowRoot.innerHTML =
+ '<style>#pass { color: green; }</style>\n' +
+ '<div id="pass">PASS</div>';
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/shadow-root-002-ref.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/shadow-root-002-ref.html
new file mode 100644
index 000000000..77b472d78
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/shadow-root-002-ref.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: Basic distribution (reference)</title>
+<link rel="author" title="Anna Ogawa" href="mailto:anna.ogawa.0219@gmail.com">
+<link rel="author" title="Yuta Kitamura" href="mailto:yutak@google.com">
+<style>
+p { color: black; }
+div { color: green; }
+</style>
+</head>
+<body>
+<p>
+You should see four lines of green text "A", "B", "C" and "D" below,
+in this order.
+</p>
+<div>A</div>
+<div>B</div>
+<div>C</div>
+<div>D</div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/shadow-root-002.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/shadow-root-002.html
new file mode 100644
index 000000000..24d5d016b
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/shadow-root-002.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<meta charset="utf-8">
+<title>Shadow DOM Test: Basic distribution</title>
+<link rel="match" href="shadow-root-002-ref.html">
+<link rel="author" title="Anna Ogawa" href="mailto:anna.ogawa.0219@gmail.com">
+<link rel="author" title="Yuta Kitamura" href="mailto:yutak@google.com">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#shadow-trees">
+<meta name="assert" content="On distribution, content element is replaced with the shadow host's children.">
+<script src="../../../html/resources/common.js"></script>
+<style>
+p { color: black; }
+.pass { color: green; }
+* { color: red; }
+</style>
+</head>
+<body>
+<p>
+You should see four lines of green text "A", "B", "C" and "D" below,
+in this order.
+</p>
+<div id="host">
+<div class="pass">B</div>
+<div class="pass">C</div>
+</div>
+<script>
+var shadowRoot = window.host.attachShadow({mode: 'open'});
+
+shadowRoot.innerHTML =
+ '<style>\n' +
+ '.shadow-pass { color: green; }\n' +
+ '* { color: red; }\n' +
+ '</style>' +
+ '<div class="shadow-pass">A</div>\n' +
+ '<slot>FAIL</slot>' +
+ '<div class="shadow-pass">D</div>';
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/text-decoration-001-ref.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/text-decoration-001-ref.html
new file mode 100644
index 000000000..8c10d2515
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/text-decoration-001-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Shadow DOM Test</title>
+ <link rel="author" title="Masaya Iseki" href="mailto:iseki.m.aa@gmail.com">
+ </head>
+ <body>
+ <span>
+ if NOT underlined, it is success.
+ </span>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/text-decoration-001.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/text-decoration-001.html
new file mode 100644
index 000000000..d8def126d
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/text-decoration-001.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" >
+ <title>Text Decoration Under Line Test</title>
+ <link rel="match" href="text-decoration-001-ref.html">
+ <link rel="author" title="Masaya Iseki" href="mailto:iseki.m.aa@gmail.com">
+ <link rel="help" href="https://www.w3.org/TR/shadow-dom/#text-decoration-property">
+ <meta name="assert" content="When shadow host has text-decoration, shadow tree is not affected.">
+ </head>
+ <body>
+ <span id="parent" style="text-decoration: underline">
+ </span>
+ <script>
+ var parent = document.getElementById('parent');
+ var shadow = parent.attachShadow({mode: 'open'});
+ var child = document.createElement('span');
+ child.textContent = "if NOT underlined, it is success.";
+ shadow.appendChild(child);
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/dom-tree-accessors-001.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/dom-tree-accessors-001.html
new file mode 100644
index 000000000..71421481e
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/dom-tree-accessors-001.html
@@ -0,0 +1,227 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: Upper-boundary encapsulation: document's DOM tree accessors</title>
+<link rel="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="author" title="Mikhail Fursov" href="mailto:mfursov@unipro.ru">
+<link rel="author" title="Yuta Kitamura" href="mailto:yutak@google.com">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#upper-boundary-encapsulation">
+<meta name="assert" content="Upper-boundary encapsulation: The shadow nodes and named shadow elements are not accessible using shadow host's document DOM tree accessors.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+// A document's "DOM tree accessors" include:
+// (document.)head, title, body, images, embeds, plugins, links, forms,
+// scripts, getElementsByName(), cssElementMap, and currentScript
+//
+// Of these, it is unclear how document.cssElementMap can be tested.
+// Except for it, there is a test corresponding to each accessor.
+//
+// Additionally, there are obsolete accessors
+// <http://www.whatwg.org/specs/web-apps/current-work/multipage/obsolete.html#other-elements,-attributes-and-apis>:
+// (document.)anchors, applets, and all.
+//
+// and some accessors defined in the DOM specification (formerly known as
+// "DOM Core") <http://dom.spec.whatwg.org/#interface-document>:
+// (document.)documentElement, getElementsByTagName(),
+// getElementsByTagNameNS(), getElementsByClassName(), and getElementById().
+//
+// As it seems reasonable to have tests for these accessors, this file also
+// includes tests for them, except for document.documentElement which is
+// unclear whether we can test; the distribution process of Shadow DOM does not
+// alter the host element, so the document element (e.g. <html>) cannot be
+// replaced with an element in a shadow tree.
+
+// ----------------------------------------------------------------------------
+// Constants and utility functions
+
+// Place the same HTML content into both the host document and the shadow root.
+// To differentiate these two, a class name is assigned to every element by
+// populateTestContentToHostDocument() and populateTestContentToShadowRoot().
+var HTML_CONTENT = [
+ '<head>',
+ '<title></title>',
+ '<link rel="help" href="#">',
+ '</head>',
+ '<body>',
+ '<p></p>',
+ '<a name="test-name"></a>',
+ '<a href="#"></a>',
+ '<area href="#">',
+ '<img src="#" alt="">',
+ '<embed></embed>',
+ '<form></form>',
+ '<script><' + '/script>',
+ '</body>'
+].join('\n');
+
+function addClassNameToAllElements(document, root, className) {
+ var nodeIterator = document.createNodeIterator(
+ root, NodeFilter.SHOW_ELEMENT, null);
+ var node;
+ while (node = nodeIterator.nextNode())
+ node.className = className;
+}
+
+function populateTestContentToHostDocument(document) {
+ document.documentElement.innerHTML = HTML_CONTENT;
+ addClassNameToAllElements(document, document.documentElement, 'host');
+}
+
+function populateTestContentToShadowRoot(shadowRoot) {
+ shadowRoot.innerHTML = HTML_CONTENT;
+ addClassNameToAllElements(shadowRoot.ownerDocument, shadowRoot, 'shadow');
+}
+
+function createDocumentForTesting() {
+ var doc = document.implementation.createHTMLDocument('');
+ populateTestContentToHostDocument(doc);
+ var shadowRoot = doc.body.attachShadow({mode: 'open'});
+ populateTestContentToShadowRoot(shadowRoot);
+ return doc;
+}
+
+// Make sure the given HTMLCollection contains at least one elements and
+// all elements have the class named "host". This function works well with
+// HTMLCollection, HTMLAllCollection, and NodeList consisting of elements.
+function assert_collection(collection) {
+ assert_true(collection.length > 0);
+ Array.prototype.forEach.call(collection, function (element) {
+ assert_equals(element.className, 'host');
+ });
+}
+
+// ----------------------------------------------------------------------------
+// Tests for DOM tree accessors defined in HTML specification
+
+test(function () {
+ var doc = createDocumentForTesting();
+ assert_equals(doc.head.className, 'host');
+ assert_equals(doc.body.className, 'host');
+},
+ '<head> and <body> in a shadow tree should not be accessible from ' +
+ 'owner document\'s "head" and "body" properties, respectively.'
+);
+
+test(function () {
+ var doc = document.implementation.createHTMLDocument('');
+ populateTestContentToHostDocument(doc);
+
+ // Note: this test is originally written to replace document.documentElement
+ // with shadow contents, but among Shadow DOM V1 allowed elements body is the
+ // most approximate to it, though some test may make lesser sense.
+ var shadowRoot = doc.body.attachShadow({mode: 'open'});
+ populateTestContentToShadowRoot(shadowRoot);
+
+ // Replace the content of <title> to distinguish elements in a host
+ // document and a shadow tree.
+ doc.getElementsByTagName('title')[0].textContent = 'Title of host document';
+ shadowRoot.querySelector('title').textContent =
+ 'Title of shadow tree';
+
+ assert_equals(doc.title, 'Title of host document');
+},
+ 'The content of title element in a shadow tree should not be accessible ' +
+ 'from owner document\'s "title" attribute.'
+);
+
+function testHTMLCollection(accessor) {
+ var doc = createDocumentForTesting();
+ assert_collection(doc[accessor]);
+}
+
+generate_tests(
+ testHTMLCollection,
+ ['images', 'embeds', 'plugins', 'links', 'forms', 'scripts'].map(
+ function (accessor) {
+ return [
+ 'Elements in a shadow tree should not be accessible from ' +
+ 'owner document\'s "' + accessor + '" attribute.',
+ accessor
+ ];
+ }));
+
+test(function () {
+ var doc = createDocumentForTesting();
+ assert_collection(doc.getElementsByName('test-name'));
+},
+ 'Elements in a shadow tree should not be accessible from owner ' +
+ 'document\'s getElementsByName() method.'
+);
+
+// ----------------------------------------------------------------------------
+// Tests for obsolete accessors
+
+generate_tests(
+ testHTMLCollection,
+ ['anchors', 'all'].map(
+ function (accessor) {
+ return [
+ 'Elements in a shadow tree should not be accessible from ' +
+ 'owner document\'s "' + accessor + '" attribute.',
+ accessor
+ ];
+ }));
+
+// ----------------------------------------------------------------------------
+// Tests for accessors defined in DOM specification
+
+test(function () {
+ var doc = createDocumentForTesting();
+ assert_collection(doc.getElementsByTagName('p'));
+},
+ 'Elements in a shadow tree should not be accessible from owner ' +
+ 'document\'s getElementsByTagName() method.'
+);
+
+test(function () {
+ // Create a XML document.
+ var namespace = 'http://www.w3.org/1999/xhtml';
+ var doc = document.implementation.createDocument(namespace, 'html');
+ doc.documentElement.appendChild(doc.createElementNS(namespace, 'head'));
+ var body = doc.createElementNS(namespace, 'body');
+ var pHost = doc.createElementNS(namespace, 'p');
+ pHost.className = "host";
+ body.appendChild(pHost);
+ doc.documentElement.appendChild(body);
+
+ var shadowRoot = body.attachShadow({mode: 'open'});
+ var pShadow = doc.createElementNS(namespace, 'p');
+ pShadow.className = "shadow";
+ shadowRoot.appendChild(pShadow);
+
+ assert_collection(doc.getElementsByTagNameNS(namespace, 'p'));
+},
+ 'Elements in a shadow tree should not be accessible from owner ' +
+ 'document\'s getElementsByTagNameNS() method.'
+);
+
+test(function () {
+ var doc = document.implementation.createHTMLDocument('');
+ populateTestContentToHostDocument(doc);
+ var shadowRoot = doc.body.attachShadow({mode: 'open'});
+ populateTestContentToShadowRoot(shadowRoot);
+
+ shadowRoot.querySelectorAll('p')[0].id = 'test-id';
+ assert_equals(doc.getElementById('test-id'), null);
+},
+ 'Elements in a shadow tree should not be accessible from owner ' +
+ 'document\'s getElementById() method.'
+);
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/dom-tree-accessors-002.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/dom-tree-accessors-002.html
new file mode 100644
index 000000000..7a8f9f3d2
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/dom-tree-accessors-002.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: Upper-boundary encapsulation: shadow root's DOM tree accessors</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="author" title="Mikhail Fursov" href="mailto:mfursov@unipro.ru">
+<link rel="author" title="Yuta Kitamura" href="mailto:yutak@google.com">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#upper-boundary-encapsulation">
+<meta name="assert" content="Upper-boundary encapsulation: The nodes are accessible using shadow root's DOM tree accessor methods.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+function assert_singleton_node_list(nodeList, expectedNode) {
+ assert_equals(nodeList.length, 1);
+ assert_equals(nodeList[0], expectedNode);
+}
+
+test(function () {
+ var doc = document.implementation.createHTMLDocument('Test');
+ var shadowRoot = doc.body.attachShadow({mode: 'open'});
+ var image = doc.createElement('img');
+ shadowRoot.appendChild(image);
+
+ assert_singleton_node_list(shadowRoot.querySelectorAll('img'), image);
+},
+ 'Elements in a shadow tree should be accessible via shadow root\'s ' +
+ 'querySelectorAll() DOM tree accessor.'
+);
+
+test(function () {
+ var doc = document.implementation.createHTMLDocument('Test');
+ var shadowRoot = doc.body.attachShadow({mode: 'open'});
+ var div = doc.createElement('div');
+ div.className = 'div-class';
+ shadowRoot.appendChild(div);
+
+ assert_singleton_node_list(
+ shadowRoot.querySelectorAll('.div-class'), div);
+},
+ 'Elements with a specific class in a shadow tree should be accessible via' +
+ 'shadow root\'s querySelectorAll() DOM tree accessor.'
+);
+
+test(function () {
+ var doc = document.implementation.createHTMLDocument('Test');
+ var shadowRoot = doc.body.attachShadow({mode: 'open'});
+ var div = doc.createElement('div');
+ div.id = 'div-id';
+ shadowRoot.appendChild(div);
+
+ assert_equals(shadowRoot.getElementById('div-id'), div);
+},
+ 'Elements in a shadow tree should be accessible via shadow root\'s ' +
+ 'getElementById() DOM tree accessor.'
+);
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/ownerdocument-001.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/ownerdocument-001.html
new file mode 100644
index 000000000..3a184f46c
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/ownerdocument-001.html
@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: Upper-boundary encapsuration on ownerDocument: basic tests</title>
+<link rel="author" title="Aleksei Yu. Semenov" href="mailto:sgrekhov@unipro.ru">
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="author" title="Mikhail Fursov" href="mailto:mfursov@unipro.ru">
+<link rel="author" title="Yuta Kitamura" href="mailto:yutak@google.com">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#upper-boundary-encapsulation">
+<meta name="assert" content="Upper-boundary encapsulation: The ownerDocument property of all nodes in shadow tree refers to the document of the shadow host.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(function () {
+ var doc = document.implementation.createHTMLDocument('Test');
+ doc.body.innerHTML = '<div>A<div>B</div>C<div><span>D</span></div>E</div>';
+ var nodeIterator = doc.createNodeIterator(doc.body,
+ NodeFilter.SHOW_ELEMENT, null);
+ var node;
+ while (node = nodeIterator.nextNode()) {
+ var shadowRoot = node.attachShadow({mode: 'open'});
+ assert_equals(shadowRoot.ownerDocument, doc);
+ }
+}, 'ownerDocument property of a shadow root should be the document of the ' +
+ 'shadow host, regardless of the location of the shadow host.');
+
+test(function () {
+ var MAX_DEPTH = 16;
+ var doc = document.implementation.createHTMLDocument('Test');
+ var tail = doc.body;
+ for (var depth = 1; depth <= MAX_DEPTH; ++depth) {
+ var div = doc.createElement('div');
+ div.id = 'depth-' + depth;
+ tail.appendChild(div);
+ tail = div;
+ }
+
+ for (var depth = 1; depth <= MAX_DEPTH; ++depth) {
+ var host = doc.getElementById('depth-' + depth);
+ var shadowRoot = host.attachShadow({mode: 'open'});
+ assert_equals(shadowRoot.ownerDocument, doc,
+ 'ownerDocument mismatch for #depth-' + depth);
+ }
+}, 'ownerDocument property of elements in a shadow tree should match ' +
+ 'the document of the shadow host, regardless of the element\'s location ' +
+ 'in a shadow tree.');
+
+test(function () {
+ var doc = document.implementation.createHTMLDocument('Test');
+ var shadowRoot = doc.body.attachShadow({mode: 'open'});
+ var div = doc.createElement('div');
+ shadowRoot.appendChild(div);
+ assert_equals(div.ownerDocument, doc);
+}, 'Elements added to a shadow tree should automatically get a valid ' +
+ 'ownerDocument.');
+
+test(function () {
+ var doc1 = document.implementation.createHTMLDocument('Test 1');
+ var doc2 = document.implementation.createHTMLDocument('Test 2');
+ var shadowRoot = doc1.body.attachShadow({mode: 'open'});
+ var div = doc2.createElement('div');
+ shadowRoot.appendChild(div);
+ assert_equals(div.ownerDocument, doc1);
+}, 'ownerDocument property of an element in a shadow tree should be the ' +
+ 'document of the shadow host, even if the host element is created from ' +
+ 'another document.');
+
+test(function () {
+ var doc1 = document.implementation.createHTMLDocument('Test 1');
+ var doc2 = document.implementation.createHTMLDocument('Test 2');
+ var shadowRoot = doc1.body.attachShadow({mode: 'open'});
+ doc2.body.innerHTML =
+ '<div id="root">A<div>B</div>C<div><span>D</span></div>E</div>';
+ shadowRoot.appendChild(doc2.getElementById('root'));
+ var nodeIterator = doc1.createNodeIterator(
+ shadowRoot.getElementById('root'), 0xFFFFFFFF, null);
+ var node;
+ while (node = nodeIterator.nextNode()) {
+ assert_equals(node.ownerDocument, doc1);
+ }
+}, 'All children nodes of a shadow root get a valid ownerDocument when ' +
+ 'added to a shadow tree.');
+
+test(function () {
+ var doc1 = document.implementation.createHTMLDocument('Test 1');
+ var doc2 = document.implementation.createHTMLDocument('Test 2');
+ var shadowRoot = doc1.body.attachShadow({mode: 'open'});
+ doc2.body.innerHTML = '<div id="parent"><div id="child"></div></div>';
+ shadowRoot.appendChild(doc2.getElementById('child'));
+ assert_equals(doc2.getElementById('parent').ownerDocument, doc2);
+}, 'ownerDocument property of a node should remain the same, even if its ' +
+ 'child is adopted into a shadow tree.');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/ownerdocument-002.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/ownerdocument-002.html
new file mode 100644
index 000000000..0b4de7f7f
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/ownerdocument-002.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: Upper-boundary encapsuration on ownerDocument: with all HTML5 elements</title>
+<link rel="author" title="Aleksei Yu. Semenov" href="mailto:sgrekhov@unipro.ru">
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="author" title="Mikhail Fursov" href="mailto:mfursov@unipro.ru">
+<link rel="author" title="Yuta Kitamura" href="mailto:yutak@google.com">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#upper-boundary-encapsulation">
+<meta name="assert" content="Upper-boundary encapsulation: The ownerDocument property of all nodes in shadow tree refers to the document of the shadow host.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+<script src="../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+function testElement(elementName) {
+ var doc = document.implementation.createHTMLDocument('Test');
+ var element = doc.createElement(elementName);
+ doc.body.appendChild(element);
+ var shadowRoot = element.attachShadow({mode: 'open'});
+ ATTACHSHADOW_SAFELISTED_ELEMENTS.forEach(function (name) {
+ shadowRoot.appendChild(doc.createElement(name));
+ });
+
+ var iterator = doc.createNodeIterator(shadowRoot, 0xFFFFFFFF, null);
+ var node;
+ while (node = iterator.nextNode()) {
+ assert_equals(node.ownerDocument, doc);
+ }
+}
+
+var testParameters = ATTACHSHADOW_SAFELISTED_ELEMENTS.map(function (name) {
+ return [
+ 'ownerDocument property of any elements in a shadow tree should ' +
+ 'match the document of the shadow host, when the host is a "' +
+ name + '" element.',
+ name
+ ];
+});
+
+generate_tests(testElement, testParameters);
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/selectors-api-001.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/selectors-api-001.html
new file mode 100644
index 000000000..1ce5c65bd
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/selectors-api-001.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: Upper-boundary encapsulation: document's Selector APIs</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="author" title="Yuta Kitamura" href="mailto:yutak@google.com">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#upper-boundary-encapsulation">
+<meta name="assert" content="Upper-boundary encapsulation: Nodes in a shadow tree must not be accessible through selector APIs of owner document.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+// Return a document containing the structure below:
+//
+// <body> - - - - - {shadow-root}
+// | |
+// | +-- <p class="test-class" id="test-id">
+// |
+// +-- <p class="test-class" id="test-id">
+function createTestDocument() {
+ var doc = document.implementation.createHTMLDocument('Test');
+ var pHost = doc.createElement('p');
+ pHost.className = 'test-class';
+ pHost.id = 'test-id';
+ doc.body.appendChild(pHost);
+ var shadowRoot = doc.body.attachShadow({mode: 'open'});
+ var pShadow = doc.createElement('p');
+ pShadow.className = 'test-class';
+ pShadow.id = 'test-id';
+ shadowRoot.appendChild(pShadow);
+ return {
+ doc: doc,
+ pHost: pHost,
+ pShadow: pShadow
+ };
+}
+
+test(function () {
+ var documentObject = createTestDocument();
+ var doc = documentObject.doc;
+ var pHost = documentObject.pHost;
+ assert_equals(doc.querySelector('p'), pHost);
+ assert_equals(doc.querySelector('.test-class'), pHost);
+ assert_equals(doc.querySelector('#test-id'), pHost);
+},
+ 'Elements in a shadow tree should not be accessible from ' +
+ 'owner document\'s querySelector() method.'
+);
+
+function assert_singleton_node_list(nodeList, expectedNode) {
+ assert_equals(nodeList.length, 1);
+ assert_equals(nodeList[0], expectedNode);
+}
+
+test(function () {
+ var documentObject = createTestDocument();
+ var doc = documentObject.doc;
+ var pHost = documentObject.pHost;
+ assert_singleton_node_list(doc.querySelectorAll('p'), pHost);
+ assert_singleton_node_list(doc.querySelectorAll('.test-class'), pHost);
+ assert_singleton_node_list(doc.querySelectorAll('#test-id'), pHost);
+},
+ 'Elements in a shadow tree should not be accessible from ' +
+ 'owner document\'s querySelectorAll() method.'
+);
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/selectors-api-002.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/selectors-api-002.html
new file mode 100644
index 000000000..173728042
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/selectors-api-002.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: Upper-boundary encapsulation: shadow root's Selector APIs</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="author" title="Mikhail Fursov" href="mailto:mfursov@unipro.ru">
+<link rel="author" title="Yuta Kitamura" href="mailto:yutak@google.com">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#upper-boundary-encapsulation">
+<meta name="assert" content="Upper-boundary encapsulation: Nodes in a shadow tree must be accessible through selector APIs of the shadow root.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+// Return a document containing the structure below:
+//
+// <body> - - - - - {shadow-root}
+// | |
+// | +-- <p class="test-class" id="test-id">
+// |
+// +-- <p class="test-class" id="test-id">
+function createTestDocument() {
+ var doc = document.implementation.createHTMLDocument('Test');
+ var pHost = doc.createElement('p');
+ pHost.className = 'test-class';
+ pHost.id = 'test-id';
+ doc.body.appendChild(pHost);
+ var shadowRoot = doc.body.attachShadow({mode: 'open'});
+ var pShadow = doc.createElement('p');
+ pShadow.className = 'test-class';
+ pShadow.id = 'test-id';
+ shadowRoot.appendChild(pShadow);
+ return {
+ doc: doc,
+ shadowRoot: shadowRoot,
+ pHost: pHost,
+ pShadow: pShadow
+ };
+}
+
+test(function () {
+ var documentObject = createTestDocument();
+ var shadowRoot = documentObject.shadowRoot;
+ var pShadow = documentObject.pShadow;
+ assert_equals(shadowRoot.querySelector('p'), pShadow);
+ assert_equals(shadowRoot.querySelector('.test-class'), pShadow);
+ assert_equals(shadowRoot.querySelector('#test-id'), pShadow);
+},
+ 'Elements in a shadow tree should be accessible from ' +
+ 'shadow root\'s querySelector() method.'
+);
+
+function assert_singleton_node_list(nodeList, expectedNode) {
+ assert_equals(nodeList.length, 1);
+ assert_equals(nodeList[0], expectedNode);
+}
+
+test(function () {
+ var documentObject = createTestDocument();
+ var shadowRoot = documentObject.shadowRoot;
+ var pShadow = documentObject.pShadow;
+ assert_singleton_node_list(shadowRoot.querySelectorAll('p'), pShadow);
+ assert_singleton_node_list(shadowRoot.querySelectorAll('.test-class'),
+ pShadow);
+ assert_singleton_node_list(shadowRoot.querySelectorAll('#test-id'),
+ pShadow);
+},
+ 'Elements in a shadow tree should be accessible from ' +
+ 'shadow root\'s querySelectorAll() method.'
+);
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/shadow-root-001.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/shadow-root-001.html
new file mode 100644
index 000000000..8e40fb23e
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/shadow-root-001.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: Shadow root's parentNode() and parentElement()</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="author" title="Mikhail Fursov" href="mailto:mfursov@unipro.ru">
+<link rel="author" title="Yuta Kitamura" href="mailto:yutak@google.com">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#upper-boundary-encapsulation">
+<meta name="assert" content="Upper-boundary encapsulation: The parentNode and parentElement attributes of the shadow root object must always return null.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(function () {
+ var doc = document.implementation.createHTMLDocument('Test');
+ var shadowRoot = doc.body.attachShadow({mode: 'open'});
+ assert_equals(shadowRoot.parentNode, null);
+}, 'The parentNode attribute of a shadow root must always return null.');
+
+test(function () {
+ var doc = document.implementation.createHTMLDocument('Test');
+ var shadowRoot = doc.body.attachShadow({mode: 'open'});
+ assert_equals(shadowRoot.parentElement, null);
+}, 'The parentElement attribute of a shadow root must always return null.');
+
+test(function () {
+ var doc = document.implementation.createHTMLDocument('Test');
+ var outerShadowRoot = doc.body.attachShadow({mode: 'open'});
+ var div = doc.createElement('div');
+ outerShadowRoot.appendChild(div);
+ var innerShadowRoot = div.attachShadow({mode: 'open'});
+ assert_equals(innerShadowRoot.parentNode, null);
+},
+ 'The parentNode attribute of a shadow root must always return null, ' +
+ 'even if the shadow root is nested inside another shadow root.'
+);
+
+test(function () {
+ var doc = document.implementation.createHTMLDocument('Test');
+ var outerShadowRoot = doc.body.attachShadow({mode: 'open'});
+ var div = doc.createElement('div');
+ outerShadowRoot.appendChild(div);
+ var innerShadowRoot = div.attachShadow({mode: 'open'});
+ assert_equals(innerShadowRoot.parentElement, null);
+},
+ 'The parentElement attribute of a shadow root must always return null, ' +
+ 'even if the shadow root is nested inside another shadow root.'
+);
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-005.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-005.html
new file mode 100644
index 000000000..0cf978a26
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-005.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_04_01_05</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#upper-boundary-encapsulation">
+<meta name="assert" content="Upper-boundary encapsulation:The nodes with a unique id and named elements are not addressable from any attributes of elements in shadow host's document">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+// check label.for attribute
+test(function () {
+ var d = newHTMLDocument();
+ var div = d.createElement('div');
+ d.body.appendChild(div);
+ var s = div.attachShadow({mode: 'open'});
+
+ // node in shadow with id
+ var input = d.createElement('input');
+ input.setAttribute('type', 'text');
+ input.setAttribute('id', 'input_id');
+ d.body.appendChild(input);
+ s.appendChild(input);
+
+ // node in host with a reference to host element with id
+ var label = d.createElement('label');
+ label.setAttribute('for', 'input_id');
+ d.body.appendChild(label);
+
+ assert_equals(label.control, null, 'Elements in shadow DOM must not be accessible from ' +
+ 'owner\'s document label.for attribute');
+
+}, 'A_04_01_05_T01');
+
+// check form associated elements
+test(function () {
+
+ HTML5_FORM_ASSOCIATED_ELEMENTS.forEach(function (tagName) {
+ var d = newHTMLDocument();
+ var div = d.createElement('div');
+ d.body.appendChild(div);
+ var s = div.attachShadow({mode: 'open'});
+
+ var form = d.createElement('form');
+ form.setAttribute('id', 'form_id');
+ d.body.appendChild(form);
+
+ var el = d.createElement(tagName);
+ el.setAttribute('form', 'form_id');
+ d.body.appendChild(el);
+
+ s.appendChild(form);
+
+ assert_equals(el.form, null, 'Elements in shadow DOM must not be accessible from ' +
+ 'owner\'s document ' + tagName + '.form attribute');
+ });
+}, 'A_04_01_05_T02');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-007.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-007.html
new file mode 100644
index 000000000..77f100d63
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-007.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_04_01_07</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#upper-boundary-encapsulation">
+<meta name="assert" content="Upper-boundary encapsulation:The nodes with a unique id and named elements are addressable from any attributes of elements in the same shadow DOM subtree">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+// check for label.control
+test(function () {
+ var d = newHTMLDocument();
+ var div = d.createElement('div');
+ d.body.appendChild(div);
+ var s = div.attachShadow({mode: 'open'});
+
+ var input = d.createElement('input');
+ input.setAttribute('type', 'text');
+ input.setAttribute('id', 'input_id');
+ d.body.appendChild(input);
+
+ var label = d.createElement('label');
+ label.setAttribute('for', 'input_id');
+ s.appendChild(label);
+ s.appendChild(input);
+
+ assert_equals(label.control, input, 'Elements in shadow DOM must be accessible from ' +
+ 'shadow document label.for attribute');
+
+}, 'A_04_01_07_T01');
+
+// check for elem.form associated elements
+test(function () {
+
+ HTML5_FORM_ASSOCIATED_ELEMENTS.forEach(function (tagName) {
+ d = newHTMLDocument();
+
+ var form = d.createElement('form');
+ var el = d.createElement(tagName);
+
+ d.body.appendChild(form);
+ d.body.appendChild(el);
+
+ form.setAttribute('id', 'form_id');
+ el.setAttribute('form', 'form_id');
+
+ div = d.createElement('div');
+ d.body.appendChild(div);
+
+ var s = div.attachShadow({mode: 'open'});
+ s.appendChild(form);
+ s.appendChild(el);
+
+ assert_equals(el.form, form, 'Elements in shadow DOM must be accessible from ' +
+ 'shadow document ' + tagName + '.form attribute');
+ });
+}, 'A_04_01_07_T02');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-009.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-009.html
new file mode 100644
index 000000000..5aa6b9218
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-009.html
@@ -0,0 +1,244 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_04_01_09</title>
+<link rel="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="author" title="Mikhail Fursov" href="mailto:mfursov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#upper-boundary-encapsulation">
+<meta name="assert" content="Upper-boundary encapsulation: no nodes other than shadow root descendants are accessible with shadow root DOM tree accessor methods">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+var A_04_01_09 = new Object();
+
+A_04_01_09.setupBlock = function (ctx, prefix, root) {
+ // create <div id='prefix+_id1' class='cls'><p class='cls'><div id='prefix+_id2' class='cls'></div></p></div> like structure
+ // where <p> will be used as shadow host element
+
+ ctx[prefix + '_div1'] = ctx.d.createElement('div');
+ ctx[prefix + '_div1'].setAttribute('id', prefix + '_id1');
+ ctx[prefix + '_div1'].setAttribute('class', 'cls');
+
+ ctx[prefix + '_p1'] = ctx.d.createElement('p');
+ ctx[prefix + '_p1'].setAttribute('class', 'cls');
+ ctx[prefix + '_p1'].setAttribute('test', 'A_04_01_09');
+
+ ctx[prefix + '_div2'] = ctx.d.createElement('div');
+ ctx[prefix + '_div2'].setAttribute('id', prefix + '_id2');
+ ctx[prefix + '_div2'].setAttribute('class', 'cls');
+ ctx[prefix + '_div2'].setAttribute('test', 'A_04_01_09');
+
+ root.appendChild(ctx[prefix + '_div1']);
+ ctx[prefix + '_div1'].appendChild(ctx[prefix + '_p1']);
+ ctx[prefix + '_p1'].appendChild(ctx[prefix + '_div2']);
+};
+
+A_04_01_09.setup = function () {
+ var ctx = {};
+
+ ctx.d = newHTMLDocument();
+ A_04_01_09.setupBlock(ctx, 'd', ctx.d.body);
+
+ ctx.s1 = ctx.d_p1.attachShadow({mode: 'open'});
+ A_04_01_09.setupBlock(ctx, 's1', ctx.s1);
+
+ ctx.s2 = ctx.s1_p1.attachShadow({mode: 'open'});
+ A_04_01_09.setupBlock(ctx, 's2', ctx.s2);
+
+ assert_true(ctx.d_div1 != null, 'setup:d_div1');
+ assert_true(ctx.d_div2 != null, 'setup:d_div2');
+ assert_true(ctx.s1_div1 != null, 'setup: s1_div1');
+ assert_true(ctx.s1_div2 != null, 'setup: s1_div2');
+ assert_true(ctx.s2_div1 != null, 'setup: s2_div1');
+ assert_true(ctx.s2_div2 != null, 'setup: s2_div2');
+
+ return ctx;
+};
+
+//check querySelectorAll
+test(function () {
+ var ctx = A_04_01_09.setup();
+
+ assert_nodelist_contents_equal_noorder(
+ ctx.s1.querySelectorAll('div'), [ctx.s1_div1, ctx.s1_div2],
+ 'nodes, other than shadow root descendants, should not be accessible with ' +
+ 'ShadowRoot.getElementsByTagName (s1)');
+
+ assert_nodelist_contents_equal_noorder(
+ ctx.s2.querySelectorAll('div'), [ctx.s2_div1, ctx.s2_div2],
+ 'nodes, other than shadow root descendants, should not be accessible with ' +
+ 'ShadowRoot.getElementsByTagName (s2)');
+
+}, 'A_04_01_09_T01');
+
+//check querySelectorAll for class
+test(function () {
+ var ctx = A_04_01_09.setup();
+
+ assert_nodelist_contents_equal_noorder(
+ ctx.s1.querySelectorAll('.cls'), [ctx.s1_div1, ctx.s1_p1, ctx.s1_div2],
+ 'nodes, other than shadow root descendants, should not be accessible with ' +
+ 'ShadowRoot.getElementsByClassName (s1)');
+
+ assert_nodelist_contents_equal_noorder(
+ ctx.s2.querySelectorAll('.cls'), [ctx.s2_div1, ctx.s2_p1, ctx.s2_div2],
+ 'nodes, other than shadow root descendants, should not be accessible with ' +
+ 'ShadowRoot.getElementsByClassName (s2)');
+
+}, 'A_04_01_09_T03');
+
+// check querySelector for id
+test(function () {
+ var ctx = A_04_01_09.setup();
+
+ assert_equals(ctx.d.querySelector('#s1_id1'), null, 'Expected no access to s1_div1 from d.querySelector()');
+ assert_equals(ctx.d.querySelector('#s1_id2'), null, 'Expected no access to s1_div2 from d.querySelector()');
+ assert_equals(ctx.d.querySelector('#s2_id1'), null, 'Expected no access to s2_div1 from d.querySelector()');
+ assert_equals(ctx.d.querySelector('#s2_id2'), null, 'Expected no access to s2_div1 from d.querySelector()');
+
+ assert_equals(ctx.s1.querySelector('#d_id1'), null, 'Expected no access to d_div1 from s1.querySelector()');
+ assert_equals(ctx.s1.querySelector('#d_id2'), null, 'Expected no access to d_div2 from s1.querySelector()');
+ assert_equals(ctx.s2.querySelector('#d_id1'), null, 'Expected no access to d_div1 from s2.querySelector()');
+ assert_equals(ctx.s2.querySelector('#d_id2'), null, 'Expected no access to d_div1 from s2.querySelector()');
+
+ assert_equals(ctx.d.querySelector('#d_id1'), ctx.d_div1, 'Expected access to d_div1 form d.querySelector()');
+ assert_equals(ctx.d.querySelector('#d_id2'), ctx.d_div2, 'Expected access to d_div2 form d.querySelector()');
+ assert_equals(ctx.s1.querySelector('#s1_id1'), ctx.s1_div1, 'Expected access to s1_div1 form s1.querySelector()');
+ assert_equals(ctx.s1.querySelector('#s1_id2'), ctx.s1_div2, 'Expected access to s1_div2 form s1.querySelector()');
+ assert_equals(ctx.s2.querySelector('#s2_id1'), ctx.s2_div1, 'Expected access to s2_div1 form s2.querySelector()');
+ assert_equals(ctx.s2.querySelector('#s2_id2'), ctx.s2_div2, 'Expected access to s2_div2 form s2.querySelector()');
+
+ assert_equals(ctx.s1.querySelector('#s2_id1'), null, 'Expected no access to s2_div1 form s1.querySelector()');
+ assert_equals(ctx.s1.querySelector('#s2_id2'), null, 'Expected no access to s2_div2 form s1.querySelector()');
+ assert_equals(ctx.s2.querySelector('#s1_id1'), null, 'Expected no access to s1_div1 form s2.querySelector()');
+ assert_equals(ctx.s2.querySelector('#s1_id2'), null, 'Expected no access to s1_div2 form s2.querySelector()');
+
+}, 'A_04_01_09_T05');
+
+
+//check querySelector for element
+test(function () {
+ var ctx = A_04_01_09.setup();
+
+ assert_equals(ctx.d.querySelector('p'), ctx.d_p1, 'Expected access to d_p1 from d.querySelector()');
+ assert_equals(ctx.s1.querySelector('p'), ctx.s1_p1, 'Expected access to s1_p1 from s1.querySelector()');
+ assert_equals(ctx.s2.querySelector('p'), ctx.s2_p1, 'Expected access to s2_p1 from s2.querySelector()');
+
+}, 'A_04_01_09_T06');
+
+// check querySelectorAll for element
+test(function () {
+ var ctx = A_04_01_09.setup();
+
+ assert_nodelist_contents_equal_noorder(ctx.d.querySelectorAll('p'), [ctx.d_p1], 'Expected access to d_p1 from d.querySelectorAll()');
+ assert_nodelist_contents_equal_noorder(ctx.s1.querySelectorAll('p'), [ctx.s1_p1], 'Expected access to s1_p1 s1.querySelectorAll');
+ assert_nodelist_contents_equal_noorder(ctx.s2.querySelectorAll('p'), [ctx.s2_p1], 'Expected access to s2_p1 from s2.querySelectorAll');
+
+}, 'A_04_01_09_T07');
+
+// check querySelectorAll for class
+test(function () {
+ var ctx = A_04_01_09.setup();
+
+ assert_nodelist_contents_equal_noorder(ctx.d.querySelectorAll('.cls'), [ctx.d_div1, ctx.d_p1, ctx.d_div2], 'd.querySelectorAll() return wrong result');
+ assert_nodelist_contents_equal_noorder(ctx.s1.querySelectorAll('.cls'), [ctx.s1_div1, ctx.s1_p1, ctx.s1_div2], 's1.querySelectorAll() return wrong result');
+ assert_nodelist_contents_equal_noorder(ctx.s2.querySelectorAll('.cls'), [ctx.s2_div1, ctx.s2_p1, ctx.s2_div2], 's2.querySelectorAll() return wrong result');
+
+}, 'A_04_01_09_T08');
+
+//check querySelectorAll with whildcat
+test(function () {
+ var ctx = A_04_01_09.setup();
+
+ //assert_nodelist_contents_equal_noorder(ctx.d.querySelectorAll('*'), [ctx.d_div1, ctx.d_p1, ctx.d_div2], 'd.querySelectorAll');
+ assert_nodelist_contents_equal_noorder(ctx.s1.querySelectorAll('*'), [ctx.s1_div1, ctx.s1_p1, ctx.s1_div2], 's1.querySelectorAll(\'*\') return wrong result');
+ assert_nodelist_contents_equal_noorder(ctx.s2.querySelectorAll('*'), [ctx.s2_div1, ctx.s2_p1, ctx.s2_div2], 's2.querySelectorAll(\'*\') return wrong result');
+
+}, 'A_04_01_09_T09');
+
+//check querySelectorAll with attribute value
+test(function () {
+ var ctx = A_04_01_09.setup();
+
+ assert_nodelist_contents_equal_noorder(ctx.d.querySelectorAll('[test=A_04_01_09]'), [ctx.d_p1, ctx.d_div2], 'd.querySelectorAll(\'[test=A_04_01_09]\') return wrong result');
+ assert_nodelist_contents_equal_noorder(ctx.s1.querySelectorAll('[test=A_04_01_09]'), [ctx.s1_p1, ctx.s1_div2], 's1.querySelectorAll(\'[test=A_04_01_09]\') return wrong result');
+ assert_nodelist_contents_equal_noorder(ctx.s2.querySelectorAll('[test=A_04_01_09]'), [ctx.s2_p1, ctx.s2_div2], 's2.querySelectorAll(\'[test=A_04_01_09]\') return wrong result');
+
+}, 'A_04_01_09_T10');
+
+//check querySelectorAll with parent-child selection
+test(function () {
+ var ctx = A_04_01_09.setup();
+
+ assert_nodelist_contents_equal_noorder(ctx.d.querySelectorAll('div:first-child'), [ctx.d_div1, ctx.d_div2], 'd.querySelectorAll(\'div:first-child\') return wrong result');
+ assert_nodelist_contents_equal_noorder(ctx.s1.querySelectorAll('div:first-child'), [ctx.s1_div1,ctx.s1_div2], 's1.querySelectorAll(\'div:first-child\') return wrong result');
+ assert_nodelist_contents_equal_noorder(ctx.s2.querySelectorAll('div:first-child'), [ctx.s2_div1,ctx.s2_div2], 's2.querySelectorAll(\'div:first-child\') return wrong result');
+
+}, 'A_04_01_09_T11');
+
+//check querySelectorAll with parent-child selection
+test(function () {
+ var ctx = A_04_01_09.setup();
+
+ assert_nodelist_contents_equal_noorder(ctx.d.querySelectorAll('div:last-child'), [ctx.d_div2], 'd.querySelectorAll(\'div:last-child\') return wrong result');
+ assert_nodelist_contents_equal_noorder(ctx.s1.querySelectorAll('div:last-child'), [ctx.s1_div1, ctx.s1_div2], 's1.querySelectorAll(\'div:last-child\') return wrong result');
+ assert_nodelist_contents_equal_noorder(ctx.s2.querySelectorAll('div:last-child'), [ctx.s2_div1, ctx.s2_div2], 's2.querySelectorAll(\'div:last-child\') return wrong result');
+
+}, 'A_04_01_09_T12');
+
+//check querySelectorAll with parent-child selection
+test(function () {
+ var ctx = A_04_01_09.setup();
+
+ assert_nodelist_contents_equal_noorder(ctx.d.querySelectorAll('p:only-child'), [ctx.d_p1], 'd.querySelectorAll(\'p:only-child\') return wrong result');
+ assert_nodelist_contents_equal_noorder(ctx.s1.querySelectorAll('p:only-child'), [ctx.s1_p1], 's1.querySelectorAll(\'p:only-child\') return wrong result');
+ assert_nodelist_contents_equal_noorder(ctx.s2.querySelectorAll('p:only-child'), [ctx.s2_p1], 's2.querySelectorAll(\'p:only-child\') return wrong result');
+
+}, 'A_04_01_09_T13');
+
+//check querySelectorAll with parent-child selection
+test(function () {
+ var ctx = A_04_01_09.setup();
+
+ assert_nodelist_contents_equal_noorder(ctx.d.querySelectorAll('div:empty'), [ctx.d_div2], 'd.querySelectorAll(\'div:empty\') return wrong result');
+ assert_nodelist_contents_equal_noorder(ctx.s1.querySelectorAll('div:empty'), [ctx.s1_div2], 's1.querySelectorAll(\'div:empty\') return wrong result');
+ assert_nodelist_contents_equal_noorder(ctx.s2.querySelectorAll('div:empty'), [ctx.s2_div2], 's2.querySelectorAll(\'div:empty\') return wrong result');
+
+}, 'A_04_01_09_T14');
+
+//check querySelectorAll with parent-child selection
+test(function () {
+ var ctx = A_04_01_09.setup();
+
+ assert_nodelist_contents_equal_noorder(ctx.d.querySelectorAll('p div'), [ctx.d_div2], 'd.querySelectorAll(\'p div\') return wrong result');
+ assert_nodelist_contents_equal_noorder(ctx.s1.querySelectorAll('p div'), [ctx.s1_div2], 's1.querySelectorAll(\'p div\') return wrong result');
+ assert_nodelist_contents_equal_noorder(ctx.s2.querySelectorAll('p div'), [ctx.s2_div2], 's2.querySelectorAll(\'p div\') return wrong result');
+
+}, 'A_04_01_09_T15');
+
+//check querySelectorAll with parent-child selection
+test(function () {
+ var ctx = A_04_01_09.setup();
+
+ assert_nodelist_contents_equal_noorder(ctx.d.querySelectorAll('p > div'), [ctx.d_div2], 'd.querySelectorAll(\'p > div\') return wrong result');
+ assert_nodelist_contents_equal_noorder(ctx.s1.querySelectorAll('p > div'), [ctx.s1_div2], 's1.querySelectorAll(\'p > div\') return wrong result');
+ assert_nodelist_contents_equal_noorder(ctx.s2.querySelectorAll('p > div'), [ctx.s2_div2], 's2.querySelectorAll(\'p > div\') return wrong result');
+
+}, 'A_04_01_09_T16');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-011.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-011.html
new file mode 100644
index 000000000..14d3f8227
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/test-011.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_04_01_11</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#upper-boundary-encapsulation">
+<meta name="assert" content="Upper-boundary encapsulation:The style sheets, represented by the shadow nodes are not accessible using shadow host document's CSSOM extensions">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+<script src="../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+// check that <link> element added to head is not exposed
+test(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+ var initialStyleSheetsCount = d.styleSheets.length;
+
+ var link = d.createElement('link');
+ link.setAttribute('rel', 'stylesheet');
+ d.body.appendChild(link);
+
+ //create Shadow root
+ var root = d.createElement('div');
+ d.body.appendChild(root);
+ var s = root.attachShadow({mode: 'open'});
+
+ s.appendChild(link);
+
+ assert_equals(d.styleSheets.length, initialStyleSheetsCount, 'stylesheet link elements in shadow DOM must not be ' +
+ 'exposed via the document.styleSheets collection');
+
+
+}), 'A_04_01_11_T2');
+
+// TODO check selectedStyleSheetSet, lastStyleSheetSet, preferredStyleSheetSet, styleSheetSets
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/window-named-properties-001.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/window-named-properties-001.html
new file mode 100644
index 000000000..f0aefee37
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/window-named-properties-001.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: Window object named properties: Frames</title>
+<link rel="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="author" title="Yuta Kitamura" href="mailto:yutak@google.com">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#upper-boundary-encapsulation">
+<meta name="assert" content="Upper-boundary encapsulation: The nodes and named elements are not accessible from Window object named properties.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(function () {
+ var host = document.createElement('div');
+ try {
+ host.style.display = 'none';
+ document.body.appendChild(host);
+ var shadowRoot = host.attachShadow({mode: 'open'});
+ var iframe = document.createElement('iframe');
+ iframe.style.display = 'none';
+ iframe.name = 'test-name';
+ shadowRoot.appendChild(iframe);
+ assert_false('test-name' in window);
+ } finally {
+ if (host.parentNode)
+ host.parentNode.removeChild(host);
+ }
+},
+ 'An iframe element in a shadow tree should not be accessible from ' +
+ 'window\'s named properties with its "name" attribute value.'
+);
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/window-named-properties-002.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/window-named-properties-002.html
new file mode 100644
index 000000000..45c0bf6a6
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/window-named-properties-002.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: Window object named properties: "name" attribute</title>
+<link rel="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="author" title="Yuta Kitamura" href="mailto:yutak@google.com">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#upper-boundary-encapsulation">
+<meta name="assert" content="Upper-boundary encapsulation: The nodes and named elements are not accessible from Window object named properties.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+function testNameAttribute(elementName) {
+ var doc = document.implementation.createHTMLDocument('Title');
+ var shadowRoot = doc.body.attachShadow({mode: 'open'});
+ var element = doc.createElement(elementName);
+ element.name = 'test-name';
+ shadowRoot.appendChild(element);
+ assert_false('test-name' in window);
+}
+
+var namedElements = [
+ 'a', 'applet', 'area', 'embed', 'form', 'frameset', 'img', 'object'
+];
+
+var nameAttributeTestParameter = namedElements.map(function (elementName) {
+ return [
+ '"' + elementName + '" element with name attribute in a shadow tree ' +
+ 'should not be accessible from window object\'s named property.',
+ elementName
+ ];
+});
+
+generate_tests(testNameAttribute, nameAttributeTestParameter);
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/window-named-properties-003.html b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/window-named-properties-003.html
new file mode 100644
index 000000000..b34f766f8
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/window-named-properties-003.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: Window object named properties: "id" attribute</title>
+<link rel="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="author" title="Yuta Kitamura" href="mailto:yutak@google.com">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#upper-boundary-encapsulation">
+<meta name="assert" content="Upper-boundary encapsulation: The nodes and named elements are not accessible from Window object named properties.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+<script src="../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+function testIDAttribute(elementName) {
+ var doc = document.implementation.createHTMLDocument('Title');
+ var shadowRoot = doc.body.attachShadow({mode: 'open'});
+ var element = doc.createElement(elementName);
+ element.id = 'test-id';
+ shadowRoot.appendChild(element);
+ assert_false('test-id' in window);
+}
+
+var idAttributeTestParameter = HTML5_ELEMENT_NAMES.map(function (elementName) {
+ return [
+ '"' + elementName + '" element with id attribute in a shadow tree ' +
+ 'should not be accessible from window object\'s named property.',
+ elementName
+ ];
+});
+
+generate_tests(testIDAttribute, idAttributeTestParameter);
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/styles/not-apply-in-shadow-root-001-ref.html b/testing/web-platform/tests/shadow-dom/untriaged/styles/not-apply-in-shadow-root-001-ref.html
new file mode 100644
index 000000000..fdcc6e5ba
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/styles/not-apply-in-shadow-root-001-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test</title>
+<link rel="author" title="Kazuhito Hokamura" href="mailto:k.hokamura@gmail.com">
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background: green;
+}
+</style>
+</head>
+<body>
+<p>Test passes if following box is green.</p>
+<div></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/styles/not-apply-in-shadow-root-001.html b/testing/web-platform/tests/shadow-dom/untriaged/styles/not-apply-in-shadow-root-001.html
new file mode 100644
index 000000000..7c27d98d4
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/styles/not-apply-in-shadow-root-001.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test - Tests CSS rules must not apply in a shadow root</title>
+<link rel="match" href="not-apply-in-shadow-root-001-ref.html">
+<link rel="author" title="Kazuhito Hokamura" href="mailto:k.hokamura@gmail.com">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#styles">
+<meta name="assert" content="Styles: CSS rules declared in an enclosing tree must not apply in a shadow tree if apply-author-styles flag is not set.">
+<script src="../../../html/resources/common.js"></script>
+<style>
+div {
+ width: 100px;
+ height: 100px;
+ background: green;
+}
+</style>
+</head>
+<body>
+<p>Test passes if following box is green.</p>
+<div id="shadow-host"></div>
+<script>
+var shadowHost = document.getElementById('shadow-host');
+var shadowRoot = shadowHost.attachShadow({mode: 'open'});
+var style = document.createElement('style');
+style.innerHTML = 'div { background: red }';
+
+shadowRoot.appendChild(style);
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/styles/test-001.html b/testing/web-platform/tests/shadow-dom/untriaged/styles/test-001.html
new file mode 100644
index 000000000..fd91574b6
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/styles/test-001.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_06_00_01</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#styles">
+<meta name="assert" content="Styles: CSS rules declared in an enclosing tree must not apply in a shadow tree if apply-author-styles flag is set to false for this tree">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../html/resources/common.js"></script>
+<script src="../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+//test apply-author-styles flag of ShadowRoot object (default value)
+test(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ d.head.innerHTML = '<style>' +
+ '.invis {' +
+ 'display:none;' +
+ '}' +
+ '</style>';
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+
+ //Shadow root to play with
+ var s = host.attachShadow({mode: 'open'});
+
+ var div1 = d.createElement('div');
+ div1.innerHTML ='<span id="shd" class="invis">This is the shadow tree</span>';
+ s.appendChild(div1);
+
+ //apply-author-styles flag is false by default. Invisible style shouldn't be applied
+ assert_true(s.querySelector('#shd').offsetTop > 0,
+ 'CSS styles declared in enclosing tree must not be applied in a shadow tree ' +
+ 'if the apply-author-styles flag is set to false');
+
+
+}), 'A_06_00_01_T01');
+
+
+//test apply-author-styles flag of ShadowRoot object (set it)
+test(unit(function (ctx) {
+
+ var d = newRenderedHTMLDocument(ctx);
+
+ d.head.innerHTML = '<style>' +
+ '.invis {' +
+ 'display:none;' +
+ '}' +
+ '</style>';
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+
+ //Shadow root to play with
+ var s = host.attachShadow({mode: 'open'});
+
+ var div1 = d.createElement('div');
+ div1.innerHTML ='<span id="shd" class="invis">This is the shadow tree</span>';
+ s.appendChild(div1);
+
+ //apply-author-styles flag is set to false. Invisible style shouldn't be applied
+ assert_true(s.querySelector('#shd').offsetTop > 0,
+ 'CSS styles declared in enclosing tree must not be applied in a shadow tree ' +
+ 'if the apply-author-styles flag is set to false');
+
+
+}), 'A_06_00_01_T02');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/styles/test-003.html b/testing/web-platform/tests/shadow-dom/untriaged/styles/test-003.html
new file mode 100644
index 000000000..d5b8f48ab
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/styles/test-003.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_06_00_03</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#styles">
+<meta name="assert" content="Styles: Each shadow root has an associated list of zero or more style sheets, named shadow root style sheets">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../html/resources/common.js"></script>
+<script src="../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(unit(function (ctx) {
+ var d = newRenderedHTMLDocument(ctx);
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+
+ //Shadow root to play with
+ var s = host.attachShadow({mode: 'open'});
+
+ assert_equals(s.styleSheets.length, 0, 'There should be no style sheets');
+}), 'A_06_00_03_T01');
+
+
+test(unit(function (ctx) {
+ var d = newRenderedHTMLDocument(ctx);
+ var host = d.createElement('div');
+ host.setAttribute('style', 'width:100px');
+ d.body.appendChild(host);
+
+ //Shadow root to play with
+ var s = host.attachShadow({mode: 'open'});
+
+ assert_equals(s.styleSheets.length, 0, 'There should be no style sheets');
+}), 'A_06_00_03_T02');
+
+//TODO Now this tests produces an error on Chromium because styleSheets.length
+//returns 0 when the shadow root is orphaned.
+//Tracking bug: http://crbug.com/392771
+test(unit(function (ctx) {
+ var d = newRenderedHTMLDocument(ctx);
+ var host = d.createElement('div');
+
+ //Shadow root to play with
+ var s = host.attachShadow({mode: 'open'});
+
+ var style = d.createElement('style');
+ style.textContent = 'div {width: 50%;}';
+ s.appendChild(style);
+
+ // The following line fixes the issue on Chromium, http://crbug.com/392771
+ // d.body.appendChild(host);
+ assert_equals(s.styleSheets.length, 1, 'Style sheet is not accessible via styleSheets');
+}), 'A_06_00_03_T03');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/styles/test-005.html b/testing/web-platform/tests/shadow-dom/untriaged/styles/test-005.html
new file mode 100644
index 000000000..0debdec5f
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/styles/test-005.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_06_00_06</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#styles">
+<meta name="assert" content="Styles:CSS rules declared in a shadow root style sheets must not apply in the document tree,">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../html/resources/common.js"></script>
+<script src="../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+//check querySelector method
+test(unit(function (ctx) {
+ var d = newRenderedHTMLDocument(ctx);
+
+ d.body.innerHTML =
+ '<div>' +
+ '<span class="invis" id="theTreeSpan">This is an element in the document tree</span>' +
+ '</div>' +
+ '<div id="sr">' +
+ '</div>';
+
+ var host = d.querySelector('#sr');
+
+ //Shadow root to play with
+ var s = host.attachShadow({mode: 'open'});
+
+ var style = d.createElement('style');
+ style.innerHTML ='.invis {display:none}';
+ s.appendChild(style);
+
+ var span = d.createElement('span');
+ span.setAttribute('id', 'theShadowSpan');
+ span.setAttribute('class', 'invis');
+ s.appendChild(span);
+
+ //theTreeSpan should be visible, theShadowSpan not
+ assert_true(d.querySelector('#theTreeSpan').offsetTop > 0,
+ 'CSS styles declared in shadow tree must not be applied to the elements ' +
+ 'in the document tree');
+
+ //theTreeSpan should be visible, theShadowSpan not
+ assert_equals(s.querySelector('#theShadowSpan').offsetTop, 0,
+ 'CSS styles declared in shadow tree must be applied to the element ' +
+ 'in the same shadow tree');
+
+}), 'A_06_00_06_T01');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/styles/test-008.html b/testing/web-platform/tests/shadow-dom/untriaged/styles/test-008.html
new file mode 100644
index 000000000..b84ca4df7
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/styles/test-008.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_06_00_09</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#styles">
+<meta name="assert" content="Styles:the styles of the shadow host are inherited by the children of the shadow root">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../html/resources/common.js"></script>
+<script src="../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(unit(function (ctx) {
+ var d = newRenderedHTMLDocument(ctx);
+
+ d.body.innerHTML = '' +
+ '<div id="shHost" style="font-size:10px">' +
+ '<span id="spn1">This is a shadow host child</span>' +
+ '</div>';
+
+ var host = d.querySelector('#shHost');
+
+ var s = host.attachShadow({mode: 'open'});
+
+ var div = d.createElement('div');
+ div.innerHTML ='<span id="spn2">This is a shadow root child</span>';
+ s.appendChild(div);
+
+ assert_equals(d.querySelector('#spn1').offsetTop, 0,
+ 'Element should not be rendered');
+ assert_true(s.querySelector('#spn2').offsetTop > 0,
+ 'Element should be rendered');
+
+ var oldHeight = s.querySelector('#spn2').offsetHeight;
+
+ host.setAttribute('style', 'font-size:20px');
+
+ assert_true(s.querySelector('#spn2').offsetHeight > oldHeight,
+ 'Shadow host style must be aplied to the shadow root children');
+
+}), 'A_06_00_09_T01');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/user-interaction/active-element/test-001.html b/testing/web-platform/tests/shadow-dom/untriaged/user-interaction/active-element/test-001.html
new file mode 100644
index 000000000..0c3b033da
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/user-interaction/active-element/test-001.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_07_03_01</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#active-element">
+<meta name="assert" content="User Interaction: each shadow root must also have an activeElement property to store the value of the focused element in the shadow tree.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+<script src="../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(unit(function (ctx) {
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+ var s = host.attachShadow({mode: 'open'});
+
+ var inp = d.createElement('input');
+ inp.setAttribute('type', 'text');
+ inp.setAttribute('id', 'inpId');
+ inp.setAttribute('value', 'Some text');
+ s.appendChild(inp);
+
+ inp.focus();
+
+ assert_equals(s.activeElement.tagName, 'INPUT', 'Point 1:activeElement property of shadow root ' +
+ 'must return the value of the focused element in the shadow tree');
+ assert_equals(s.activeElement.getAttribute('id'), 'inpId', 'Point 2:activeElement property of shadow root ' +
+ 'must return the value of the focused element in the shadow tree');
+
+}), 'A_07_03_01_T01');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/user-interaction/active-element/test-002.html b/testing/web-platform/tests/shadow-dom/untriaged/user-interaction/active-element/test-002.html
new file mode 100644
index 000000000..ed679ee91
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/user-interaction/active-element/test-002.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_07_03_02</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#active-element">
+<meta name="assert" content="User Interaction: Document's activeElement property must be adjusted">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+<script src="../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(unit(function (ctx) {
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ host.setAttribute('id', 'shRoot');
+ d.body.appendChild(host);
+ var s = host.attachShadow({mode: 'open'});
+
+ var inp = d.createElement('input');
+ inp.setAttribute('type', 'text');
+ inp.setAttribute('id', 'inpId');
+ inp.setAttribute('value', 'Some text');
+ s.appendChild(inp);
+
+ inp.focus();
+
+ assert_equals(d.activeElement.tagName, 'DIV', 'Point 1: document\'s activeElement property ' +
+ 'must return adjusted the value of the focused element in the shadow tree');
+ assert_equals(d.activeElement.getAttribute('id'), 'shRoot', 'Point 2: document\'s activeElement property ' +
+ 'must return adjusted the value of the focused element in the shadow tree');
+
+}), 'A_07_03_02_T01');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/user-interaction/editing/inheritance-of-content-editable-001.html b/testing/web-platform/tests/shadow-dom/untriaged/user-interaction/editing/inheritance-of-content-editable-001.html
new file mode 100644
index 000000000..28225ac4a
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/user-interaction/editing/inheritance-of-content-editable-001.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: Inheritance of contentEditable attribute</title>
+<link rel="author" title="Moto Ishizawa" href="mailto:summerwind.jp@gmail.com">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#editing">
+<meta name="assert" content="User Interaction: Shadow trees must not be propagated contentEditable attribute from shadow host">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+<script src="../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(unit(function (ctx) {
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ host.contentEditable = "true";
+ d.body.appendChild(host);
+
+ var s = host.attachShadow({mode: 'open'});
+
+ assert_equals(host.contentEditable, "true");
+ assert_equals(s.contentEditable, undefined);
+}), 'contentEditable of shadow trees must be undefined when contentEditable attribute of shadow host is "true"');
+
+test(unit(function (ctx) {
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ host.contentEditable = "false";
+ d.body.appendChild(host);
+
+ var s = host.attachShadow({mode: 'open'});
+
+ assert_equals(host.contentEditable, 'false');
+ assert_equals(s.contentEditable, undefined);
+}), 'contentEditable of shadow trees must be undefined when contentEditable of shadow host is "false"');
+
+test(unit(function (ctx) {
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+ d.body.contentEditable = "true";
+
+ var s = host.attachShadow({mode: 'open'});
+
+ assert_equals(host.contentEditable, 'inherit');
+ assert_equals(s.contentEditable, undefined);
+}), 'contentEditable of shadow trees must be undefined when contentEditable attribute of shadow host is "inherit"');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/user-interaction/ranges-and-selections/test-001.html b/testing/web-platform/tests/shadow-dom/untriaged/user-interaction/ranges-and-selections/test-001.html
new file mode 100644
index 000000000..2df78d8a6
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/user-interaction/ranges-and-selections/test-001.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_07_01_01</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#ranges-and-selection">
+<meta name="assert" content="User Interaction: Selection, returned by the window.getSelection() method must never return a selection within a shadow tree">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+<script src="../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(unit(function (ctx) {
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+ var s = host.attachShadow({mode: 'open'});
+
+ var span = d.createElement('span');
+ span.innerHTML = 'Some text';
+ s.appendChild(span);
+
+ var range = d.createRange();
+ range.setStart(span.firstChild, 0);
+ range.setEnd(span.firstChild, 3);
+
+ var selection = window.getSelection();
+ selection.removeAllRanges();
+ selection.addRange(range);
+
+ var sl = window.getSelection();
+ assert_equals(sl.toString(), '', 'window.getSelection() method must never return a selection ' +
+ 'within a shadow tree');
+
+}), 'A_07_07_01_T01');
+
+
+// test distributed nodes
+test(unit(function (ctx) {
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+
+ var span = d.createElement('span');
+ span.innerHTML = 'Some text';
+ span.setAttribute('slot', 'span');
+ host.appendChild(span);
+
+ var s = host.attachShadow({mode: 'open'});
+ s.innerHTML = '<slot name="span"></slot>';
+
+ var range = d.createRange();
+ range.setStart(span.firstChild, 0);
+ range.setEnd(span.firstChild, 3);
+
+ var selection = window.getSelection();
+ selection.removeAllRanges();
+ selection.addRange(range);
+
+ var sl = window.getSelection();
+ assert_equals(sl.toString(), '', 'window.getSelection() method must never return a selection ' +
+ 'within a shadow tree');
+
+}), 'A_07_07_01_T02');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shadow-dom/untriaged/user-interaction/ranges-and-selections/test-002.html b/testing/web-platform/tests/shadow-dom/untriaged/user-interaction/ranges-and-selections/test-002.html
new file mode 100644
index 000000000..76ff0f5dd
--- /dev/null
+++ b/testing/web-platform/tests/shadow-dom/untriaged/user-interaction/ranges-and-selections/test-002.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<!--
+Distributed under both the W3C Test Suite License [1] and the W3C
+3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
+policies and contribution forms [3].
+
+[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
+[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
+[3] http://www.w3.org/2004/10/27-testcases
+-->
+<html>
+<head>
+<title>Shadow DOM Test: A_07_01_02</title>
+<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
+<link rel="help" href="http://www.w3.org/TR/2013/WD-shadow-dom-20130514/#ranges-and-selection">
+<meta name="assert" content="User Interaction: The getSelection() method of the shadow root object must return the current selection in this shadow tree.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../../../html/resources/common.js"></script>
+<script src="../../../resources/shadow-dom-utils.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(unit(function (ctx) {
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+ var s = host.attachShadow({mode: 'open'});
+
+ var span = d.createElement('span');
+ span.innerHTML = 'Some text';
+ s.appendChild(span);
+
+ var range = d.createRange();
+ range.setStart(span.firstChild, 0);
+ range.setEnd(span.firstChild, 3);
+
+ var selection = d.defaultView.getSelection();
+ selection.removeAllRanges();
+ selection.addRange(range);
+
+ var sl = s.getSelection();
+ assert_equals(sl.toString(), 'Som', 'The getSelection() method of the shadow root object must return ' +
+ 'the current selection in this shadow tree');
+
+}), 'A_07_01_02_T01');
+
+
+//test distributed nodes
+test(unit(function (ctx) {
+ var d = newRenderedHTMLDocument(ctx);
+
+ var host = d.createElement('div');
+ d.body.appendChild(host);
+
+ var span = d.createElement('span');
+ span.innerHTML = 'Some text';
+ span.setAttribute('slot', 'slot');
+ host.appendChild(span);
+
+ var s = host.attachShadow({mode: 'open'});
+ s.innerHTML = '<slot name="slot"></slot>';
+
+ var range = d.createRange();
+ range.setStart(span.firstChild, 0);
+ range.setEnd(span.firstChild, 3);
+
+ var selection = d.defaultView.getSelection();
+ selection.removeAllRanges();
+ selection.addRange(range);
+
+ var sl = s.getSelection();
+ assert_equals(sl.toString(), 'Som', 'The getSelection() method of the shadow root object must return ' +
+ 'the current selection in this shadow tree');
+
+}), 'A_07_07_02_T02');
+</script>
+</body>
+</html>