| <!DOCTYPE html> |
| <html> |
| <head> |
| <script src="../../../resources/js-test-pre.js"></script> |
| <script src="resources/shadow-dom.js"></script> |
| </head> |
| <body> |
| <div id="console"></div> |
| <div id="sandbox"></div> |
| <script> |
| description("Tests for Composed Shadow DOM Tree Traversal APIs. Can only run within DRT"); |
| |
| if (window.testRunner) |
| testRunner.dumpAsText(); |
| |
| function dumpNode(node) |
| { |
| if (!node) |
| return '(null)' |
| var output = node.nodeName + "\t"; |
| if (node.id) |
| output += ' id=' + node.id; |
| if (node.className) |
| output += ' class=' + node.className; |
| return output; |
| } |
| |
| function dumpComposedShadowTree(node, indent) |
| { |
| indent = indent || ""; |
| var output = indent + dumpNode(node) + "\n"; |
| var child; |
| for (child = internals.firstChildByWalker(node); child; child = internals.nextSiblingByWalker(child)) |
| output += dumpComposedShadowTree(child, indent + "\t"); |
| return output; |
| } |
| |
| function lastNodeByWalker(root) |
| { |
| var lastNode = root; |
| while (internals.lastChildByWalker(lastNode)) |
| lastNode = internals.lastChildByWalker(lastNode); |
| return lastNode; |
| } |
| |
| function showComposedShadowTreeByTraversingInForward(root) |
| { |
| var node = root; |
| var last = lastNodeByWalker(root); |
| while (node) { |
| debug(dumpNode(node)); |
| if (node == last) |
| break; |
| node = internals.nextNodeByWalker(node); |
| } |
| } |
| |
| function showComposedShadowTreeByTraversingInBackward(root) |
| { |
| var node = lastNodeByWalker(root); |
| while (node) { |
| debug(dumpNode(node)); |
| if (node == root) |
| break; |
| node = internals.previousNodeByWalker(node); |
| } |
| } |
| |
| function showComposedShadowTree(node) |
| { |
| debug('Composed Shadow Tree:'); |
| debug(dumpComposedShadowTree(node)); |
| |
| debug('Traverse in forward.'); |
| showComposedShadowTreeByTraversingInForward(node); |
| |
| debug('Traverse in backward.'); |
| showComposedShadowTreeByTraversingInBackward(node); |
| |
| debug(''); |
| } |
| |
| function showNextNode(node) { |
| var next = internals.nextNodeByWalker(node); |
| debug('Next node of [' + dumpNode(node) + '] is [' + dumpNode(next) + ']'); |
| } |
| |
| function testComposedShadowTree(node) |
| { |
| var sandbox = document.getElementById('sandbox'); |
| sandbox.innerHTML = ''; |
| sandbox.appendChild(node); |
| document.body.offsetLeft; |
| showComposedShadowTree(node); |
| } |
| |
| debug('ShadowRoot should be used.'); |
| testComposedShadowTree( |
| createDOM('div', {'id': 'a'}, |
| createShadowRoot(createDOM('div', {'id': 'b'})), |
| createDOM('div', {'id': 'c'}))); |
| |
| debug('A content element should select light children'); |
| testComposedShadowTree( |
| createDOM('div', {'id': 'a'}, |
| createShadowRoot(createDOM('div', {'id': 'b'}), |
| createDOM('content')), |
| createDOM('div', {'id': 'c'}), |
| createDOM('div', {'id': 'd'}))); |
| |
| debug('Test for content element selector.'); |
| testComposedShadowTree( |
| createDOM('div', {'id': 'a'}, |
| createShadowRoot(createDOM('div', {'id': 'b'}), |
| createDOM('content', {'select': '#d'})), |
| createDOM('div', {'id': 'c'}), |
| createDOM('div', {'id': 'd'}), |
| createDOM('div', {'id': 'e'}))); |
| |
| debug('Light children should be selected only at once.'); |
| testComposedShadowTree( |
| createDOM('div', {'id': 'a'}, |
| createShadowRoot(createDOM('div', {'id': 'b'}), |
| createDOM('content', {'select': '#d'}), |
| createDOM('content')), |
| createDOM('div', {'id': 'c'}), |
| createDOM('div', {'id': 'd'}), |
| createDOM('div', {'id': 'e'}))); |
| |
| debug('A content element can have fallback elements.'); |
| testComposedShadowTree( |
| createDOM('div', {'id': 'a'}, |
| createShadowRoot(createDOM('div', {'id': 'b'}), |
| createDOM('content', {'select': '#z'}, |
| createDOM('div', {'id': 'f1'}), |
| createDOM('div', {'id': 'f2'}))), |
| createDOM('div', {'id': 'c'}))); |
| |
| debug('Fallback elements should not be used if a content element selects an element.'); |
| testComposedShadowTree( |
| createDOM('div', {'id': 'a'}, |
| createShadowRoot(createDOM('div', {'id': 'b'}), |
| createDOM('content', {'select': '#c'}, |
| createDOM('div', {'id': 'f1'}, |
| createDOM('div', {'id': 'f2'})))), |
| createDOM('div', {'id': 'c'}))); |
| |
| debug('Test for traversal, starting with a fallback element which is not used.'); |
| showComposedShadowTree(getNodeInShadowTreeStack('a/f1')); |
| showNextNode(getNodeInShadowTreeStack('a/f1')); |
| showNextNode(getNodeInShadowTreeStack('a/f2')); |
| debug(''); |
| |
| debug('Test for Nested ShadowRoots.'); |
| testComposedShadowTree( |
| createDOM('div', {'id': 'a'}, |
| createShadowRoot(createDOM('div', {'id': 'b'}, |
| createShadowRoot(createDOM('div', {'id': 'c'}), |
| createDOM('content'), |
| createDOM('div', {'id': 'd'})), |
| createDOM('div', {'id': 'e'})), |
| createDOM('div', {'id': 'f'}), |
| createDOM('content'), |
| createDOM('div', {'id': 'g'})), |
| createDOM('div', {'id': 'h'}), |
| createDOM('div', {'id': 'i'}))); |
| |
| debug('Test for Multiple ShadowRoots.'); |
| testComposedShadowTree( |
| createDOM('div', {'id': 'a'}, |
| createShadowRoot(createDOM('div', {'id': 'b'}), |
| createDOM('content'), |
| createDOM('div', {'id': 'c'})), |
| createShadowRoot(createDOM('div', {'id': 'd'}), |
| createDOM('shadow'), |
| createDOM('div', {'id': 'e'})), |
| createDOM('div', {'id': 'f'}))); |
| |
| debug('Test for inactive insertion points.'); |
| testComposedShadowTree( |
| createDOM('div', {'id': 'a'}, |
| createDOM('content', {'id': 'b'}, |
| createDOM('content', {'id': 'c'})))); |
| |
| debug('Test for an orphaned shadow subtree.'); |
| testComposedShadowTree( |
| createDOM('div', {'id': 'a'}, |
| createShadowRoot( |
| createDOM('div', {'id': 'b'}, |
| createDOM('div', {'id': 'c'}))), |
| createShadowRoot( |
| createDOM('div', {'id': 'd'})))); |
| |
| debug('Test for traversal, starting with a node in an orphaned shadow subtree.'); |
| showComposedShadowTree(getNodeInShadowTreeStack('a/b')); |
| |
| debug('Test for a content element which does not select any nodes nor have fallback elements.'); |
| testComposedShadowTree( |
| createDOM('div', {'id': 'a'}, |
| createShadowRoot(createDOM('content', {'select': '#none'}), |
| createDOM('div', {'id': 'b'}), |
| createDOM('content', {'select': '#none'}), |
| createDOM('div', {'id': 'c'}), |
| createDOM('content', {'select': '#none'})))); |
| |
| debug('Test for a nested insertion point.'); |
| testComposedShadowTree( |
| createDOM('div', {'id': 'a'}, |
| createShadowRoot(createDOM('div', {'id': 'b'}, |
| createShadowRoot(createDOM('content', {})), |
| createDOM('content', {}))), |
| createDOM('div', {'id': 'c'}))); |
| |
| debug('Test for nested insertion points. Some of them are either empty insertion points or inactive insertion points.'); |
| testComposedShadowTree( |
| createDOM('div', {'id': 'a'}, |
| createShadowRoot(createDOM('content', {'select': '#none'}), |
| createDOM('div', {'id': 'b'}, |
| createShadowRoot(createDOM('content', {'select': '.select-1'}), |
| createDOM('div', {'id': 'c'}), |
| createDOM('content', {'select': '.select-2'})), |
| createDOM('content', {'class': 'select-1', 'select': '.select-4'}), |
| createDOM('content', {'class': 'select-2', 'select': '#none'}), |
| createDOM('div', {'id': 'd', 'class': 'select-2'}), |
| createDOM('content', {'class': 'select-2', 'select': '#none'}), |
| createDOM('div', {'id': 'e', 'class': 'select-2'}), |
| createDOM('content', {'class': 'select-2', 'select': '#none'}))), |
| createDOM('content', {'id': 'inactive-insertion-point', 'class': 'select-4'}), |
| createDOM('div', {'id': 'should-not-be-selected'}), |
| createDOM('div', {'id': 'f', 'class': 'select-4'}))); |
| |
| debug('Test for a re-projection.'); |
| testComposedShadowTree( |
| createDOM('div', {'id': 'a'}, |
| createShadowRoot( |
| createDOM('div', {'id': 'b'}, |
| createShadowRoot(createDOM('content', {'select': '#c'})), |
| createDOM('content', {'select': '#c'}))), |
| createDOM('div', {'id': 'c'}))); |
| |
| debug('Test for a content element which is selected by another content element.'); |
| testComposedShadowTree( |
| createDOM('div', {'id': 'a'}, |
| createShadowRoot( |
| createDOM('div', {'id': 'b'}, |
| createShadowRoot(createDOM('content', {'select': '#content'}), |
| createDOM('div', {'id': 'most-inner-child'}), |
| createDOM('content', {'select': '#host-child'})), |
| createDOM('content', {'id': 'content', 'select': '#host-child'}, |
| createDOM('div', {'id': 'should-not-be-used'})), |
| createDOM('div', {'id': 'inner-child', 'class': 'foo'}))), |
| createDOM('div', {'id': 'host-child'}))); |
| |
| debug('Test for a reprojection. Content elements should be used in document order.'); |
| testComposedShadowTree( |
| createDOM('div', {'id': 'a'}, |
| createShadowRoot( |
| createDOM('content', {'select': '#host-child1'}), |
| createDOM('div', {'id': 'b'}, |
| createShadowRoot(createDOM('content', {'select': '.child'})), |
| createDOM('content', {'select': '.child'}))), |
| createDOM('div', {'id': 'host-child1', 'class': 'child'}), |
| createDOM('div', {'id': 'host-child2', 'class': 'child'}))); |
| |
| debug('Test for complex re-projections.'); |
| testComposedShadowTree( |
| createDOM('div', {'id': 'a'}, |
| createShadowRoot( |
| createDOM('div', {'id': 'b'}, |
| createShadowRoot(createDOM('content', {'select': '.foo'}), |
| createDOM('div', {'id': 'c'})), |
| // Select #child-1 |
| createDOM('content', {'select': '#child-1'}, |
| createDOM('div', {'class': 'should-not-be-used'}), |
| // Should not select any nodes since it's inactive. |
| createDOM('content', {'class': 'should-be-inactive', 'select': '.foo'})), |
| createDOM('div', {'id': 'd', 'class': 'foo'}, |
| createShadowRoot(createDOM('div', {'id': 'e'}), |
| // Should select #child-2 and #g. |
| createDOM('content', {'select': '.foo'}), |
| createDOM('div', {'id': 'f'})), |
| // Select #child-2 |
| createDOM('content', {'select': '#child-2'}), |
| createDOM('div', {'id': 'g', 'class': 'foo'})), |
| createDOM('div', {'class': 'should-not-be-selected'}), |
| createDOM('div', {'id': 'h', 'class': 'foo'}))), |
| createDOM('div', {'id': 'child-1', 'class': 'foo'}), |
| createDOM('div', {'id': 'not-selected', 'class': 'foo'}), |
| createDOM('div', {'id': 'child-2', 'class': 'foo'}))); |
| </script> |
| <script src="../../../resources/js-test-post.js"></script> |
| </body> |
| </html> |