summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/dom/traversal
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/dom/traversal')
-rw-r--r--testing/web-platform/tests/dom/traversal/NodeFilter-constants.html34
-rw-r--r--testing/web-platform/tests/dom/traversal/NodeIterator-removal.html100
-rw-r--r--testing/web-platform/tests/dom/traversal/NodeIterator.html215
-rw-r--r--testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter-cross-realm-null-browsing-context.html30
-rw-r--r--testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter-cross-realm.html60
-rw-r--r--testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter.html195
-rw-r--r--testing/web-platform/tests/dom/traversal/TreeWalker-basic.html154
-rw-r--r--testing/web-platform/tests/dom/traversal/TreeWalker-currentNode.html73
-rw-r--r--testing/web-platform/tests/dom/traversal/TreeWalker-previousNodeLastChildReject.html87
-rw-r--r--testing/web-platform/tests/dom/traversal/TreeWalker-previousSiblingLastChildSkip.html91
-rw-r--r--testing/web-platform/tests/dom/traversal/TreeWalker-traversal-reject.html109
-rw-r--r--testing/web-platform/tests/dom/traversal/TreeWalker-traversal-skip-most.html66
-rw-r--r--testing/web-platform/tests/dom/traversal/TreeWalker-traversal-skip.html111
-rw-r--r--testing/web-platform/tests/dom/traversal/TreeWalker-walking-outside-a-tree.html40
-rw-r--r--testing/web-platform/tests/dom/traversal/TreeWalker.html324
-rw-r--r--testing/web-platform/tests/dom/traversal/support/TreeWalker-acceptNode-filter-cross-realm-null-browsing-context-subframe.html13
-rw-r--r--testing/web-platform/tests/dom/traversal/support/assert-node.js10
-rw-r--r--testing/web-platform/tests/dom/traversal/support/empty-document.html3
-rw-r--r--testing/web-platform/tests/dom/traversal/unfinished/001.xml53
-rw-r--r--testing/web-platform/tests/dom/traversal/unfinished/002.xml54
-rw-r--r--testing/web-platform/tests/dom/traversal/unfinished/003.xml58
-rw-r--r--testing/web-platform/tests/dom/traversal/unfinished/004.xml49
-rw-r--r--testing/web-platform/tests/dom/traversal/unfinished/005.xml57
-rw-r--r--testing/web-platform/tests/dom/traversal/unfinished/006.xml47
-rw-r--r--testing/web-platform/tests/dom/traversal/unfinished/007.xml54
-rw-r--r--testing/web-platform/tests/dom/traversal/unfinished/008.xml48
-rw-r--r--testing/web-platform/tests/dom/traversal/unfinished/009.xml55
-rw-r--r--testing/web-platform/tests/dom/traversal/unfinished/010.xml64
-rw-r--r--testing/web-platform/tests/dom/traversal/unfinished/TODO1
29 files changed, 2255 insertions, 0 deletions
diff --git a/testing/web-platform/tests/dom/traversal/NodeFilter-constants.html b/testing/web-platform/tests/dom/traversal/NodeFilter-constants.html
new file mode 100644
index 0000000000..1ce4736cc6
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/NodeFilter-constants.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<title>NodeFilter constants</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../constants.js"></script>
+<div id="log"></div>
+<script>
+var objects;
+setup(function() {
+ objects = [
+ [NodeFilter, "NodeFilter interface object"],
+ ]
+})
+testConstants(objects, [
+ ["FILTER_ACCEPT", 1],
+ ["FILTER_REJECT", 2],
+ ["FILTER_SKIP", 3]
+], "acceptNode")
+testConstants(objects, [
+ ["SHOW_ALL", 0xFFFFFFFF],
+ ["SHOW_ELEMENT", 0x1],
+ ["SHOW_ATTRIBUTE", 0x2],
+ ["SHOW_TEXT", 0x4],
+ ["SHOW_CDATA_SECTION", 0x8],
+ ["SHOW_ENTITY_REFERENCE", 0x10],
+ ["SHOW_ENTITY", 0x20],
+ ["SHOW_PROCESSING_INSTRUCTION", 0x40],
+ ["SHOW_COMMENT", 0x80],
+ ["SHOW_DOCUMENT", 0x100],
+ ["SHOW_DOCUMENT_TYPE", 0x200],
+ ["SHOW_DOCUMENT_FRAGMENT", 0x400],
+ ["SHOW_NOTATION", 0x800]
+], "whatToShow")
+</script>
diff --git a/testing/web-platform/tests/dom/traversal/NodeIterator-removal.html b/testing/web-platform/tests/dom/traversal/NodeIterator-removal.html
new file mode 100644
index 0000000000..b5fc69541a
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/NodeIterator-removal.html
@@ -0,0 +1,100 @@
+<!doctype html>
+<title>NodeIterator removal tests</title>
+<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name>
+<meta name=timeout content=long>
+<div id=log></div>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=../common.js></script>
+<script>
+"use strict";
+
+for (var i = 0; i < testNodes.length; i++) {
+ var node = eval(testNodes[i]);
+ if (!node.parentNode) {
+ // Nothing to test
+ continue;
+ }
+ test(function() {
+ var iters = [];
+ var descs = [];
+ var expectedReferenceNodes = [];
+ var expectedPointers = [];
+
+ for (var j = 0; j < testNodes.length; j++) {
+ var root = eval(testNodes[j]);
+ // Add all distinct iterators with this root, calling nextNode()
+ // repeatedly until it winds up with the same iterator.
+ for (var k = 0; ; k++) {
+ var iter = document.createNodeIterator(root);
+ for (var l = 0; l < k; l++) {
+ iter.nextNode();
+ }
+ if (k && iter.referenceNode == iters[iters.length - 1].referenceNode
+ && iter.pointerBeforeReferenceNode
+ == iters[iters.length - 1].pointerBeforeReferenceNode) {
+ break;
+ } else {
+ iters.push(iter);
+ descs.push("document.createNodeIterator(" + testNodes[j]
+ + ") advanced " + k + " times");
+ expectedReferenceNodes.push(iter.referenceNode);
+ expectedPointers.push(iter.pointerBeforeReferenceNode);
+
+ var idx = iters.length - 1;
+
+ // "If the node is root or is not an inclusive ancestor of the
+ // referenceNode attribute value, terminate these steps."
+ //
+ // We also have to rule out the case where node is an ancestor of
+ // root, which is implicitly handled by the spec since such a node
+ // was not part of the iterator collection to start with.
+ if (isInclusiveAncestor(node, root)
+ || !isInclusiveAncestor(node, iter.referenceNode)) {
+ continue;
+ }
+
+ // "If the pointerBeforeReferenceNode attribute value is false, set
+ // the referenceNode attribute to the first node preceding the node
+ // that is being removed, and terminate these steps."
+ if (!iter.pointerBeforeReferenceNode) {
+ expectedReferenceNodes[idx] = previousNode(node);
+ continue;
+ }
+
+ // "If there is a node following the last inclusive descendant of the
+ // node that is being removed, set the referenceNode attribute to the
+ // first such node, and terminate these steps."
+ var next = nextNodeDescendants(node);
+ if (next) {
+ expectedReferenceNodes[idx] = next;
+ continue;
+ }
+
+ // "Set the referenceNode attribute to the first node preceding the
+ // node that is being removed and set the pointerBeforeReferenceNode
+ // attribute to false."
+ expectedReferenceNodes[idx] = previousNode(node);
+ expectedPointers[idx] = false;
+ }
+ }
+ }
+
+ var oldParent = node.parentNode;
+ var oldSibling = node.nextSibling;
+ oldParent.removeChild(node);
+
+ for (var j = 0; j < iters.length; j++) {
+ var iter = iters[j];
+ assert_equals(iter.referenceNode, expectedReferenceNodes[j],
+ ".referenceNode of " + descs[j]);
+ assert_equals(iter.pointerBeforeReferenceNode, expectedPointers[j],
+ ".pointerBeforeReferenceNode of " + descs[j]);
+ }
+
+ oldParent.insertBefore(node, oldSibling);
+ }, "Test removing node " + testNodes[i]);
+}
+
+testDiv.style.display = "none";
+</script>
diff --git a/testing/web-platform/tests/dom/traversal/NodeIterator.html b/testing/web-platform/tests/dom/traversal/NodeIterator.html
new file mode 100644
index 0000000000..fb81676cc5
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/NodeIterator.html
@@ -0,0 +1,215 @@
+<!doctype html>
+<title>NodeIterator tests</title>
+<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name>
+<meta name=timeout content=long>
+<div id=log></div>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=../common.js></script>
+<script>
+"use strict";
+
+function check_iter(iter, root, whatToShowValue) {
+ whatToShowValue = whatToShowValue === undefined ? 0xFFFFFFFF : whatToShowValue;
+
+ assert_equals(iter.toString(), '[object NodeIterator]', 'toString');
+ assert_equals(iter.root, root, 'root');
+ assert_equals(iter.whatToShow, whatToShowValue, 'whatToShow');
+ assert_equals(iter.filter, null, 'filter');
+ assert_equals(iter.referenceNode, root, 'referenceNode');
+ assert_equals(iter.pointerBeforeReferenceNode, true, 'pointerBeforeReferenceNode');
+ assert_readonly(iter, 'root');
+ assert_readonly(iter, 'whatToShow');
+ assert_readonly(iter, 'filter');
+ assert_readonly(iter, 'referenceNode');
+ assert_readonly(iter, 'pointerBeforeReferenceNode');
+}
+
+test(function() {
+ var iter = document.createNodeIterator(document);
+ iter.detach();
+ iter.detach();
+}, "detach() should be a no-op");
+
+test(function() {
+ var iter = document.createNodeIterator(document);
+ check_iter(iter, document);
+}, "createNodeIterator() parameter defaults");
+
+test(function() {
+ var iter = document.createNodeIterator(document, null, null);
+ check_iter(iter, document, 0);
+}, "createNodeIterator() with null as arguments");
+
+test(function() {
+ var iter = document.createNodeIterator(document, undefined, undefined);
+ check_iter(iter, document);
+}, "createNodeIterator() with undefined as arguments");
+
+test(function() {
+ var err = {name: "failed"};
+ var iter = document.createNodeIterator(document, NodeFilter.SHOW_ALL,
+ function() { throw err; });
+ assert_throws_exactly(err, function() { iter.nextNode() });
+}, "Propagate exception from filter function");
+
+test(function() {
+ var depth = 0;
+ var iter = document.createNodeIterator(document, NodeFilter.SHOW_ALL,
+ function() {
+ if (iter.referenceNode != document && depth == 0) {
+ depth++;
+ iter.nextNode();
+ }
+ return NodeFilter.FILTER_ACCEPT;
+ });
+ iter.nextNode();
+ iter.nextNode();
+ assert_throws_dom("InvalidStateError", function() { iter.nextNode() });
+ depth--;
+ assert_throws_dom("InvalidStateError", function() { iter.previousNode() });
+}, "Recursive filters need to throw");
+
+function testIterator(root, whatToShow, filter) {
+ var iter = document.createNodeIterator(root, whatToShow, filter);
+
+ assert_equals(iter.root, root, ".root");
+ assert_equals(iter.referenceNode, root, "Initial .referenceNode");
+ assert_equals(iter.pointerBeforeReferenceNode, true,
+ ".pointerBeforeReferenceNode");
+ assert_equals(iter.whatToShow, whatToShow, ".whatToShow");
+ assert_equals(iter.filter, filter, ".filter");
+
+ var expectedReferenceNode = root;
+ var expectedBeforeNode = true;
+ // "Let node be the value of the referenceNode attribute."
+ var node = root;
+ // "Let before node be the value of the pointerBeforeReferenceNode
+ // attribute."
+ var beforeNode = true;
+ var i = 1;
+ // Each loop iteration runs nextNode() once.
+ while (node) {
+ do {
+ if (!beforeNode) {
+ // "If before node is false, let node be the first node following node
+ // in the iterator collection. If there is no such node return null."
+ node = nextNode(node);
+ if (!isInclusiveDescendant(node, root)) {
+ node = null;
+ break;
+ }
+ } else {
+ // "If before node is true, set it to false."
+ beforeNode = false;
+ }
+ // "Filter node and let result be the return value.
+ //
+ // "If result is FILTER_ACCEPT, go to the next step in the overall set of
+ // steps.
+ //
+ // "Otherwise, run these substeps again."
+ if (!((1 << (node.nodeType - 1)) & whatToShow)
+ || (filter && filter(node) != NodeFilter.FILTER_ACCEPT)) {
+ continue;
+ }
+
+ // "Set the referenceNode attribute to node, set the
+ // pointerBeforeReferenceNode attribute to before node, and return node."
+ expectedReferenceNode = node;
+ expectedBeforeNode = beforeNode;
+
+ break;
+ } while (true);
+
+ assert_equals(iter.nextNode(), node, ".nextNode() " + i + " time(s)");
+ assert_equals(iter.referenceNode, expectedReferenceNode,
+ ".referenceNode after nextNode() " + i + " time(s)");
+ assert_equals(iter.pointerBeforeReferenceNode, expectedBeforeNode,
+ ".pointerBeforeReferenceNode after nextNode() " + i + " time(s)");
+
+ i++;
+ }
+
+ // Same but for previousNode() (mostly copy-pasted, oh well)
+ var iter = document.createNodeIterator(root, whatToShow, filter);
+
+ var expectedReferenceNode = root;
+ var expectedBeforeNode = true;
+ // "Let node be the value of the referenceNode attribute."
+ var node = root;
+ // "Let before node be the value of the pointerBeforeReferenceNode
+ // attribute."
+ var beforeNode = true;
+ var i = 1;
+ // Each loop iteration runs previousNode() once.
+ while (node) {
+ do {
+ if (beforeNode) {
+ // "If before node is true, let node be the first node preceding node
+ // in the iterator collection. If there is no such node return null."
+ node = previousNode(node);
+ if (!isInclusiveDescendant(node, root)) {
+ node = null;
+ break;
+ }
+ } else {
+ // "If before node is false, set it to true."
+ beforeNode = true;
+ }
+ // "Filter node and let result be the return value.
+ //
+ // "If result is FILTER_ACCEPT, go to the next step in the overall set of
+ // steps.
+ //
+ // "Otherwise, run these substeps again."
+ if (!((1 << (node.nodeType - 1)) & whatToShow)
+ || (filter && filter(node) != NodeFilter.FILTER_ACCEPT)) {
+ continue;
+ }
+
+ // "Set the referenceNode attribute to node, set the
+ // pointerBeforeReferenceNode attribute to before node, and return node."
+ expectedReferenceNode = node;
+ expectedBeforeNode = beforeNode;
+
+ break;
+ } while (true);
+
+ assert_equals(iter.previousNode(), node, ".previousNode() " + i + " time(s)");
+ assert_equals(iter.referenceNode, expectedReferenceNode,
+ ".referenceNode after previousNode() " + i + " time(s)");
+ assert_equals(iter.pointerBeforeReferenceNode, expectedBeforeNode,
+ ".pointerBeforeReferenceNode after previousNode() " + i + " time(s)");
+
+ i++;
+ }
+}
+
+var whatToShows = [
+ "0",
+ "0xFFFFFFFF",
+ "NodeFilter.SHOW_ELEMENT",
+ "NodeFilter.SHOW_ATTRIBUTE",
+ "NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_DOCUMENT",
+];
+
+var callbacks = [
+ "null",
+ "(function(node) { return true })",
+ "(function(node) { return false })",
+ "(function(node) { return node.nodeName[0] == '#' })",
+];
+
+for (var i = 0; i < testNodes.length; i++) {
+ for (var j = 0; j < whatToShows.length; j++) {
+ for (var k = 0; k < callbacks.length; k++) {
+ test(() => {
+ testIterator(eval(testNodes[i]), eval(whatToShows[j]), eval(callbacks[k]));
+ }, "document.createNodeIterator(" + testNodes[i] + ", " + whatToShows[j] + ", " + callbacks[k] + ")");
+ }
+ }
+}
+
+testDiv.style.display = "none";
+</script>
diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter-cross-realm-null-browsing-context.html b/testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter-cross-realm-null-browsing-context.html
new file mode 100644
index 0000000000..f8e71bcdf5
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter-cross-realm-null-browsing-context.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TreeWalker: NodeFilter from detached iframe doesn't get called</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<div></div>
+
+<script>
+const t = async_test();
+
+const iframe = document.createElement("iframe");
+iframe.src = "support/TreeWalker-acceptNode-filter-cross-realm-null-browsing-context-subframe.html";
+iframe.onload = t.step_func_done(() => {
+ const nodeIterator = iframe.contentWindow.createNodeIterator();
+ iframe.remove();
+
+ assert_equals(iframe.contentWindow, null);
+
+ let errorWasThrown = false;
+ try { nodeIterator.nextNode(); }
+ catch { errorWasThrown = true; }
+
+ assert_true(errorWasThrown);
+ assert_false(nodeIterator.dummyFilterCalled);
+});
+
+document.body.append(iframe);
+</script>
diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter-cross-realm.html b/testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter-cross-realm.html
new file mode 100644
index 0000000000..da91cf6cb2
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter-cross-realm.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>TreeWalker: cross-realm NodeFilter throws TypeError of its associated Realm</title>
+<link rel="help" href="https://webidl.spec.whatwg.org/#ref-for-prepare-to-run-script">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<iframe name="nodeFilterGlobalObject" src="support/empty-document.html"></iframe>
+
+<div id="treeWalkerRoot">
+ <div class="firstChild"></div>
+</div>
+
+<script>
+test_onload(() => {
+ const nodeFilter = new nodeFilterGlobalObject.Object;
+
+ const walker = document.createTreeWalker(treeWalkerRoot, NodeFilter.SHOW_ELEMENT, nodeFilter);
+ assert_throws_js(nodeFilterGlobalObject.TypeError, () => { walker.firstChild(); });
+}, "NodeFilter is cross-realm plain object without 'acceptNode' property");
+
+test_onload(() => {
+ const nodeFilter = new nodeFilterGlobalObject.Object;
+ nodeFilter.acceptNode = {};
+
+ const walker = document.createTreeWalker(treeWalkerRoot, NodeFilter.SHOW_ELEMENT, nodeFilter);
+ assert_throws_js(nodeFilterGlobalObject.TypeError, () => { walker.firstChild(); });
+}, "NodeFilter is cross-realm plain object with non-callable 'acceptNode' property");
+
+test_onload(() => {
+ const { proxy, revoke } = Proxy.revocable(() => {}, {});
+ revoke();
+
+ const nodeFilter = new nodeFilterGlobalObject.Object;
+ nodeFilter.acceptNode = proxy;
+
+ const walker = document.createTreeWalker(treeWalkerRoot, NodeFilter.SHOW_ELEMENT, nodeFilter);
+ assert_throws_js(nodeFilterGlobalObject.TypeError, () => { walker.firstChild(); });
+}, "NodeFilter is cross-realm plain object with revoked Proxy as 'acceptNode' property");
+
+test_onload(() => {
+ const { proxy, revoke } = nodeFilterGlobalObject.Proxy.revocable({}, {});
+ revoke();
+
+ const walker = document.createTreeWalker(treeWalkerRoot, NodeFilter.SHOW_ELEMENT, proxy);
+ assert_throws_js(nodeFilterGlobalObject.TypeError, () => { walker.firstChild(); });
+}, "NodeFilter is cross-realm non-callable revoked Proxy");
+
+test_onload(() => {
+ const { proxy, revoke } = nodeFilterGlobalObject.Proxy.revocable(() => {}, {});
+ revoke();
+
+ const walker = document.createTreeWalker(treeWalkerRoot, NodeFilter.SHOW_ELEMENT, proxy);
+ assert_throws_js(nodeFilterGlobalObject.TypeError, () => { walker.firstChild(); });
+}, "NodeFilter is cross-realm callable revoked Proxy");
+
+function test_onload(fn, desc) {
+ async_test(t => { window.addEventListener("load", t.step_func_done(fn)); }, desc);
+}
+</script>
diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter.html b/testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter.html
new file mode 100644
index 0000000000..282dc9d142
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter.html
@@ -0,0 +1,195 @@
+<!DOCTYPE html>
+<html>
+<!--
+Test adapted from chromium/source/src/third_party/WebKit/LayoutTests/fast/dom/TreeWalker/script-tests/acceptNode-filter.js
+-->
+<head>
+<title>TreeWalker: acceptNode-filter</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/assert-node.js"></script>
+<link rel="help" href="https://dom.spec.whatwg.org/#callbackdef-nodefilter">
+<div id=log></div>
+</head>
+<body>
+<p>Test JS objects as NodeFilters</p>
+<script>
+var testElement;
+setup(function() {
+ testElement = document.createElement("div");
+ testElement.id = 'root';
+ //testElement.innerHTML='<div id="A1"><div id="B1"></div><div id="B2"></div></div>';
+
+ // XXX for Servo, build the tree without using innerHTML
+ var a1 = document.createElement("div");
+ a1.id = "A1";
+ var b1 = document.createElement("div");
+ b1.id = "B1";
+ var b2 = document.createElement("div");
+ b2.id = "B2";
+ testElement.appendChild(a1);
+ a1.appendChild(b1);
+ a1.appendChild(b2);
+});
+
+test(function()
+{
+ function filter(node)
+ {
+ if (node.id == "B1")
+ return NodeFilter.FILTER_SKIP;
+ return NodeFilter.FILTER_ACCEPT;
+ }
+
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, filter);
+ assert_node(walker.currentNode, { type: Element, id: 'root' });
+ assert_node(walker.firstChild(), { type: Element, id: 'A1' });
+ assert_node(walker.currentNode, { type: Element, id: 'A1' });
+ assert_node(walker.nextNode(), { type: Element, id: 'B2' });
+ assert_node(walker.currentNode, { type: Element, id: 'B2' });
+}, 'Testing with raw function filter');
+
+test(function()
+{
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, {
+ acceptNode : function(node) {
+ if (node.id == "B1")
+ return NodeFilter.FILTER_SKIP;
+ return NodeFilter.FILTER_ACCEPT;
+ }
+ });
+ assert_node(walker.currentNode, { type: Element, id: 'root' });
+ assert_node(walker.firstChild(), { type: Element, id: 'A1' });
+ assert_node(walker.currentNode, { type: Element, id: 'A1' });
+ assert_node(walker.nextNode(), { type: Element, id: 'B2' });
+ assert_node(walker.currentNode, { type: Element, id: 'B2' });
+}, 'Testing with object filter');
+
+test(function()
+{
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, null);
+ assert_node(walker.currentNode, { type: Element, id: 'root' });
+ assert_node(walker.firstChild(), { type: Element, id: 'A1' });
+ assert_node(walker.currentNode, { type: Element, id: 'A1' });
+ assert_node(walker.nextNode(), { type: Element, id: 'B1' });
+ assert_node(walker.currentNode, { type: Element, id: 'B1' });
+}, 'Testing with null filter');
+
+test(function()
+{
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, undefined);
+ assert_node(walker.currentNode, { type: Element, id: 'root' });
+ assert_node(walker.firstChild(), { type: Element, id: 'A1' });
+ assert_node(walker.currentNode, { type: Element, id: 'A1' });
+ assert_node(walker.nextNode(), { type: Element, id: 'B1' });
+ assert_node(walker.currentNode, { type: Element, id: 'B1' });
+}, 'Testing with undefined filter');
+
+test(function()
+{
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, {});
+ assert_throws_js(TypeError, function () { walker.firstChild(); });
+ assert_node(walker.currentNode, { type: Element, id: 'root' });
+ assert_throws_js(TypeError, function () { walker.nextNode(); });
+ assert_node(walker.currentNode, { type: Element, id: 'root' });
+}, 'Testing with object lacking acceptNode property');
+
+test(function()
+{
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, { acceptNode: "foo" });
+ assert_throws_js(TypeError, function () { walker.firstChild(); });
+ assert_node(walker.currentNode, { type: Element, id: 'root' });
+ assert_throws_js(TypeError, function () { walker.nextNode(); });
+ assert_node(walker.currentNode, { type: Element, id: 'root' });
+}, 'Testing with object with non-function acceptNode property');
+
+test(function(t)
+{
+ var filter = function() { return NodeFilter.FILTER_ACCEPT; };
+ filter.acceptNode = t.unreached_func("`acceptNode` method should not be called on functions");
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, filter);
+ assert_node(walker.firstChild(), { type: Element, id: 'A1' });
+ assert_node(walker.nextNode(), { type: Element, id: 'B1' });
+}, 'Testing with function having acceptNode function');
+
+test(function()
+{
+ var test_error = { name: "test" };
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT,
+ function(node) {
+ throw test_error;
+ });
+ assert_throws_exactly(test_error, function () { walker.firstChild(); });
+ assert_node(walker.currentNode, { type: Element, id: 'root' });
+ assert_throws_exactly(test_error, function () { walker.nextNode(); });
+ assert_node(walker.currentNode, { type: Element, id: 'root' });
+}, 'Testing with filter function that throws');
+
+test(function() {
+ var testError = { name: "test" };
+ var filter = {
+ get acceptNode() {
+ throw testError;
+ },
+ };
+
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, filter);
+ assert_throws_exactly(testError, function() { walker.firstChild(); });
+ assert_node(walker.currentNode, { type: Element, id: 'root' });
+ assert_throws_exactly(testError, function() { walker.nextNode(); });
+ assert_node(walker.currentNode, { type: Element, id: 'root' });
+}, "rethrows errors when getting `acceptNode`");
+
+test(function() {
+ var calls = 0;
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, {
+ get acceptNode() {
+ calls++;
+ return function() {
+ return NodeFilter.FILTER_ACCEPT;
+ };
+ },
+ });
+
+ assert_equals(calls, 0);
+ walker.nextNode();
+ walker.nextNode();
+ assert_equals(calls, 2);
+}, "performs `Get` on every traverse");
+
+test(function()
+{
+ var test_error = { name: "test" };
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT,
+ {
+ acceptNode : function(node) {
+ throw test_error;
+ }
+ });
+ assert_throws_exactly(test_error, function () { walker.firstChild(); });
+ assert_node(walker.currentNode, { type: Element, id: 'root' });
+ assert_throws_exactly(test_error, function () { walker.nextNode(); });
+ assert_node(walker.currentNode, { type: Element, id: 'root' });
+}, 'Testing with filter object that throws');
+
+test(() =>
+{
+ let thisValue, nodeArgID;
+ const filter = {
+ acceptNode(node) {
+ thisValue = this;
+ nodeArgID = node.id;
+ return NodeFilter.FILTER_ACCEPT;
+ },
+ };
+
+ const walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, filter);
+ walker.nextNode();
+
+ assert_equals(thisValue, filter);
+ assert_equals(nodeArgID, 'A1');
+}, 'Testing with filter object: this value and `node` argument');
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-basic.html b/testing/web-platform/tests/dom/traversal/TreeWalker-basic.html
new file mode 100644
index 0000000000..bd8b112840
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/TreeWalker-basic.html
@@ -0,0 +1,154 @@
+<!DOCTYPE html>
+<html>
+<!--
+Test adapted from chromium/source/src/third_party/WebKit/LayoutTests/fast/dom/TreeWalker/TreeWalker-basic.html
+-->
+<head>
+<title>TreeWalker: Basic test</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/assert-node.js"></script>
+<div id=log></div>
+</head>
+<body>
+<p>This test checks the basic functionality of TreeWalker.</p>
+<script>
+function createSampleDOM()
+{
+ // Tree structure:
+ // #a
+ // |
+ // +----+----+
+ // | |
+ // "b" #c
+ // |
+ // +----+----+
+ // | |
+ // #d <!--j-->
+ // |
+ // +----+----+
+ // | | |
+ // "e" #f "i"
+ // |
+ // +--+--+
+ // | |
+ // "g" <!--h-->
+ var div = document.createElement('div');
+ div.id = 'a';
+ // div.innerHTML = 'b<div id="c"><div id="d">e<span id="f">g<!--h--></span>i</div><!--j--></div>';
+
+ div.appendChild(document.createTextNode("b"));
+
+ var c = document.createElement("div");
+ c.id = 'c';
+ div.appendChild(c);
+
+ var d = document.createElement("div");
+ d.id = 'd';
+ c.appendChild(d);
+
+ var e = document.createTextNode("e");
+ d.appendChild(e);
+
+ var f = document.createElement("span");
+ f.id = 'f';
+ d.appendChild(f);
+
+ var g = document.createTextNode("g");
+ f.appendChild(g);
+
+ var h = document.createComment("h");
+ f.appendChild(h);
+
+ var i = document.createTextNode("i");
+ d.appendChild(i);
+
+ var j = document.createComment("j");
+ c.appendChild(j);
+
+ return div;
+}
+
+function check_walker(walker, root, whatToShowValue)
+{
+ whatToShowValue = whatToShowValue === undefined ? 0xFFFFFFFF : whatToShowValue;
+
+ assert_equals(walker.toString(), '[object TreeWalker]', 'toString');
+ assert_equals(walker.root, root, 'root');
+ assert_equals(walker.whatToShow, whatToShowValue, 'whatToShow');
+ assert_equals(walker.filter, null, 'filter');
+ assert_equals(walker.currentNode, root, 'currentNode');
+ assert_readonly(walker, 'root');
+ assert_readonly(walker, 'whatToShow');
+ assert_readonly(walker, 'filter');
+}
+
+test(function ()
+{
+ var root = createSampleDOM();
+ var walker = document.createTreeWalker(root);
+ check_walker(walker, root);
+}, 'Construct a TreeWalker by document.createTreeWalker(root).');
+
+test(function ()
+{
+ var root = createSampleDOM();
+ var walker = document.createTreeWalker(root, null, null);
+ check_walker(walker, root, 0);
+}, 'Construct a TreeWalker by document.createTreeWalker(root, null, null).');
+
+test(function ()
+{
+ var root = createSampleDOM();
+ var walker = document.createTreeWalker(root, undefined, undefined);
+ check_walker(walker, root);
+}, 'Construct a TreeWalker by document.createTreeWalker(root, undefined, undefined).');
+
+test(function ()
+{
+ assert_throws_js(TypeError, function () { document.createTreeWalker(); });
+ assert_throws_js(TypeError, function () { document.createTreeWalker(null); });
+ assert_throws_js(TypeError, function () { document.createTreeWalker(undefined); });
+ assert_throws_js(TypeError, function () { document.createTreeWalker(new Object()); });
+ assert_throws_js(TypeError, function () { document.createTreeWalker(1); });
+}, 'Give an invalid root node to document.createTreeWalker().');
+
+test(function ()
+{
+ var root = createSampleDOM();
+ var walker = document.createTreeWalker(root);
+ var f = root.lastChild.firstChild.childNodes[1]; // An element node: div#f.
+
+ assert_node(walker.currentNode, { type: Element, id: 'a' });
+ assert_equals(walker.parentNode(), null);
+ assert_node(walker.currentNode, { type: Element, id: 'a' });
+ assert_node(walker.firstChild(), { type: Text, nodeValue: 'b' });
+ assert_node(walker.currentNode, { type: Text, nodeValue: 'b' });
+ assert_node(walker.nextSibling(), { type: Element, id: 'c' });
+ assert_node(walker.currentNode, { type: Element, id: 'c' });
+ assert_node(walker.lastChild(), { type: Comment, nodeValue: 'j' });
+ assert_node(walker.currentNode, { type: Comment, nodeValue: 'j' });
+ assert_node(walker.previousSibling(), { type: Element, id: 'd' });
+ assert_node(walker.currentNode, { type: Element, id: 'd' });
+ assert_node(walker.nextNode(), { type: Text, nodeValue: 'e' });
+ assert_node(walker.currentNode, { type: Text, nodeValue: 'e' });
+ assert_node(walker.parentNode(), { type: Element, id: 'd' });
+ assert_node(walker.currentNode, { type: Element, id: 'd' });
+ assert_node(walker.previousNode(), { type: Element, id: 'c' });
+ assert_node(walker.currentNode, { type: Element, id: 'c' });
+ assert_equals(walker.nextSibling(), null);
+ assert_node(walker.currentNode, { type: Element, id: 'c' });
+ walker.currentNode = f;
+ assert_equals(walker.currentNode, f);
+}, 'Walk over nodes.');
+
+test(function() {
+ var treeWalker = document.createTreeWalker(document.body, 42, null);
+ assert_equals(treeWalker.root, document.body);
+ assert_equals(treeWalker.currentNode, document.body);
+ assert_equals(treeWalker.whatToShow, 42);
+ assert_equals(treeWalker.filter, null);
+}, "Optional arguments to createTreeWalker should be optional (3 passed, null).");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-currentNode.html b/testing/web-platform/tests/dom/traversal/TreeWalker-currentNode.html
new file mode 100644
index 0000000000..f795abe0d2
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/TreeWalker-currentNode.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html>
+<!--
+Test adapted from chromium/source/src/third_party/WebKit/LayoutTests/fast/dom/TreeWalker/resources/TreeWalker-currentNode.js
+-->
+<head>
+<title>TreeWalker: currentNode</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/assert-node.js"></script>
+<div id=log></div>
+</head>
+<body>
+<div id='parent'>
+<div id='subTree'><p>Lorem ipsum <span>dolor <b>sit</b> amet</span>, consectetur <i>adipisicing</i> elit, sed do eiusmod <tt>tempor <b><i>incididunt ut</i> labore</b> et dolore magna</tt> aliqua.</p></div>
+</div>
+<p>Test TreeWalker currentNode functionality</p>
+<script>
+// var subTree = document.createElement('div');
+// subTree.innerHTML = "<p>Lorem ipsum <span>dolor <b>sit</b> amet</span>, consectetur <i>adipisicing</i> elit, sed do eiusmod <tt>tempor <b><i>incididunt ut</i> labore</b> et dolore magna</tt> aliqua.</p>"
+// document.body.appendChild(subTree);
+var subTree = document.getElementById("subTree");
+
+var all = function(node) { return true; }
+
+test(function()
+{
+ var w = document.createTreeWalker(subTree, NodeFilter.SHOW_ELEMENT, all);
+ assert_node(w.currentNode, { type: Element, id: 'subTree' });
+ assert_equals(w.parentNode(), null);
+ assert_node(w.currentNode, { type: Element, id: 'subTree' });
+}, "Test that TreeWalker.parent() doesn't set the currentNode to a node not under the root.");
+
+test(function()
+{
+ var w = document.createTreeWalker(subTree,
+ NodeFilter.SHOW_ELEMENT
+ | NodeFilter.SHOW_COMMENT,
+ all);
+ w.currentNode = document.documentElement;
+ assert_equals(w.parentNode(), null);
+ assert_equals(w.currentNode, document.documentElement);
+ w.currentNode = document.documentElement;
+ assert_equals(w.nextNode(), document.documentElement.firstChild);
+ assert_equals(w.currentNode, document.documentElement.firstChild);
+ w.currentNode = document.documentElement;
+ assert_equals(w.previousNode(), null);
+ assert_equals(w.currentNode, document.documentElement);
+ w.currentNode = document.documentElement;
+ assert_equals(w.firstChild(), document.documentElement.firstChild);
+ assert_equals(w.currentNode, document.documentElement.firstChild);
+ w.currentNode = document.documentElement;
+ assert_equals(w.lastChild(), document.documentElement.lastChild);
+ assert_equals(w.currentNode, document.documentElement.lastChild);
+ w.currentNode = document.documentElement;
+ assert_equals(w.nextSibling(), null);
+ assert_equals(w.currentNode, document.documentElement);
+ w.currentNode = document.documentElement;
+ assert_equals(w.previousSibling(), null);
+ assert_equals(w.currentNode, document.documentElement);
+}, "Test that we handle setting the currentNode to arbitrary nodes not under the root element.");
+
+test(function()
+{
+ var w = document.createTreeWalker(subTree, NodeFilter.SHOW_ELEMENT, all);
+ w.currentNode = subTree.previousSibling;
+ assert_equals(w.nextNode(), subTree);
+ w.currentNode = document.getElementById("parent");
+ assert_equals(w.firstChild(), subTree);
+}, "Test how we handle the case when the traversed to node is within the root, but the currentElement is not.");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-previousNodeLastChildReject.html b/testing/web-platform/tests/dom/traversal/TreeWalker-previousNodeLastChildReject.html
new file mode 100644
index 0000000000..e24ca06e20
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/TreeWalker-previousNodeLastChildReject.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<html>
+<!--
+Test adapted from chromium/source/src/third_party/WebKit/LayoutTests/fast/dom/TreeWalker/script-tests/previousNodeLastChildReject.js
+-->
+<head>
+<title>TreeWalker: previousNodeLastChildReject</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/assert-node.js"></script>
+<div id=log></div>
+</head>
+<body>
+<p>Test that previousNode properly respects the filter.</p>
+<script>
+var testElement;
+setup(function() {
+ testElement = document.createElement("div");
+ testElement.id = 'root';
+ // testElement.innerHTML='<div id="A1"><div id="B1"><div id="C1"></div><div id="C2"><div id="D1"></div><div id="D2"></div></div></div><div id="B2"><div id="C3"></div><div id="C4"></div></div></div>';
+ // testElement.innerHTML='
+ // <div id="A1">
+ // <div id="B1">
+ // <div id="C1">
+ // </div>
+ // <div id="C2">
+ // <div id="D1">
+ // </div>
+ // <div id="D2">
+ // </div>
+ // </div>
+ // </div>
+ // <div id="B2">
+ // <div id="C3">
+ // </div>
+ // <div id="C4">
+ // </div>
+ // </div>
+ // </div>';
+
+ // XXX for Servo, build the tree without using innerHTML
+ var a1 = document.createElement("div"); a1.id = "A1";
+ var b1 = document.createElement("div"); b1.id = "B1";
+ var b2 = document.createElement("div"); b2.id = "B2";
+ var c1 = document.createElement("div"); c1.id = "C1";
+ var c2 = document.createElement("div"); c2.id = "C2";
+ var c3 = document.createElement("div"); c3.id = "C3";
+ var c4 = document.createElement("div"); c4.id = "C4";
+ var d1 = document.createElement("div"); d1.id = "D1";
+ var d2 = document.createElement("div"); d2.id = "D2";
+
+ testElement.appendChild(a1);
+ a1.appendChild(b1);
+ a1.appendChild(b2);
+ b1.appendChild(c1);
+ b1.appendChild(c2);
+ b2.appendChild(c3);
+ b2.appendChild(c4);
+ c2.appendChild(d1);
+ c2.appendChild(d2);
+});
+
+test(function()
+{
+ function filter(node)
+ {
+ if (node.id == "C2")
+ return NodeFilter.FILTER_REJECT;
+ return NodeFilter.FILTER_ACCEPT;
+ }
+
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, filter);
+ assert_node(walker.currentNode, { type: Element, id: 'root' });
+ assert_node(walker.firstChild(), { type: Element, id: 'A1' });
+ assert_node(walker.currentNode, { type: Element, id: 'A1' });
+ assert_node(walker.nextNode(), { type: Element, id: 'B1' });
+ assert_node(walker.currentNode, { type: Element, id: 'B1' });
+ assert_node(walker.nextNode(), { type: Element, id: 'C1' });
+ assert_node(walker.currentNode, { type: Element, id: 'C1' });
+ assert_node(walker.nextNode(), { type: Element, id: 'B2' });
+ assert_node(walker.currentNode, { type: Element, id: 'B2' });
+ assert_node(walker.previousNode(), { type: Element, id: 'C1' });
+ assert_node(walker.currentNode, { type: Element, id: 'C1' });
+}, 'Test that previousNode properly respects the filter.');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-previousSiblingLastChildSkip.html b/testing/web-platform/tests/dom/traversal/TreeWalker-previousSiblingLastChildSkip.html
new file mode 100644
index 0000000000..5e28aa5142
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/TreeWalker-previousSiblingLastChildSkip.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html>
+<!--
+Test adapted from chromium/source/src/third_party/WebKit/LayoutTests/fast/dom/TreeWalker/script-tests/previousSiblingLastChildSkip.js
+-->
+<head>
+<title>TreeWalker: previousSiblingLastChildSkip</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/assert-node.js"></script>
+<div id=log></div>
+</head>
+<body>
+<p>Test that previousSibling properly respects the filter.</p>
+<script>
+var testElement;
+setup(function() {
+ testElement = document.createElement("div");
+ testElement.id = 'root';
+ // testElement.innerHTML='<div id="A1"><div id="B1"><div id="C1"></div><div id="C2"><div id="D1"></div><div id="D2"></div></div></div><div id="B2"><div id="C3"></div><div id="C4"></div></div></div>';
+ // testElement.innerHTML='
+ // <div id="A1">
+ // <div id="B1">
+ // <div id="C1">
+ // </div>
+ // <div id="C2">
+ // <div id="D1">
+ // </div>
+ // <div id="D2">
+ // </div>
+ // </div>
+ // </div>
+ // <div id="B2">
+ // <div id="C3">
+ // </div>
+ // <div id="C4">
+ // </div>
+ // </div>
+ // </div>';
+
+ // XXX for Servo, build the tree without using innerHTML
+ var a1 = document.createElement("div"); a1.id = "A1";
+ var b1 = document.createElement("div"); b1.id = "B1";
+ var b2 = document.createElement("div"); b2.id = "B2";
+ var c1 = document.createElement("div"); c1.id = "C1";
+ var c2 = document.createElement("div"); c2.id = "C2";
+ var c3 = document.createElement("div"); c3.id = "C3";
+ var c4 = document.createElement("div"); c4.id = "C4";
+ var d1 = document.createElement("div"); d1.id = "D1";
+ var d2 = document.createElement("div"); d2.id = "D2";
+
+ testElement.appendChild(a1);
+ a1.appendChild(b1);
+ a1.appendChild(b2);
+ b1.appendChild(c1);
+ b1.appendChild(c2);
+ b2.appendChild(c3);
+ b2.appendChild(c4);
+ c2.appendChild(d1);
+ c2.appendChild(d2);
+});
+
+test(function()
+{
+ function filter(node)
+ {
+ if (node.id == "B1")
+ return NodeFilter.FILTER_SKIP;
+ return NodeFilter.FILTER_ACCEPT;
+ }
+
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, filter);
+ assert_node(walker.currentNode, { type: Element, id: 'root' });
+ assert_node(walker.firstChild(), { type: Element, id: 'A1' });
+ assert_node(walker.currentNode, { type: Element, id: 'A1' });
+ assert_node(walker.nextNode(), { type: Element, id: 'C1' });
+ assert_node(walker.currentNode, { type: Element, id: 'C1' });
+ assert_node(walker.nextNode(), { type: Element, id: 'C2' });
+ assert_node(walker.currentNode, { type: Element, id: 'C2' });
+ assert_node(walker.nextNode(), { type: Element, id: 'D1' });
+ assert_node(walker.currentNode, { type: Element, id: 'D1' });
+ assert_node(walker.nextNode(), { type: Element, id: 'D2' });
+ assert_node(walker.currentNode, { type: Element, id: 'D2' });
+ assert_node(walker.nextNode(), { type: Element, id: 'B2' });
+ assert_node(walker.currentNode, { type: Element, id: 'B2' });
+ assert_node(walker.previousSibling(), { type: Element, id: 'C2' });
+ assert_node(walker.currentNode, { type: Element, id: 'C2' });
+}, 'Test that previousSibling properly respects the filter.');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-traversal-reject.html b/testing/web-platform/tests/dom/traversal/TreeWalker-traversal-reject.html
new file mode 100644
index 0000000000..d6c96adc11
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/TreeWalker-traversal-reject.html
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<html>
+<!--
+Test adapted from chromium/source/src/third_party/WebKit/LayoutTests/fast/dom/TreeWalker/script-tests/traversal-reject.js
+-->
+<head>
+<title>TreeWalker: traversal-reject</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/assert-node.js"></script>
+<div id=log></div>
+</head>
+<body>
+<p>Test TreeWalker with rejection</p>
+<script>
+var testElement;
+setup(function() {
+ testElement = document.createElement("div");
+ testElement.id = 'root';
+ //testElement.innerHTML='<div id="A1"> <div id="B1"> <div id="C1"></div> </div> <div id="B2"></div><div id="B3"></div> </div>';
+ // <div id="A1">
+ // <div id="B1">
+ // <div id="C1"></div>
+ // </div>
+ // <div id="B2"></div>
+ // <div id="B3"></div>
+ // </div>
+
+
+ // XXX for Servo, build the tree without using innerHTML
+ var a1 = document.createElement("div"); a1.id = "A1";
+ var b1 = document.createElement("div"); b1.id = "B1";
+ var b2 = document.createElement("div"); b2.id = "B2";
+ var b3 = document.createElement("div"); b3.id = "B3";
+ var c1 = document.createElement("div"); c1.id = "C1";
+
+ testElement.appendChild(a1);
+ a1.appendChild(b1);
+ a1.appendChild(b2);
+ a1.appendChild(b3);
+ b1.appendChild(c1);
+});
+
+var rejectB1Filter = {
+ acceptNode: function(node) {
+ if (node.id == 'B1')
+ return NodeFilter.FILTER_REJECT;
+
+ return NodeFilter.FILTER_ACCEPT;
+ }
+}
+
+var skipB2Filter = {
+ acceptNode: function(node) {
+ if (node.id == 'B2')
+ return NodeFilter.FILTER_SKIP;
+
+ return NodeFilter.FILTER_ACCEPT;
+ }
+}
+
+test(function()
+{
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, rejectB1Filter);
+ assert_node(walker.nextNode(), { type: Element, id: 'A1' });
+ assert_node(walker.nextNode(), { type: Element, id: 'B2' });
+ assert_node(walker.nextNode(), { type: Element, id: 'B3' });
+}, 'Testing nextNode');
+
+test(function()
+{
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, rejectB1Filter);
+ assert_node(walker.firstChild(), { type: Element, id: 'A1' });
+ assert_node(walker.firstChild(), { type: Element, id: 'B2' });
+}, 'Testing firstChild');
+
+test(function()
+{
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, skipB2Filter);
+ assert_node(walker.firstChild(), { type: Element, id: 'A1' });
+ assert_node(walker.firstChild(), { type: Element, id: 'B1' });
+ assert_node(walker.nextSibling(), { type: Element, id: 'B3' });
+}, 'Testing nextSibling');
+
+test(function()
+{
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, rejectB1Filter);
+ walker.currentNode = testElement.querySelectorAll('#C1')[0];
+ assert_node(walker.parentNode(), { type: Element, id: 'A1' });
+}, 'Testing parentNode');
+
+test(function()
+{
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, skipB2Filter);
+ walker.currentNode = testElement.querySelectorAll('#B3')[0];
+ assert_node(walker.previousSibling(), { type: Element, id: 'B1' });
+}, 'Testing previousSibling');
+
+test(function()
+{
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, rejectB1Filter);
+ walker.currentNode = testElement.querySelectorAll('#B3')[0];
+ assert_node(walker.previousNode(), { type: Element, id: 'B2' });
+ assert_node(walker.previousNode(), { type: Element, id: 'A1' });
+}, 'Testing previousNode');
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-traversal-skip-most.html b/testing/web-platform/tests/dom/traversal/TreeWalker-traversal-skip-most.html
new file mode 100644
index 0000000000..b6eafd4596
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/TreeWalker-traversal-skip-most.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html>
+<!--
+Test adapted from chromium/source/src/third_party/WebKit/LayoutTests/fast/dom/TreeWalker/script-tests/traversal-skip-most.js
+-->
+<head>
+<title>TreeWalker: traversal-skip-most</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/assert-node.js"></script>
+<div id=log></div>
+</head>
+<body>
+<p>Test TreeWalker with skipping</p>
+<script>
+var testElement;
+setup(function() {
+ testElement = document.createElement("div");
+ testElement.id = 'root';
+ // testElement.innerHTML='<div id="A1"><div id="B1" class="keep"></div><div id="B2">this text matters</div><div id="B3" class="keep"></div></div>';
+ // <div id="A1">
+ // <div id="B1" class="keep"></div>
+ // <div id="B2">this text matters</div>
+ // <div id="B3" class="keep"></div>
+ // </div>
+
+
+ // XXX for Servo, build the tree without using innerHTML
+ var a1 = document.createElement("div"); a1.id = "A1";
+ var b1 = document.createElement("div"); b1.id = "B1"; b1.className = "keep";
+ var b2 = document.createElement("div"); b2.id = "B2";
+ var b3 = document.createElement("div"); b3.id = "B3"; b3.className = "keep";
+
+ testElement.appendChild(a1);
+ a1.appendChild(b1);
+ a1.appendChild(b2)
+ .appendChild(document.createTextNode("this text matters"));
+ a1.appendChild(b3);
+});
+
+var filter = {
+ acceptNode: function(node) {
+ if (node.className == 'keep')
+ return NodeFilter.FILTER_ACCEPT;
+
+ return NodeFilter.FILTER_SKIP;
+ }
+}
+
+test(function()
+{
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, filter);
+ assert_node(walker.firstChild(), { type: Element, id: 'B1' });
+ assert_node(walker.nextSibling(), { type: Element, id: 'B3' });
+}, 'Testing nextSibling');
+
+test(function()
+{
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, filter);
+ walker.currentNode = testElement.querySelectorAll('#B3')[0];
+ assert_node(walker.previousSibling(), { type: Element, id: 'B1' });
+}, 'Testing previousSibling');
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-traversal-skip.html b/testing/web-platform/tests/dom/traversal/TreeWalker-traversal-skip.html
new file mode 100644
index 0000000000..6bbebe667e
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/TreeWalker-traversal-skip.html
@@ -0,0 +1,111 @@
+<!DOCTYPE html>
+<html>
+<!--
+Test adapted from chromium/source/src/third_party/WebKit/LayoutTests/fast/dom/TreeWalker/script-tests/traversal-skip.js
+-->
+<head>
+<title>TreeWalker: traversal-skip</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/assert-node.js"></script>
+<div id=log></div>
+</head>
+<body>
+<p>Test TreeWalker with skipping</p>
+<script>
+var testElement;
+setup(function() {
+ testElement = document.createElement("div");
+ testElement.id = 'root';
+ // testElement.innerHTML='<div id="A1"> <div id="B1"> <div id="C1"></div> </div> <div id="B2"></div><div id="B3"></div> </div>';
+ // <div id="A1">
+ // <div id="B1">
+ // <div id="C1"></div>
+ // </div>
+ // <div id="B2"></div>
+ // <div id="B3"></div>
+ // </div>
+
+
+ // XXX for Servo, build the tree without using innerHTML
+ var a1 = document.createElement("div"); a1.id = "A1";
+ var b1 = document.createElement("div"); b1.id = "B1";
+ var b2 = document.createElement("div"); b2.id = "B2";
+ var b3 = document.createElement("div"); b3.id = "B3";
+ var c1 = document.createElement("div"); c1.id = "C1";
+
+ testElement.appendChild(a1);
+ a1.appendChild(b1);
+ a1.appendChild(b2);
+ a1.appendChild(b3);
+ b1.appendChild(c1);
+});
+
+var skipB1Filter = {
+ acceptNode: function(node) {
+ if (node.id == 'B1')
+ return NodeFilter.FILTER_SKIP;
+
+ return NodeFilter.FILTER_ACCEPT;
+ }
+}
+
+var skipB2Filter = {
+ acceptNode: function(node) {
+ if (node.id == 'B2')
+ return NodeFilter.FILTER_SKIP;
+
+ return NodeFilter.FILTER_ACCEPT;
+ }
+}
+
+test(function()
+{
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, skipB1Filter);
+ assert_node(walker.nextNode(), { type: Element, id: 'A1' });
+ assert_node(walker.nextNode(), { type: Element, id: 'C1' });
+ assert_node(walker.nextNode(), { type: Element, id: 'B2' });
+ assert_node(walker.nextNode(), { type: Element, id: 'B3' });
+}, 'Testing nextNode');
+
+test(function()
+{
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, skipB1Filter);
+ assert_node(walker.firstChild(), { type: Element, id: 'A1' });
+ assert_node(walker.firstChild(), { type: Element, id: 'C1' });
+}, 'Testing firstChild');
+
+test(function()
+{
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, skipB2Filter);
+ assert_node(walker.firstChild(), { type: Element, id: 'A1' });
+ assert_node(walker.firstChild(), { type: Element, id: 'B1' });
+ assert_node(walker.nextSibling(), { type: Element, id: 'B3' });
+}, 'Testing nextSibling');
+
+test(function()
+{
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, skipB1Filter);
+ walker.currentNode = testElement.querySelectorAll('#C1')[0];
+ assert_node(walker.parentNode(), { type: Element, id: 'A1' });
+}, 'Testing parentNode');
+
+test(function()
+{
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, skipB2Filter);
+ walker.currentNode = testElement.querySelectorAll('#B3')[0];
+ assert_node(walker.previousSibling(), { type: Element, id: 'B1' });
+}, 'Testing previousSibling');
+
+test(function()
+{
+ var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, skipB1Filter);
+ walker.currentNode = testElement.querySelectorAll('#B3')[0];
+ assert_node(walker.previousNode(), { type: Element, id: 'B2' });
+ assert_node(walker.previousNode(), { type: Element, id: 'C1' });
+ assert_node(walker.previousNode(), { type: Element, id: 'A1' });
+}, 'Testing previousNode');
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-walking-outside-a-tree.html b/testing/web-platform/tests/dom/traversal/TreeWalker-walking-outside-a-tree.html
new file mode 100644
index 0000000000..b99e33e01f
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/TreeWalker-walking-outside-a-tree.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+<!--
+Test adapted from https://github.com/operasoftware/presto-testo/blob/master/core/standards/acid3/individual/006a.html
+-->
+<head>
+<title>TreeWalker: walking-outside-a-tree</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/assert-node.js"></script>
+<div id=log></div>
+</head>
+<body>
+<p>[Acid3 - Test 006a] walking outside a tree</p>
+<script>
+test(function () {
+ // test 6: walking outside a tree
+ var doc = document.createElement("div");
+ var head = document.createElement('head');
+ var title = document.createElement('title');
+ var body = document.createElement('body');
+ var p = document.createElement('p');
+ doc.appendChild(head);
+ head.appendChild(title);
+ doc.appendChild(body);
+ body.appendChild(p);
+
+ var w = document.createTreeWalker(body, 0xFFFFFFFF, null);
+ doc.removeChild(body);
+ assert_equals(w.lastChild(), p, "TreeWalker failed after removing the current node from the tree");
+ doc.appendChild(p);
+ assert_equals(w.previousNode(), title, "failed to handle regrafting correctly");
+ p.appendChild(body);
+ assert_equals(w.nextNode(), p, "couldn't retrace steps");
+ assert_equals(w.nextNode(), body, "couldn't step back into root");
+ assert_equals(w.previousNode(), null, "root didn't retake its rootish position");
+}, "walking outside a tree");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker.html b/testing/web-platform/tests/dom/traversal/TreeWalker.html
new file mode 100644
index 0000000000..093c781447
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/TreeWalker.html
@@ -0,0 +1,324 @@
+<!doctype html>
+<title>TreeWalker tests</title>
+<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name>
+<meta name=timeout content=long>
+<div id=log></div>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=../common.js></script>
+<script>
+"use strict";
+
+// TODO .previousNode, .nextNode
+
+test(function() {
+ var depth = 0;
+ var walker = document.createTreeWalker(document, NodeFilter.SHOW_ALL,
+ function() {
+ if (depth == 0) {
+ depth++;
+ walker.firstChild();
+ }
+ return NodeFilter.FILTER_ACCEPT;
+ });
+ walker.currentNode = document.body;
+ assert_throws_dom("InvalidStateError", function() { walker.parentNode() });
+ depth--;
+ assert_throws_dom("InvalidStateError", function() { walker.firstChild() });
+ depth--;
+ assert_throws_dom("InvalidStateError", function() { walker.lastChild() });
+ depth--;
+ assert_throws_dom("InvalidStateError", function() { walker.previousSibling() });
+ depth--;
+ assert_throws_dom("InvalidStateError", function() { walker.nextSibling() });
+ depth--;
+ assert_throws_dom("InvalidStateError", function() { walker.previousNode() });
+ depth--;
+ assert_throws_dom("InvalidStateError", function() { walker.nextNode() });
+}, "Recursive filters need to throw");
+
+function filterNode(node, whatToShow, filter) {
+ // "If active flag is set throw an "InvalidStateError"."
+ // Ignore active flag for these tests, we aren't calling recursively
+ // TODO Test me
+
+ // "Let n be node's nodeType attribute value minus 1."
+ var n = node.nodeType - 1;
+
+ // "If the nth bit (where 0 is the least significant bit) of whatToShow is
+ // not set, return FILTER_SKIP."
+ if (!(whatToShow & (1 << n))) {
+ return NodeFilter.FILTER_SKIP;
+ }
+
+ // "If filter is null, return FILTER_ACCEPT."
+ if (!filter) {
+ return NodeFilter.FILTER_ACCEPT;
+ }
+
+ // "Set the active flag."
+ //
+ // "Let result be the return value of invoking filter."
+ //
+ // "Unset the active flag."
+ //
+ // "If an exception was thrown, re-throw the exception."
+ // TODO Test me
+ //
+ // "Return result."
+ return filter(node);
+}
+
+function testTraverseChildren(type, walker, root, whatToShow, filter) {
+ // TODO We don't test .currentNode other than the root
+ walker.currentNode = root;
+ assert_equals(walker.currentNode, root, "Setting .currentNode");
+
+ var expectedReturn = null;
+ var expectedCurrentNode = root;
+
+ // "To traverse children of type type, run these steps:
+ //
+ // "Let node be the value of the currentNode attribute."
+ var node = walker.currentNode;
+
+ // "Set node to node's first child if type is first, and node's last child
+ // if type is last."
+ node = type == "first" ? node.firstChild : node.lastChild;
+
+ // "Main: While node is not null, run these substeps:"
+ while (node) {
+ // "Filter node and let result be the return value."
+ var result = filterNode(node, whatToShow, filter);
+
+ // "If result is FILTER_ACCEPT, then set the currentNode attribute to
+ // node and return node."
+ if (result == NodeFilter.FILTER_ACCEPT) {
+ expectedCurrentNode = expectedReturn = node;
+ break;
+ }
+
+ // "If result is FILTER_SKIP, run these subsubsteps:"
+ if (result == NodeFilter.FILTER_SKIP) {
+ // "Let child be node's first child if type is first, and node's
+ // last child if type is last."
+ var child = type == "first" ? node.firstChild : node.lastChild;
+
+ // "If child is not null, set node to child and goto Main."
+ if (child) {
+ node = child;
+ continue;
+ }
+ }
+
+ // "While node is not null, run these subsubsteps:"
+ while (node) {
+ // "Let sibling be node's next sibling if type is first, and node's
+ // previous sibling if type is last."
+ var sibling = type == "first" ? node.nextSibling
+ : node.previousSibling;
+
+ // "If sibling is not null, set node to sibling and goto Main."
+ if (sibling) {
+ node = sibling;
+ break;
+ }
+
+ // "Let parent be node's parent."
+ var parent = node.parentNode;
+
+ // "If parent is null, parent is root, or parent is currentNode
+ // attribute's value, return null."
+ if (!parent || parent == root || parent == walker.currentNode) {
+ expectedReturn = node = null;
+ break;
+ } else {
+ // "Otherwise, set node to parent."
+ node = parent;
+ }
+ }
+ }
+
+ if (type == "first") {
+ assert_equals(walker.firstChild(), expectedReturn, ".firstChild()");
+ assert_equals(walker.currentNode, expectedCurrentNode,
+ ".currentNode after .firstChild()");
+ } else {
+ assert_equals(walker.lastChild(), expectedReturn, ".lastChild()");
+ assert_equals(walker.currentNode, expectedCurrentNode,
+ ".currentNode after .lastChild()");
+ }
+}
+
+function testTraverseSiblings(type, walker, root, whatToShow, filter) {
+ // TODO We don't test .currentNode other than the root's first or last child
+ if (!root.firstChild) {
+ // Nothing much to test
+
+ walker.currentNode = root;
+ assert_equals(walker.currentNode, root, "Setting .currentNode");
+
+ if (type == "next") {
+ assert_equals(walker.nextSibling(), null, ".nextSibling()");
+ assert_equals(walker.currentNode, root,
+ ".currentNode after .nextSibling()")
+ } else {
+ assert_equals(walker.previousSibling(), null, ".previousSibling()");
+ assert_equals(walker.currentNode, root,
+ ".currentNode after .previousSibling()")
+ }
+ return;
+ }
+
+ if (type == "next") {
+ walker.currentNode = root.firstChild;
+ assert_equals(walker.currentNode, root.firstChild,
+ "Setting .currentNode");
+ } else {
+ walker.currentNode = root.lastChild;
+ assert_equals(walker.currentNode, root.lastChild,
+ "Setting .currentNode");
+ }
+
+ var expectedReturn = null;
+ var expectedCurrentNode = type == "next" ? root.firstChild : root.lastChild;
+
+ // "To traverse siblings of type type run these steps:"
+ (function() {
+ // "Let node be the value of the currentNode attribute."
+ var node = type == "next" ? root.firstChild : root.lastChild;
+
+ // "If node is root, return null.
+ //
+ // "Run these substeps:
+ do {
+ // "Let sibling be node's next sibling if type is next, and node's
+ // previous sibling if type is previous."
+ var sibling = type == "next" ? node.nextSibling :
+ node.previousSibling;
+
+ // "While sibling is not null, run these subsubsteps:"
+ while (sibling) {
+ // "Set node to sibling."
+ node = sibling;
+
+ // "Filter node and let result be the return value."
+ var result = filterNode(node, whatToShow, filter);
+
+ // "If result is FILTER_ACCEPT, then set the currentNode
+ // attribute to node and return node."
+ if (result == NodeFilter.FILTER_ACCEPT) {
+ expectedCurrentNode = expectedReturn = node;
+ return;
+ }
+
+ // "Set sibling to node's first child if type is next, and
+ // node's last child if type is previous."
+ sibling = type == "next" ? node.firstChild : node.lastChild;
+
+ // "If result is FILTER_REJECT or sibling is null, then set
+ // sibling to node's next sibling if type is next, and node's
+ // previous sibling if type is previous."
+ if (result == NodeFilter.FILTER_REJECT || !sibling) {
+ sibling = type == "next" ? node.nextSibling :
+ node.previousSibling;
+ }
+ }
+
+ // "Set node to its parent."
+ node = node.parentNode;
+
+ // "If node is null or is root, return null.
+ if (!node || node == root) {
+ return;
+ }
+ // "Filter node and if the return value is FILTER_ACCEPT, then
+ // return null."
+ if (filterNode(node, whatToShow, filter)) {
+ return;
+ }
+
+ // "Run these substeps again."
+ } while (true);
+ })();
+
+ if (type == "next") {
+ assert_equals(walker.nextSibling(), expectedReturn, ".nextSibling()");
+ assert_equals(walker.currentNode, expectedCurrentNode,
+ ".currentNode after .nextSibling()");
+ } else {
+ assert_equals(walker.previousSibling(), expectedReturn, ".previousSibling()");
+ assert_equals(walker.currentNode, expectedCurrentNode,
+ ".currentNode after .previousSibling()");
+ }
+}
+
+function testWalker(root, whatToShow, filter) {
+ var walker = document.createTreeWalker(root, whatToShow, filter);
+
+ assert_equals(walker.root, root, ".root");
+ assert_equals(walker.whatToShow, whatToShow, ".whatToShow");
+ assert_equals(walker.filter, filter, ".filter");
+ assert_equals(walker.currentNode, root, ".currentNode");
+
+ var expectedReturn = null;
+ var expectedCurrentNode = walker.currentNode;
+ // "The parentNode() method must run these steps:"
+ //
+ // "Let node be the value of the currentNode attribute."
+ var node = walker.currentNode;
+
+ // "While node is not null and is not root, run these substeps:"
+ while (node && node != root) {
+ // "Let node be node's parent."
+ node = node.parentNode;
+
+ // "If node is not null and filtering node returns FILTER_ACCEPT, then
+ // set the currentNode attribute to node, return node."
+ if (node && filterNode(node, whatToShow, filter) ==
+ NodeFilter.FILTER_ACCEPT) {
+ expectedCurrentNode = expectedReturn = node;
+ }
+ }
+ assert_equals(walker.parentNode(), expectedReturn, ".parentNode()");
+ assert_equals(walker.currentNode, expectedCurrentNode,
+ ".currentNode after .parentNode()");
+
+ testTraverseChildren("first", walker, root, whatToShow, filter);
+ testTraverseChildren("last", walker, root, whatToShow, filter);
+
+ testTraverseSiblings("next", walker, root, whatToShow, filter);
+ testTraverseSiblings("previous", walker, root, whatToShow, filter);
+}
+
+var whatToShows = [
+ "0",
+ "0xFFFFFFFF",
+ "NodeFilter.SHOW_ELEMENT",
+ "NodeFilter.SHOW_ATTRIBUTE",
+ "NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_DOCUMENT",
+];
+
+var callbacks = [
+ "null",
+ "(function(node) { return true })",
+ "(function(node) { return false })",
+ "(function(node) { return node.nodeName[0] == '#' })",
+];
+
+var tests = [];
+for (var i = 0; i < testNodes.length; i++) {
+ for (var j = 0; j < whatToShows.length; j++) {
+ for (var k = 0; k < callbacks.length; k++) {
+ tests.push([
+ "document.createTreeWalker(" + testNodes[i] +
+ ", " + whatToShows[j] + ", " + callbacks[k] + ")",
+ eval(testNodes[i]), eval(whatToShows[j]), eval(callbacks[k])
+ ]);
+ }
+ }
+}
+generate_tests(testWalker, tests);
+
+testDiv.style.display = "none";
+</script>
diff --git a/testing/web-platform/tests/dom/traversal/support/TreeWalker-acceptNode-filter-cross-realm-null-browsing-context-subframe.html b/testing/web-platform/tests/dom/traversal/support/TreeWalker-acceptNode-filter-cross-realm-null-browsing-context-subframe.html
new file mode 100644
index 0000000000..f5e393d0f0
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/support/TreeWalker-acceptNode-filter-cross-realm-null-browsing-context-subframe.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+
+<script>
+function createNodeIterator() {
+ function filter() {
+ nodeIterator.dummyFilterCalled = true;
+ return true;
+ }
+ const nodeIterator = parent.document.createNodeIterator(parent.document.body, NodeFilter.SHOW_ELEMENT, filter);
+ nodeIterator.dummyFilterCalled = false;
+ return nodeIterator;
+}
+</script>
diff --git a/testing/web-platform/tests/dom/traversal/support/assert-node.js b/testing/web-platform/tests/dom/traversal/support/assert-node.js
new file mode 100644
index 0000000000..0d5d8ad74f
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/support/assert-node.js
@@ -0,0 +1,10 @@
+// |expected| should be an object indicating the expected type of node.
+function assert_node(actual, expected)
+{
+ assert_true(actual instanceof expected.type,
+ 'Node type mismatch: actual = ' + actual.nodeType + ', expected = ' + expected.nodeType);
+ if (typeof(expected.id) !== 'undefined')
+ assert_equals(actual.id, expected.id);
+ if (typeof(expected.nodeValue) !== 'undefined')
+ assert_equals(actual.nodeValue, expected.nodeValue);
+}
diff --git a/testing/web-platform/tests/dom/traversal/support/empty-document.html b/testing/web-platform/tests/dom/traversal/support/empty-document.html
new file mode 100644
index 0000000000..b9cd130a07
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/support/empty-document.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<body>
diff --git a/testing/web-platform/tests/dom/traversal/unfinished/001.xml b/testing/web-platform/tests/dom/traversal/unfinished/001.xml
new file mode 100644
index 0000000000..08bce72fcf
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/unfinished/001.xml
@@ -0,0 +1,53 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>DOM Traversal: NodeIterator: Basics</title>
+ <script type="text/javascript"> <![CDATA[
+ function doTest() {
+ var iterator = document.createNodeIterator(document, NodeFilter.SHOW_ALL, null, false);
+ var expected = new Array(9, // document
+ 1, // html
+ 3, 1, // head
+ 3, 1, 3, // title
+ 3, 1, 3, 4, // script and CDATA block
+ 3, 3, 1, // body
+ 3, 1, 3, // pre
+ 3, // </body>
+ 3, 8, // <!-- -->
+ 3, 7, // <? ?>,
+ 3, 4, 3); // CDATA
+ var found = new Array();
+
+ // walk document
+ var node;
+ while (node = iterator.nextNode())
+ found.push(node.nodeType);
+
+ // check results
+ var errors = 0;
+ var s = '';
+ var length = (found.length > expected.length) ? found.length : expected.length;
+ s += 'EXPECTED FOUND\n';
+ for (var i = 0; i < length; i += 1) {
+ s += ' ' + (expected[i] ? expected[i] : '-') +
+ ' ' + (found[i] ? found[i] : '-');
+ if (found[i] != expected[i]) {
+ s += ' MISMATCH';
+ errors += 1;
+ }
+ s += '\n';
+ }
+ var p = document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'pre')[0];
+ if (errors)
+ p.firstChild.data = 'FAIL: ' + errors + ' errors found:\n\n' + s;
+ else
+ p.firstChild.data = 'PASS';
+ }
+ ]]></script>
+ </head>
+ <body onload="doTest()">
+ <pre id="result">FAIL: Script failed to run.</pre>
+ </body>
+ <!-- some more nodes to test this: -->
+ <?test node?>
+ <![CDATA[]]>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/dom/traversal/unfinished/002.xml b/testing/web-platform/tests/dom/traversal/unfinished/002.xml
new file mode 100644
index 0000000000..bf3489688c
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/unfinished/002.xml
@@ -0,0 +1,54 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>DOM Traversal: NodeIterator: Basics Backwards</title>
+ <script type="text/javascript"> <![CDATA[
+ function doTest() {
+ var iterator = document.createNodeIterator(document, NodeFilter.SHOW_ALL, null, false);
+ var expected = new Array(9, // document
+ 1, // html
+ 3, 1, // head
+ 3, 1, 3, // title
+ 3, 1, 3, 4, // script and CDATA block
+ 3, 3, 1, // body
+ 3, 1, 3, // pre
+ 3, // </body>
+ 3, 8, // <!-- -->
+ 3, 7, // <? ?>,
+ 3, 4, 3); // CDATA
+ var found = new Array();
+
+ // walk document
+ var node;
+ while (node = iterator.nextNode());
+ while (node = iterator.previousNode())
+ found.unshift(node.nodeType);
+
+ // check results
+ var errors = 0;
+ var s = '';
+ var length = (found.length > expected.length) ? found.length : expected.length;
+ s += 'EXPECTED FOUND\n';
+ for (var i = 0; i < length; i += 1) {
+ s += ' ' + (expected[i] ? expected[i] : '-') +
+ ' ' + (found[i] ? found[i] : '-');
+ if (found[i] != expected[i]) {
+ s += ' MISMATCH';
+ errors += 1;
+ }
+ s += '\n';
+ }
+ var p = document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'pre')[0];
+ if (errors)
+ p.firstChild.data = 'FAIL: ' + errors + ' errors found:\n\n' + s;
+ else
+ p.firstChild.data = 'PASS';
+ }
+ ]]></script>
+ </head>
+ <body onload="doTest()">
+ <pre id="result">FAIL: Script failed to run.</pre>
+ </body>
+ <!-- some more nodes to test this: -->
+ <?test node?>
+ <![CDATA[]]>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/dom/traversal/unfinished/003.xml b/testing/web-platform/tests/dom/traversal/unfinished/003.xml
new file mode 100644
index 0000000000..268e6bb4d7
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/unfinished/003.xml
@@ -0,0 +1,58 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>DOM Traversal: NodeIterator: Removal of nodes that should have no effect</title>
+ <!--
+ This tests these cases that should have no effect:
+ 1. Remove a node unrelated to the reference node
+ 2. Remove an ancestor of the root node
+ 3. Remove the root node itself
+ 4. Remove descendant of reference node
+ -->
+ <script type="text/javascript"> <![CDATA[
+ var errors = 0;
+ var log = '';
+ function doTest() {
+ var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false);
+ var root = document.getElementById('root');
+ var A = document.getElementById('A');
+ var B = document.getElementById('B');
+ var C = document.getElementById('C');
+ var D = document.getElementById('D');
+ var E = document.getElementById('E');
+ check(iterator.nextNode(), root);
+ remove(document.getElementById('X'));
+ check(iterator.nextNode(), A);
+ remove(document.getElementById('Y'));
+ check(iterator.nextNode(), B);
+ remove(root);
+ check(iterator.nextNode(), C);
+ remove(E);
+ check(iterator.nextNode(), D);
+ if (errors)
+ document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log;
+ else
+ document.getElementById('result').firstChild.data = 'PASS';
+ }
+ function check(a, b) {
+ if (!a) {
+ errors += 1;
+ log += 'Found null but expected ' + b + ' (' + b.id + ').\n';
+ } else if (a != b) {
+ errors += 1;
+ log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n';
+ }
+ }
+ function remove(a) {
+ if (!a) {
+ errors += 1;
+ log += 'Tried removing null node.\n';
+ } else
+ a.parentNode.removeChild(a);
+ }
+ ]]></script>
+ </head>
+ <body onload="doTest()">
+ <pre id="result">FAIL: Script did not complete.</pre>
+ <p><span id="X"></span><span id="Y"><span id="root"><span id="A"><span id="B"><span id="C"><span id="D"><span id="E"></span></span></span></span></span></span></span></p>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/dom/traversal/unfinished/004.xml b/testing/web-platform/tests/dom/traversal/unfinished/004.xml
new file mode 100644
index 0000000000..618978f021
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/unfinished/004.xml
@@ -0,0 +1,49 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>DOM Traversal: NodeIterator: Removal of the Reference Node</title>
+ <script type="text/javascript"> <![CDATA[
+ var errors = 0;
+ var log = '';
+ function doTest() {
+ var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false);
+ var root = document.getElementById('root');
+ var A = document.getElementById('A');
+ var AA = document.getElementById('AA');
+ var B = document.getElementById('B');
+ var C = document.getElementById('C');
+ check(iterator.nextNode(), root);
+ check(iterator.nextNode(), A);
+ check(iterator.nextNode(), AA);
+ check(iterator.nextNode(), B);
+ remove(B);
+ check(iterator.previousNode(), AA);
+ remove(AA);
+ check(iterator.nextNode(), C);
+ if (errors)
+ document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log;
+ else
+ document.getElementById('result').firstChild.data = 'PASS';
+ }
+ function check(a, b) {
+ if (!a) {
+ errors += 1;
+ log += 'Found null but expected ' + b + ' (' + b.id + ').\n';
+ } else if (a != b) {
+ errors += 1;
+ log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n';
+ }
+ }
+ function remove(a) {
+ if (!a) {
+ errors += 1;
+ log += 'Tried removing null node.\n';
+ } else
+ a.parentNode.removeChild(a);
+ }
+ ]]></script>
+ </head>
+ <body onload="doTest()">
+ <pre id="result">FAIL: Script did not complete.</pre>
+ <p><span id="root"><span id="A"><span id="AA"></span></span><span id="B"></span><span id="C"><span id="CC"></span></span></span></p>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/dom/traversal/unfinished/005.xml b/testing/web-platform/tests/dom/traversal/unfinished/005.xml
new file mode 100644
index 0000000000..643e2f1cd4
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/unfinished/005.xml
@@ -0,0 +1,57 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>DOM Traversal: NodeIterator: Removal of the Reference Node (deep check)</title>
+ <script type="text/javascript"> <![CDATA[
+ var errors = 0;
+ var log = '';
+ function doTest() {
+ var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false);
+ var root = document.getElementById('root');
+ var A = document.getElementById('A');
+ var AA = document.getElementById('AA');
+ var B = document.getElementById('B');
+ var C = document.getElementById('C');
+ check(iterator.nextNode(), root);
+ check(iterator.nextNode(), A);
+ check(iterator.nextNode(), AA);
+ check(iterator.nextNode(), B);
+ remove(B);
+ var X = addChildTo(AA);
+ check(iterator.nextNode(), X);
+ check(iterator.previousNode(), X);
+ remove(X);
+ var Y = addChildTo(AA);
+ check(iterator.previousNode(), Y);
+ if (errors)
+ document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log;
+ else
+ document.getElementById('result').firstChild.data = 'PASS';
+ }
+ function check(a, b) {
+ if (!a) {
+ errors += 1;
+ log += 'Found null but expected ' + b + ' (' + b.id + ').\n';
+ } else if (a != b) {
+ errors += 1;
+ log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n';
+ }
+ }
+ function remove(a) {
+ if (!a) {
+ errors += 1;
+ log += 'Tried removing null node.\n';
+ } else
+ a.parentNode.removeChild(a);
+ }
+ function addChildTo(a) {
+ var x = document.createElementNS('http://www.w3.org/1999/xhtml', 'span');
+ a.appendChild(x);
+ return x;
+ }
+ ]]></script>
+ </head>
+ <body onload="doTest()">
+ <pre id="result">FAIL: Script did not complete.</pre>
+ <p><span id="root"><span id="A"><span id="AA"></span></span><span id="B"></span><span id="C"><span id="CC"></span></span></span></p>
+ </body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/dom/traversal/unfinished/006.xml b/testing/web-platform/tests/dom/traversal/unfinished/006.xml
new file mode 100644
index 0000000000..c2302af836
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/unfinished/006.xml
@@ -0,0 +1,47 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>DOM Traversal: NodeIterator: Removal of an ancestor of the Reference Node (forwards)</title>
+ <script type="text/javascript"> <![CDATA[
+ var errors = 0;
+ var log = '';
+ function doTest() {
+ var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false);
+ var root = document.getElementById('root');
+ var A = document.getElementById('A');
+ var B = document.getElementById('B');
+ var BB = document.getElementById('BB');
+ var C = document.getElementById('C');
+ check(iterator.nextNode(), root);
+ check(iterator.nextNode(), A);
+ check(iterator.nextNode(), B);
+ check(iterator.nextNode(), BB);
+ remove(B);
+ check(iterator.previousNode(), A);
+ if (errors)
+ document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log;
+ else
+ document.getElementById('result').firstChild.data = 'PASS';
+ }
+ function check(a, b) {
+ if (!a) {
+ errors += 1;
+ log += 'Found null but expected ' + b + ' (' + b.id + ').\n';
+ } else if (a != b) {
+ errors += 1;
+ log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n';
+ }
+ }
+ function remove(a) {
+ if (!a) {
+ errors += 1;
+ log += 'Tried removing null node.\n';
+ } else
+ a.parentNode.removeChild(a);
+ }
+ ]]></script>
+ </head>
+ <body onload="doTest()">
+ <pre id="result">FAIL: Script did not complete.</pre>
+ <p><span id="root"><span id="A"></span><span id="B"><span id="BB"></span></span><span id="C"></span></span></p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/dom/traversal/unfinished/007.xml b/testing/web-platform/tests/dom/traversal/unfinished/007.xml
new file mode 100644
index 0000000000..98b212e4e5
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/unfinished/007.xml
@@ -0,0 +1,54 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>DOM Traversal: NodeIterator: Removal of an ancestor of the Reference Node (forwards) (deep check)</title>
+ <script type="text/javascript"> <![CDATA[
+ var errors = 0;
+ var log = '';
+ function doTest() {
+ var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false);
+ var root = document.getElementById('root');
+ var A = document.getElementById('A');
+ var B = document.getElementById('B');
+ var BB = document.getElementById('BB');
+ var C = document.getElementById('C');
+ check(iterator.nextNode(), root);
+ check(iterator.nextNode(), A);
+ check(iterator.nextNode(), B);
+ check(iterator.nextNode(), BB);
+ remove(B);
+ var X = addChildTo(A);
+ check(iterator.nextNode(), X);
+ if (errors)
+ document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log;
+ else
+ document.getElementById('result').firstChild.data = 'PASS';
+ }
+ function check(a, b) {
+ if (!a) {
+ errors += 1;
+ log += 'Found null but expected ' + b + ' (' + b.id + ').\n';
+ } else if (a != b) {
+ errors += 1;
+ log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n';
+ }
+ }
+ function remove(a) {
+ if (!a) {
+ errors += 1;
+ log += 'Tried removing null node.\n';
+ } else
+ a.parentNode.removeChild(a);
+ }
+ function addChildTo(a) {
+ var x = document.createElementNS('http://www.w3.org/1999/xhtml', 'span');
+ x.id = 'X';
+ a.appendChild(x);
+ return x;
+ }
+ ]]></script>
+ </head>
+ <body onload="doTest()">
+ <pre id="result">FAIL: Script did not complete.</pre>
+ <p><span id="root"><span id="A"></span><span id="B"><span id="BB"></span></span><span id="C"></span></span></p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/dom/traversal/unfinished/008.xml b/testing/web-platform/tests/dom/traversal/unfinished/008.xml
new file mode 100644
index 0000000000..41d7008ae4
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/unfinished/008.xml
@@ -0,0 +1,48 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>DOM Traversal: NodeIterator: Removal of an ancestor of the Reference Node (backwards)</title>
+ <script type="text/javascript"> <![CDATA[
+ var errors = 0;
+ var log = '';
+ function doTest() {
+ var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false);
+ var root = document.getElementById('root');
+ var A = document.getElementById('A');
+ var B = document.getElementById('B');
+ var BB = document.getElementById('BB');
+ var C = document.getElementById('C');
+ check(iterator.nextNode(), root);
+ check(iterator.nextNode(), A);
+ check(iterator.nextNode(), B);
+ check(iterator.nextNode(), BB);
+ check(iterator.previousNode(), BB);
+ remove(B);
+ check(iterator.nextNode(), C);
+ if (errors)
+ document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log;
+ else
+ document.getElementById('result').firstChild.data = 'PASS';
+ }
+ function check(a, b) {
+ if (!a) {
+ errors += 1;
+ log += 'Found null but expected ' + b + ' (' + b.id + ').\n';
+ } else if (a != b) {
+ errors += 1;
+ log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n';
+ }
+ }
+ function remove(a) {
+ if (!a) {
+ errors += 1;
+ log += 'Tried removing null node.\n';
+ } else
+ a.parentNode.removeChild(a);
+ }
+ ]]></script>
+ </head>
+ <body onload="doTest()">
+ <pre id="result">FAIL: Script did not complete.</pre>
+ <p><span id="root"><span id="A"></span><span id="B"><span id="BB"></span></span><span id="C"></span></span></p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/dom/traversal/unfinished/009.xml b/testing/web-platform/tests/dom/traversal/unfinished/009.xml
new file mode 100644
index 0000000000..c3006ecbd6
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/unfinished/009.xml
@@ -0,0 +1,55 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>DOM Traversal: NodeIterator: Removal of an ancestor of the Reference Node (backwards) (deep check)</title>
+ <script type="text/javascript"> <![CDATA[
+ var errors = 0;
+ var log = '';
+ function doTest() {
+ var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false);
+ var root = document.getElementById('root');
+ var A = document.getElementById('A');
+ var B = document.getElementById('B');
+ var BB = document.getElementById('BB');
+ var C = document.getElementById('C');
+ check(iterator.nextNode(), root);
+ check(iterator.nextNode(), A);
+ check(iterator.nextNode(), B);
+ check(iterator.nextNode(), BB);
+ check(iterator.previousNode(), BB);
+ remove(B);
+ var X = addChildTo(A);
+ check(iterator.previousNode(), X);
+ if (errors)
+ document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log;
+ else
+ document.getElementById('result').firstChild.data = 'PASS';
+ }
+ function check(a, b) {
+ if (!a) {
+ errors += 1;
+ log += 'Found null but expected ' + b + ' (' + b.id + ').\n';
+ } else if (a != b) {
+ errors += 1;
+ log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n';
+ }
+ }
+ function remove(a) {
+ if (!a) {
+ errors += 1;
+ log += 'Tried removing null node.\n';
+ } else
+ a.parentNode.removeChild(a);
+ }
+ function addChildTo(a) {
+ var x = document.createElementNS('http://www.w3.org/1999/xhtml', 'span');
+ x.id = 'X';
+ a.appendChild(x);
+ return x;
+ }
+ ]]></script>
+ </head>
+ <body onload="doTest()">
+ <pre id="result">FAIL: Script did not complete.</pre>
+ <p><span id="root"><span id="A"></span><span id="B"><span id="BB"></span></span><span id="C"></span></span></p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/dom/traversal/unfinished/010.xml b/testing/web-platform/tests/dom/traversal/unfinished/010.xml
new file mode 100644
index 0000000000..63263a5fd7
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/unfinished/010.xml
@@ -0,0 +1,64 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>DOM Traversal: NodeIterator: Filters</title>
+ <script type="text/javascript"> <![CDATA[
+ function doTest() {
+ var iterator = document.createNodeIterator(document, NodeFilter.SHOW_ALL, testFilter, false);
+ // skips text nodes and body element
+ var expected = new Array(9, // document
+ 1, // html
+ 1, // head
+ 1, // title
+ 1, 4, // script and CDATA block
+ // body (skipped)
+ 1, // pre
+ // </body>
+ 8, // <!-- -->
+ // PI skipped
+ 4); // CDATA
+ var found = new Array();
+
+ // walk document
+ var node;
+ while (node = iterator.nextNode())
+ found.push(node.nodeType);
+
+ // check results
+ var errors = 0;
+ var s = '';
+ var length = (found.length > expected.length) ? found.length : expected.length;
+ s += 'EXPECTED FOUND\n';
+ for (var i = 0; i < length; i += 1) {
+ s += ' ' + (expected[i] ? expected[i] : '-') +
+ ' ' + (found[i] ? found[i] : '-');
+ if (found[i] != expected[i]) {
+ s += ' MISMATCH';
+ errors += 1;
+ }
+ s += '\n';
+ }
+ var p = document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'pre')[0];
+ if (errors)
+ p.firstChild.data = 'FAIL: ' + errors + ' errors found:\n\n' + s;
+ else
+ p.firstChild.data = 'PASS';
+ }
+
+ function testFilter(n) {
+ if (n.nodeType == 3) {
+ return NodeFilter.FILTER_SKIP;
+ } else if (n.nodeName == 'body') {
+ return NodeFilter.FILTER_REJECT; // same as _SKIP
+ }
+ return 1; // FILTER_ACCEPT
+ }
+
+ ]]></script>
+ </head>
+ <body onload="doTest()">
+ <pre id="result">FAIL: Script failed to run.</pre>
+ </body>
+ <!-- some more nodes to test this: -->
+ <?body test?>
+ <![CDATA[]]>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/dom/traversal/unfinished/TODO b/testing/web-platform/tests/dom/traversal/unfinished/TODO
new file mode 100644
index 0000000000..cecdf98b08
--- /dev/null
+++ b/testing/web-platform/tests/dom/traversal/unfinished/TODO
@@ -0,0 +1 @@
+Check what happens when a NodeFilter turns a number not in the range 1..3 \ No newline at end of file