--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<title>Shadow DOM: Extensions to Node interface</title>
+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+<meta name="assert" content="Node interface must have treeRoot attribute">
+<link rel="help" href="http://w3c.github.io/webcomponents/spec/shadow/#extensions-to-node-interface">
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<link rel='stylesheet' href='../../resources/testharness.css'>
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+test(function () {
+ assert_true('treeRoot' in Node.prototype, 'treeRoot must be defined on Node.prototype');
+ assert_true('treeRoot' in document.createElement('div'), 'treeRoot must be defined on a div element');
+ assert_true('treeRoot' in document.createTextNode(''), 'assignedSlot must be defined on a text node');
+ assert_true('treeRoot' in document.createComment(''), 'assignedSlot must be defined on a comment node');
+ assert_true('treeRoot' in document.createProcessingInstruction('target', 'data'), 'assignedSlot must be defined on a processing instruction node');
+ assert_true('treeRoot' in document, 'assignedSlot must be defined on a document node');
+ assert_true('treeRoot' in document.createElement('div').attachShadow({mode: 'closed'}), 'treeRoot must be defined on a closed shadow root element');
+ assert_true('treeRoot' in document.createElement('div').attachShadow({mode: 'open'}), 'treeRoot must be defined on a open shadow root element');
+}, 'treeRoot attribute must be defined on Node interface');
+
+test(function () {
+ var element = document.createElement('div');
+ assert_equals(element.treeRoot, element, 'treeRoot on an element without a parent must return the element itself');
+
+ var text = document.createTextNode('');
+ assert_equals(text.treeRoot, text, 'treeRoot on a text node without a parent must return the text node itself');
+
+ var processingInstruction = document.createProcessingInstruction('target', 'data');
+ assert_equals(processingInstruction.treeRoot, processingInstruction, 'treeRoot on a processing instruction node without a parent must return the processing instruction node itself');
+
+ assert_equals(document.treeRoot, document, 'treeRoot on a document node must return the document itself');
+
+ var closedShadowRoot = document.createElement('div').attachShadow({mode: 'closed'});
+ assert_equals(closedShadowRoot.treeRoot, closedShadowRoot, 'treeRoot on a closed shadow root must return the shadow root itself');
+
+ var openShadowRoot = document.createElement('div').attachShadow({mode: 'open'});
+ assert_equals(openShadowRoot.treeRoot, openShadowRoot, 'treeRoot on a open shadow root must return the shadow root itself');
+}, 'treeRoot attribute must return the context object when it does not have any parent');
+
+test(function () {
+ var parent = document.createElement('div');
+
+ var element = document.createElement('div');
+ parent.appendChild(element);
+ assert_equals(element.treeRoot, parent, 'treeRoot on an element with a single ancestor must return the parent node');
+
+ var text = document.createTextNode('');
+ parent.appendChild(text);
+ assert_equals(text.treeRoot, parent, 'treeRoot on a text node with a single ancestor must return the parent node');
+
+ var processingInstruction = document.createProcessingInstruction('target', 'data');
+ parent.appendChild(processingInstruction)
+ assert_equals(processingInstruction.treeRoot, parent, 'treeRoot on a processing instruction node with a single ancestor must return the parent node');
+
+ var hostWithClosedShadowRoot = document.createElement('div');
+ parent.appendChild(hostWithClosedShadowRoot);
+ var closedShadowRoot = hostWithClosedShadowRoot.attachShadow({mode: 'closed'});
+ assert_equals(closedShadowRoot.treeRoot, closedShadowRoot, 'treeRoot on a closed shadow root with a single ancestor on its host must return the shadow root itself');
+
+ var hostWithOpenShadowRoot = document.createElement('div');
+ parent.appendChild(hostWithOpenShadowRoot);
+ var openShadowRoot = hostWithOpenShadowRoot.attachShadow({mode: 'open'});
+ assert_equals(openShadowRoot.treeRoot, openShadowRoot, 'treeRoot on a open shadow root with a single ancestor on its host must return the shadow root itself');
+}, 'treeRoot attribute must return the parent node of the context object when the context object has a single ancestor not in a document');
+
+test(function () {
+ var parent = document.createElement('div');
+ document.body.appendChild(parent);
+
+ var element = document.createElement('div');
+ parent.appendChild(element);
+ assert_equals(element.treeRoot, document, 'treeRoot on an element inside a document must return the document');
+
+ var text = document.createTextNode('');
+ parent.appendChild(text);
+ assert_equals(text.treeRoot, document, 'treeRoot on a text node inside a document must return the document');
+
+ var processingInstruction = document.createProcessingInstruction('target', 'data');
+ parent.appendChild(processingInstruction)
+ assert_equals(processingInstruction.treeRoot, document, 'treeRoot on a processing instruction node inside a document must return the document');
+}, 'treeRoot attribute must return the document when a node is in document and not in a shadow tree');
+
+function testTreeRootOnNodeInsideShadowTree(mode) {
+ test(function () {
+ var host = document.createElement('div');
+ document.body.appendChild(host);
+
+ var shadowRoot = host.attachShadow({mode: mode});
+ var parent = document.createElement('p');
+ shadowRoot.appendChild(parent);
+
+ var element = document.createElement('span');
+ parent.appendChild(element);
+ assert_equals(element.treeRoot, shadowRoot, 'treeRoot on an element inside a shadow tree must return the shadow root');
+
+ var text = document.createTextNode('');
+ parent.appendChild(text);
+ assert_equals(text.treeRoot, shadowRoot, 'treeRoot on a text node inside a shadow tree must return the shadow root');
+
+ var processingInstruction = document.createProcessingInstruction('target', 'data');
+ parent.appendChild(processingInstruction);
+ assert_equals(processingInstruction.treeRoot, shadowRoot, 'treeRoot on a processing instruction node inside a shadow tree must return the shadow root');
+ }, 'treeRoot attribute must return the ' + mode + ' shadow root of the context object when the shadow host is in a document');
+}
+
+testTreeRootOnNodeInsideShadowTree('open');
+testTreeRootOnNodeInsideShadowTree('closed');
+
+function testTreeRootOnNodeInsideNestedShadowTree(outerMode, innerMode) {
+ test(function () {
+ var outerHost = document.createElement('div');
+ document.body.appendChild(outerHost);
+ var outerShadowRoot = outerHost.attachShadow({mode: outerMode});
+
+ var innerHost = document.createElement('section');
+ outerShadowRoot.appendChild(innerHost);
+ var innerShadowRoot = innerHost.attachShadow({mode: innerMode});
+
+ var parent = document.createElement('p');
+ innerShadowRoot.appendChild(parent);
+
+ var element = document.createElement('span');
+ parent.appendChild(element);
+ assert_equals(element.treeRoot, innerShadowRoot, 'treeRoot on an element inside a shadow tree must return its root node');
+
+ var text = document.createTextNode('');
+ parent.appendChild(text);
+ assert_equals(text.treeRoot, innerShadowRoot, 'treeRoot on a text node inside a shadow tree must return its root node');
+
+ var processingInstruction = document.createProcessingInstruction('target', 'data');
+ parent.appendChild(processingInstruction);
+ assert_equals(processingInstruction.treeRoot, innerShadowRoot, 'treeRoot on a processing instruction node inside a shadow tree must return its root node');
+ }, 'treeRoot attribute must return the root node of the context object when the context object is inside a ' + innerMode
+ + ' shadow root whose shadow host is in another ' + outerMode + ' shadow root');
+}
+
+testTreeRootOnNodeInsideNestedShadowTree('open', 'open');
+testTreeRootOnNodeInsideNestedShadowTree('open', 'closed');
+testTreeRootOnNodeInsideNestedShadowTree('closed', 'open');
+testTreeRootOnNodeInsideNestedShadowTree('closed', 'closed');
+
+</script>
+</body>
+</html>