add wpt tests

This commit is contained in:
Pierre Tachoire
2023-12-15 11:06:53 +01:00
parent d7f8014d53
commit 923296426e
22 changed files with 955 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
<!DOCTYPE HTML>
<meta charset=utf8>
<title>Test for Element.closest</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body id="body">
<div id="test8" class="div3" style="display:none">
<div id="test7" class="div2">
<div id="test6" class="div1">
<form id="test10" class="form2"></form>
<form id="test5" class="form1" name="form-a">
<input id="test1" class="input1" required>
<fieldset class="fieldset2" id="test2">
<select id="test3" class="select1" required>
<option default id="test4" value="">Test4</option>
<option selected id="test11">Test11</option>
<option id="test12">Test12</option>
<option id="test13">Test13</option>
</select>
<input id="test9" type="text" required>
</fieldset>
</form>
</div>
</div>
</div>
<div id=log></div>
<script>
do_test("select" , "test12", "test3");
do_test("fieldset" , "test13", "test2");
do_test("div" , "test13", "test6");
do_test("body" , "test3" , "body");
do_test("[default]" , "test4" , "test4");
do_test("[selected]" , "test4" , "");
do_test("[selected]" , "test11", "test11");
do_test('[name="form-a"]' , "test12", "test5");
do_test('form[name="form-a"]' , "test13", "test5");
do_test("input[required]" , "test9" , "test9");
do_test("select[required]" , "test9" , "");
do_test("div:not(.div1)" , "test13", "test7");
do_test("div.div3" , "test6" , "test8");
do_test("div#test7" , "test1" , "test7");
do_test(".div3 > .div2" , "test12", "test7");
do_test(".div3 > .div1" , "test12", "");
do_test("form > input[required]" , "test9" , "");
do_test("fieldset > select[required]", "test12", "test3");
do_test("input + fieldset" , "test6" , "");
do_test("form + form" , "test3" , "test5");
do_test("form + form" , "test5" , "test5");
do_test(":empty" , "test10", "test10");
do_test(":last-child" , "test11", "test2");
do_test(":first-child" , "test12", "test3");
do_test(":invalid" , "test11", "test2");
do_test(":scope" , "test4", "test4");
do_test("select > :scope" , "test4", "test4");
do_test("div > :scope" , "test4", "");
do_test(":has(> :scope)" , "test4", "test3");
function do_test(aSelector, aElementId, aTargetId) {
test(function() {
var el = document.getElementById(aElementId).closest(aSelector);
if (el === null) {
assert_equals("", aTargetId, aSelector);
} else {
assert_equals(el.id, aTargetId, aSelector);
}
}, "Element.closest with context node '" + aElementId + "' and selector '" + aSelector + "'");
}
</script>

View File

@@ -0,0 +1,91 @@
<!doctype html>
<meta charset=utf-8>
<title></title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<div id="target"></div>
<div id="parent"><span id=target2></span></div>
<div id="log" style="visibility:visible"></div>
<span id="test1"></span>
<span id="test2"></span>
<span id="test3"></span>
<span id="test4"></span>
<script>
var target = document.getElementById("target");
var target2 = document.getElementById("target2");
test(function() {
assert_throws_dom("SyntaxError", function() {
target.insertAdjacentElement("test", document.getElementById("test1"))
});
assert_throws_dom("SyntaxError", function() {
target2.insertAdjacentElement("test", document.getElementById("test1"))
});
}, "Inserting to an invalid location should cause a Syntax Error exception")
test(function() {
var el = target.insertAdjacentElement("beforebegin", document.getElementById("test1"));
assert_equals(target.previousSibling.id, "test1");
assert_equals(el.id, "test1");
el = target2.insertAdjacentElement("beforebegin", document.getElementById("test1"));
assert_equals(target2.previousSibling.id, "test1");
assert_equals(el.id, "test1");
}, "Inserted element should be target element's previous sibling for 'beforebegin' case")
test(function() {
var el = target.insertAdjacentElement("afterbegin", document.getElementById("test2"));
assert_equals(target.firstChild.id, "test2");
assert_equals(el.id, "test2");
el = target2.insertAdjacentElement("afterbegin", document.getElementById("test2"));
assert_equals(target2.firstChild.id, "test2");
assert_equals(el.id, "test2");
}, "Inserted element should be target element's first child for 'afterbegin' case")
test(function() {
var el = target.insertAdjacentElement("beforeend", document.getElementById("test3"));
assert_equals(target.lastChild.id, "test3");
assert_equals(el.id, "test3");
el = target2.insertAdjacentElement("beforeend", document.getElementById("test3"));
assert_equals(target2.lastChild.id, "test3");
assert_equals(el.id, "test3");
}, "Inserted element should be target element's last child for 'beforeend' case")
test(function() {
var el = target.insertAdjacentElement("afterend", document.getElementById("test4"));
assert_equals(target.nextSibling.id, "test4");
assert_equals(el.id, "test4");
el = target2.insertAdjacentElement("afterend", document.getElementById("test4"));
assert_equals(target2.nextSibling.id, "test4");
assert_equals(el.id, "test4");
}, "Inserted element should be target element's next sibling for 'afterend' case")
test(function() {
var docElement = document.documentElement;
docElement.style.visibility="hidden";
assert_throws_dom("HierarchyRequestError", function() {
var el = docElement.insertAdjacentElement("beforebegin", document.getElementById("test1"));
assert_equals(el, null);
});
var el = docElement.insertAdjacentElement("afterbegin", document.getElementById("test2"));
assert_equals(docElement.firstChild.id, "test2");
assert_equals(el.id, "test2");
el = docElement.insertAdjacentElement("beforeend", document.getElementById("test3"));
assert_equals(docElement.lastChild.id, "test3");
assert_equals(el.id, "test3");
assert_throws_dom("HierarchyRequestError", function() {
var el = docElement.insertAdjacentElement("afterend", document.getElementById("test4"));
assert_equals(el, null);
});
}, "Adding more than one child to document should cause a HierarchyRequestError exception")
</script>

View File

@@ -0,0 +1,76 @@
<!doctype html>
<meta charset=utf-8>
<title></title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<body style="visibility:hidden">
<div id="target"></div>
<div id="parent"><span id=target2></span></div>
<div id="log" style="visibility:visible"></div>
</body>
<script>
var target = document.getElementById("target");
var target2 = document.getElementById("target2");
test(function() {
assert_throws_dom("SyntaxError", function() {
target.insertAdjacentText("test", "text")
});
assert_throws_dom("SyntaxError", function() {
target2.insertAdjacentText("test", "test")
});
}, "Inserting to an invalid location should cause a Syntax Error exception")
test(function() {
target.insertAdjacentText("beforebegin", "test1");
assert_equals(target.previousSibling.nodeValue, "test1");
target2.insertAdjacentText("beforebegin", "test1");
assert_equals(target2.previousSibling.nodeValue, "test1");
}, "Inserted text node should be target element's previous sibling for 'beforebegin' case")
test(function() {
target.insertAdjacentText("afterbegin", "test2");
assert_equals(target.firstChild.nodeValue, "test2");
target2.insertAdjacentText("afterbegin", "test2");
assert_equals(target2.firstChild.nodeValue, "test2");
}, "Inserted text node should be target element's first child for 'afterbegin' case")
test(function() {
target.insertAdjacentText("beforeend", "test3");
assert_equals(target.lastChild.nodeValue, "test3");
target2.insertAdjacentText("beforeend", "test3");
assert_equals(target2.lastChild.nodeValue, "test3");
}, "Inserted text node should be target element's last child for 'beforeend' case")
test(function() {
target.insertAdjacentText("afterend", "test4");
assert_equals(target.nextSibling.nodeValue, "test4");
target2.insertAdjacentText("afterend", "test4");
assert_equals(target.nextSibling.nodeValue, "test4");
}, "Inserted text node should be target element's next sibling for 'afterend' case")
test(function() {
var docElement = document.documentElement;
docElement.style.visibility="hidden";
assert_throws_dom("HierarchyRequestError", function() {
docElement.insertAdjacentText("beforebegin", "text1")
});
docElement.insertAdjacentText("afterbegin", "test2");
assert_equals(docElement.firstChild.nodeValue, "test2");
docElement.insertAdjacentText("beforeend", "test3");
assert_equals(docElement.lastChild.nodeValue, "test3");
assert_throws_dom("HierarchyRequestError", function() {
docElement.insertAdjacentText("afterend", "test4")
});
}, "Adding more than one child to document should cause a HierarchyRequestError exception")
</script>

View File

@@ -0,0 +1,65 @@
function init(e, method) {
/*
* This test suite tests Selectors API methods in 4 different contexts:
* 1. Document node
* 2. In-document Element node
* 3. Detached Element node (an element with no parent, not in the document)
* 4. Document Fragment node
*
* For each context, the following tests are run:
*
* The interface check tests ensure that each type of node exposes the Selectors API methods.
*
* The matches() tests are run
* All the selectors tested for both the valid and invalid selector tests are found in selectors.js.
* See comments in that file for documentation of the format used.
*
* The level2-lib.js file contains all the common test functions for running each of the aforementioned tests
*/
var docType = "html"; // Only run tests suitable for HTML
// Prepare the nodes for testing
var doc = e.target.contentDocument; // Document Node tests
var element = doc.getElementById("root"); // In-document Element Node tests
//Setup the namespace tests
setupSpecialElements(doc, element);
var outOfScope = element.cloneNode(true); // Append this to the body before running the in-document
// Element tests, but after running the Document tests. This
// tests that no elements that are not descendants of element
// are selected.
traverse(outOfScope, function(elem) { // Annotate each element as being a clone; used for verifying
elem.setAttribute("data-clone", ""); // that none of these elements ever match.
});
var detached = element.cloneNode(true); // Detached Element Node tests
var fragment = doc.createDocumentFragment(); // Fragment Node tests
fragment.appendChild(element.cloneNode(true));
// Setup Tests
interfaceCheckMatches(method, "Document", doc);
interfaceCheckMatches(method, "Detached Element", detached);
interfaceCheckMatches(method, "Fragment", fragment);
interfaceCheckMatches(method, "In-document Element", element);
runSpecialMatchesTests(method, "DIV Element", element);
runSpecialMatchesTests(method, "NULL Element", document.createElement("null"));
runSpecialMatchesTests(method, "UNDEFINED Element", document.createElement("undefined"));
runInvalidSelectorTestMatches(method, "Document", doc, invalidSelectors);
runInvalidSelectorTestMatches(method, "Detached Element", detached, invalidSelectors);
runInvalidSelectorTestMatches(method, "Fragment", fragment, invalidSelectors);
runInvalidSelectorTestMatches(method, "In-document Element", element, invalidSelectors);
runMatchesTest(method, "In-document", doc, validSelectors, "html");
runMatchesTest(method, "Detached", detached, validSelectors, "html");
runMatchesTest(method, "Fragment", fragment, validSelectors, "html");
runMatchesTest(method, "In-document", doc, scopedSelectors, "html");
}

View File

@@ -0,0 +1,24 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>matches/webkitMatchesSelector must work when an element has a namespace</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<!-- Regression tests for https://github.com/jsdom/jsdom/issues/1846, https://github.com/jsdom/jsdom/issues/2247 -->
<script>
"use strict";
for (const method of ["matches", "webkitMatchesSelector"]) {
test(() => {
assert_true(document.createElementNS("", "element")[method]("element"));
}, `empty string namespace, ${method}`);
test(() => {
assert_true(document.createElementNS("urn:ns", "h")[method]("h"));
}, `has a namespace, ${method}`);
test(() => {
assert_true(document.createElementNS("urn:ns", "h")[method]("*|h"));
}, `has a namespace, *|, ${method}`);
}
</script>

View File

@@ -0,0 +1,22 @@
<!DOCTYPE html>
<meta charset="UTF-8">
<title>Selectors-API Level 2 Test Suite: HTML with Selectors Level 3</title>
<!-- Selectors API Test Suite Version 3 -->
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/dom/nodes/selectors.js"></script>
<script src="/dom/nodes/ParentNode-querySelector-All.js"></script>
<script src="Element-matches.js"></script>
<script src="Element-matches-init.js"></script>
<style>iframe { visibility: hidden; position: absolute; }</style>
<div id="log">This test requires JavaScript.</div>
<script>
async_test(function() {
var frame = document.createElement("iframe");
frame.onload = this.step_func_done(e => init(e, "matches" ));
frame.src = "/dom/nodes/ParentNode-querySelector-All-content.html#target";
document.body.appendChild(frame);
});
</script>

View File

@@ -0,0 +1,135 @@
/*
* Check that the matches() method exists on the given Node
*/
function interfaceCheckMatches(method, type, obj) {
if (obj.nodeType === obj.ELEMENT_NODE) {
test(function() {
assert_idl_attribute(obj, method, type + " supports " + method);
}, type + " supports " + method)
} else {
test(function() {
assert_false(method in obj, type + " supports " + method);
}, type + " should not support " + method)
}
}
function runSpecialMatchesTests(method, type, element) {
test(function() { // 1
if (element.tagName.toLowerCase() === "null") {
assert_true(element[method](null), "An element with the tag name '" + element.tagName.toLowerCase() + "' should match.");
} else {
assert_false(element[method](null), "An element with the tag name '" + element.tagName.toLowerCase() + "' should not match.");
}
}, type + "." + method + "(null)")
test(function() { // 2
if (element.tagName.toLowerCase() === "undefined") {
assert_true(element[method](undefined), "An element with the tag name '" + element.tagName.toLowerCase() + "' should match.");
} else {
assert_false(element[method](undefined), "An element with the tag name '" + element.tagName.toLowerCase() + "' should not match.");
}
}, type + "." + method + "(undefined)")
test(function() { // 3
assert_throws_js(element.ownerDocument.defaultView.TypeError, function() {
element[method]();
}, "This should throw a TypeError.")
}, type + "." + method + " no parameter")
}
/*
* Execute queries with the specified invalid selectors for matches()
* Only run these tests when errors are expected. Don't run for valid selector tests.
*/
function runInvalidSelectorTestMatches(method, type, root, selectors) {
if (root.nodeType === root.ELEMENT_NODE) {
for (var i = 0; i < selectors.length; i++) {
var s = selectors[i];
var n = s["name"];
var q = s["selector"];
test(function() {
assert_throws_dom(
"SyntaxError",
root.ownerDocument.defaultView.DOMException,
function() {
root[method](q)
}
);
}, type + "." + method + ": " + n + ": " + q);
}
}
}
function runMatchesTest(method, type, root, selectors, docType) {
var nodeType = getNodeType(root);
for (var i = 0; i < selectors.length; i++) {
var s = selectors[i];
var n = s["name"];
var q = s["selector"];
var e = s["expect"];
var u = s["unexpected"];
var ctx = s["ctx"];
var ref = s["ref"];
if ((!s["exclude"] || (s["exclude"].indexOf(nodeType) === -1 && s["exclude"].indexOf(docType) === -1))
&& (s["testType"] & TEST_MATCH) ) {
if (ctx && !ref) {
test(function() {
var j, element, refNode;
for (j = 0; j < e.length; j++) {
element = root.querySelector("#" + e[j]);
refNode = root.querySelector(ctx);
assert_true(element[method](q, refNode), "The element #" + e[j] + " should match the selector.")
}
if (u) {
for (j = 0; j < u.length; j++) {
element = root.querySelector("#" + u[j]);
refNode = root.querySelector(ctx);
assert_false(element[method](q, refNode), "The element #" + u[j] + " should not match the selector.")
}
}
}, type + " Element." + method + ": " + n + " (with refNode Element): " + q);
}
if (ref) {
test(function() {
var j, element, refNodes;
for (j = 0; j < e.length; j++) {
element = root.querySelector("#" + e[j]);
refNodes = root.querySelectorAll(ref);
assert_true(element[method](q, refNodes), "The element #" + e[j] + " should match the selector.")
}
if (u) {
for (j = 0; j < u.length; j++) {
element = root.querySelector("#" + u[j]);
refNodes = root.querySelectorAll(ref);
assert_false(element[method](q, refNodes), "The element #" + u[j] + " should not match the selector.")
}
}
}, type + " Element." + method + ": " + n + " (with refNodes NodeList): " + q);
}
if (!ctx && !ref) {
test(function() {
for (var j = 0; j < e.length; j++) {
var element = root.querySelector("#" + e[j]);
assert_true(element[method](q), "The element #" + e[j] + " should match the selector.")
}
if (u) {
for (j = 0; j < u.length; j++) {
element = root.querySelector("#" + u[j]);
assert_false(element[method](q), "The element #" + u[j] + " should not match the selector.")
}
}
}, type + " Element." + method + ": " + n + " (with no refNodes): " + q);
}
}
}
}

View File

@@ -0,0 +1,16 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Element.remove</title>
<link rel=help href="https://dom.spec.whatwg.org/#dom-childnode-remove">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="ChildNode-remove.js"></script>
<div id=log></div>
<script>
var node, parentNode;
setup(function() {
node = document.createElement("div");
parentNode = document.createElement("div");
});
testRemove(node, parentNode, "element");
</script>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:h="http://www.w3.org/1999/xhtml"
version="1.1"
width="100%" height="100%" viewBox="0 0 400 400">
<title>Null test</title>
<h:script src="/resources/testharness.js"/>
<h:script src="/resources/testharnessreport.js"/>
<text x="200" y="40" font-size="25" fill="black" text-anchor="middle">Test of previousElementSibling and nextElementSibling returning null</text>
<text id="parentEl" x="200" y="70" font-size="20" fill="black" text-anchor="middle">The result of this test is <tspan id="first_element_child" font-weight="bold">unknown.</tspan></text>
<h:script><![CDATA[
test(function() {
var fec = document.getElementById("first_element_child");
assert_equals(fec.previousElementSibling, null)
assert_equals(fec.nextElementSibling, null)
})
]]></h:script>
</svg>

After

Width:  |  Height:  |  Size: 869 B

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Null Test</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<body>
<h1>Test of previousElementSibling and nextElementSibling returning null</h1>
<div id="log"></div>
<p id="parentEl">The result of this test is <span id="first_element_child" style="font-weight:bold;">unknown.</span></p>
<script><![CDATA[
test(function() {
var fec = document.getElementById("first_element_child");
assert_equals(fec.previousElementSibling, null)
assert_equals(fec.nextElementSibling, null)
})
]]></script>
</body>
</html>

View File

@@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<meta charset=utf-8>
<title>Null test</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<h1>Test of previousElementSibling and nextElementSibling returning null</h1>
<div id="log"></div>
<p id="parentEl">The result of this test is <span id="first_element_child" style="font-weight:bold;">unknown.</span></p>
<script>
test(function() {
var fec = document.getElementById("first_element_child");
assert_equals(fec.previousElementSibling, null)
assert_equals(fec.nextElementSibling, null)
})
</script>

View File

@@ -0,0 +1,57 @@
<!DOCTYPE html>
<title>Element.tagName</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
test(function() {
var HTMLNS = "http://www.w3.org/1999/xhtml"
assert_equals(document.createElementNS(HTMLNS, "I").tagName, "I")
assert_equals(document.createElementNS(HTMLNS, "i").tagName, "I")
assert_equals(document.createElementNS(HTMLNS, "x:b").tagName, "X:B")
}, "tagName should upper-case for HTML elements in HTML documents.")
test(function() {
var SVGNS = "http://www.w3.org/2000/svg"
assert_equals(document.createElementNS(SVGNS, "svg").tagName, "svg")
assert_equals(document.createElementNS(SVGNS, "SVG").tagName, "SVG")
assert_equals(document.createElementNS(SVGNS, "s:svg").tagName, "s:svg")
assert_equals(document.createElementNS(SVGNS, "s:SVG").tagName, "s:SVG")
assert_equals(document.createElementNS(SVGNS, "textPath").tagName, "textPath");
}, "tagName should not upper-case for SVG elements in HTML documents.")
test(() => {
const el2 = document.createElementNS("http://example.com/", "mixedCase");
assert_equals(el2.tagName, "mixedCase");
}, "tagName should not upper-case for other non-HTML namespaces");
test(function() {
if ("DOMParser" in window) {
var xmlel = new DOMParser()
.parseFromString('<div xmlns="http://www.w3.org/1999/xhtml">Test</div>', 'text/xml')
.documentElement;
assert_equals(xmlel.tagName, "div", "tagName should be lowercase in XML")
var htmlel = document.importNode(xmlel, true)
assert_equals(htmlel.tagName, "DIV", "tagName should be uppercase in HTML")
}
}, "tagName should be updated when changing ownerDocument")
test(function() {
var xmlel = document.implementation
.createDocument("http://www.w3.org/1999/xhtml", "div", null)
.documentElement;
assert_equals(xmlel.tagName, "div", "tagName should be lowercase in XML")
var htmlel = document.importNode(xmlel, true)
assert_equals(htmlel.tagName, "DIV", "tagName should be uppercase in HTML")
}, "tagName should be updated when changing ownerDocument (createDocument without prefix)")
test(function() {
var xmlel = document.implementation
.createDocument("http://www.w3.org/1999/xhtml", "foo:div", null)
.documentElement;
assert_equals(xmlel.tagName, "foo:div", "tagName should be lowercase in XML")
var htmlel = document.importNode(xmlel, true)
assert_equals(htmlel.tagName, "FOO:DIV", "tagName should be uppercase in HTML")
}, "tagName should be updated when changing ownerDocument (createDocument with prefix)")
</script>

View File

@@ -0,0 +1,22 @@
<!DOCTYPE html>
<meta charset="UTF-8">
<title>Selectors-API Level 2 Test Suite: HTML with Selectors Level 3</title>
<!-- Selectors API Test Suite Version 3 -->
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/dom/nodes/selectors.js"></script>
<script src="/dom/nodes/ParentNode-querySelector-All.js"></script>
<script src="Element-matches.js"></script>
<script src="Element-matches-init.js"></script>
<style>iframe { visibility: hidden; position: absolute; }</style>
<div id="log">This test requires JavaScript.</div>
<script>
async_test(function() {
var frame = document.createElement("iframe");
frame.onload = this.step_func_done(e => init(e, "webkitMatchesSelector" ));
frame.src = "/dom/nodes/ParentNode-querySelector-All-content.html#target";
document.body.appendChild(frame);
});
</script>

View File

@@ -0,0 +1,61 @@
<!doctype html>
<meta charset="utf-8">
<title>NodeList Iterable Test</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<p id="1"></p>
<p id="2"></p>
<p id="3"></p>
<p id="4"></p>
<p id="5"></p>
<div id="live"><b id="b1">1</b><b id="b2">2</b><b id="b3">3</b></div>
<script>
var paragraphs;
setup(function() {
paragraphs = document.querySelectorAll('p');
})
test(function() {
assert_true('length' in paragraphs);
}, 'NodeList has length method.');
test(function() {
assert_true('values' in paragraphs);
}, 'NodeList has values method.');
test(function() {
assert_true('entries' in paragraphs);
}, 'NodeList has entries method.');
test(function() {
assert_true('forEach' in paragraphs);
}, 'NodeList has forEach method.');
test(function() {
assert_true(Symbol.iterator in paragraphs);
}, 'NodeList has Symbol.iterator.');
test(function() {
var ids = "12345", idx=0;
for(var node of paragraphs){
assert_equals(node.getAttribute('id'), ids[idx++]);
}
}, 'NodeList is iterable via for-of loop.');
test(function() {
assert_array_equals(Object.keys(paragraphs), ['0', '1', '2', '3', '4']);
}, 'NodeList responds to Object.keys correctly');
test(function() {
var container = document.getElementById('live');
var nodeList = container.childNodes;
var ids = [];
for (var el of nodeList) {
ids.push(el.id);
assert_equals(el.localName, 'b');
if (ids.length < 3) {
var newEl = document.createElement('b');
newEl.id = 'after' + el.id;
container.appendChild(newEl);
}
}
assert_array_equals(ids, ['b1', 'b2', 'b3', 'afterb1', 'afterb2']);
}, 'live NodeLists are for-of iterable and update appropriately');
</script>

View File

@@ -0,0 +1,79 @@
function testNodeList(name, hooks) {
test(() => {
const nodes = {
root: document.createElement("div"),
div1: document.createElement("div"),
div2: document.createElement("div"),
p: document.createElement("p")
};
const list = nodes.root.childNodes;
hooks.initial(list, nodes);
nodes.root.appendChild(nodes.div1);
nodes.root.appendChild(nodes.p);
nodes.root.appendChild(nodes.div2);
hooks.afterInsertion(list, nodes);
nodes.root.removeChild(nodes.div1);
hooks.afterRemoval(list, nodes);
}, `NodeList live mutations: ${name}`);
}
testNodeList("NodeList.length", {
initial(list) {
assert_equals(list.length, 0);
},
afterInsertion(list) {
assert_equals(list.length, 3);
},
afterRemoval(list) {
assert_equals(list.length, 2);
}
});
testNodeList("NodeList.item(index)", {
initial(list) {
assert_equals(list.item(0), null);
},
afterInsertion(list, nodes) {
assert_equals(list.item(0), nodes.div1);
assert_equals(list.item(1), nodes.p);
assert_equals(list.item(2), nodes.div2);
},
afterRemoval(list, nodes) {
assert_equals(list.item(0), nodes.p);
assert_equals(list.item(1), nodes.div2);
}
});
testNodeList("NodeList[index]", {
initial(list) {
assert_equals(list[0], undefined);
},
afterInsertion(list, nodes) {
assert_equals(list[0], nodes.div1);
assert_equals(list[1], nodes.p);
assert_equals(list[2], nodes.div2);
},
afterRemoval(list, nodes) {
assert_equals(list[0], nodes.p);
assert_equals(list[1], nodes.div2);
}
});
testNodeList("NodeList ownPropertyNames", {
initial(list) {
assert_object_equals(Object.getOwnPropertyNames(list), []);
},
afterInsertion(list) {
assert_object_equals(Object.getOwnPropertyNames(list), ["0", "1", "2"]);
},
afterRemoval(list) {
assert_object_equals(Object.getOwnPropertyNames(list), ["0", "1"]);
}
});

View File

@@ -0,0 +1,22 @@
<!doctype html>
<meta charset="utf-8">
<meta name=timeout content=long>
<title>NodeList (static collection) "length" getter tampered</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<script src="support/NodeList-static-length-tampered.js"></script>
<script>
test(() => {
const nodeList = makeStaticNodeList(100);
for (var i = 0; i < 50; i++) {
if (i === 25)
Object.defineProperty(nodeList, "length", { get() { return 10; } });
assert_equals(indexOfNodeList(nodeList), i >= 25 ? -1 : 50);
}
});
</script>

View File

@@ -0,0 +1,22 @@
<!doctype html>
<meta charset="utf-8">
<meta name=timeout content=long>
<title>NodeList (static collection) "length" getter tampered</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<script src="support/NodeList-static-length-tampered.js"></script>
<script>
test(() => {
const nodeList = makeStaticNodeList(100);
for (var i = 0; i < 50; i++) {
if (i === 25)
Object.setPrototypeOf(nodeList, { get length() { return 10; } });
assert_equals(indexOfNodeList(nodeList), i >= 25 ? -1 : 50);
}
});
</script>

View File

@@ -0,0 +1,22 @@
<!doctype html>
<meta charset="utf-8">
<meta name=timeout content=long>
<title>NodeList (static collection) "length" getter tampered</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<script src="support/NodeList-static-length-tampered.js"></script>
<script>
test(() => {
const nodeList = makeStaticNodeList(100);
for (var i = 0; i < 50; i++) {
if (i === 25)
Object.defineProperty(NodeList.prototype, "length", { get() { return 10; } });
assert_equals(indexOfNodeList(nodeList), i >= 25 ? -1 : 50);
}
});
</script>

View File

@@ -0,0 +1,22 @@
<!doctype html>
<meta charset="utf-8">
<meta name=timeout content=long>
<title>NodeList (static collection) "length" getter tampered (Array.prototype.indexOf)</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<script src="support/NodeList-static-length-tampered.js"></script>
<script>
test(() => {
const nodeList = makeStaticNodeList(100);
for (var i = 0; i < 50; i++) {
if (i === 25)
Object.defineProperty(nodeList, "length", { get() { return 10; } });
assert_equals(arrayIndexOfNodeList(nodeList), i >= 25 ? -1 : 50);
}
});
</script>

View File

@@ -0,0 +1,22 @@
<!doctype html>
<meta charset="utf-8">
<meta name=timeout content=long>
<title>NodeList (static collection) "length" getter tampered (Array.prototype.indexOf)</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<script src="support/NodeList-static-length-tampered.js"></script>
<script>
test(() => {
const nodeList = makeStaticNodeList(100);
for (var i = 0; i < 50; i++) {
if (i === 25)
Object.setPrototypeOf(nodeList, { get length() { return 10; } });
assert_equals(arrayIndexOfNodeList(nodeList), i >= 25 ? -1 : 50);
}
});
</script>

View File

@@ -0,0 +1,22 @@
<!doctype html>
<meta charset="utf-8">
<meta name=timeout content=long>
<title>NodeList (static collection) "length" getter tampered (Array.prototype.indexOf)</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<script src="support/NodeList-static-length-tampered.js"></script>
<script>
test(() => {
const nodeList = makeStaticNodeList(100);
for (var i = 0; i < 50; i++) {
if (i === 25)
Object.defineProperty(NodeList.prototype, "length", { get() { return 10; } });
assert_equals(arrayIndexOfNodeList(nodeList), i >= 25 ? -1 : 50);
}
});
</script>

View File

@@ -0,0 +1,46 @@
"use strict";
function makeStaticNodeList(length) {
const fooRoot = document.createElement("div");
for (var i = 0; i < length; i++) {
const el = document.createElement("span");
el.className = "foo";
fooRoot.append(el);
}
document.body.append(fooRoot);
return fooRoot.querySelectorAll(".foo");
}
const indexOfNodeList = new Function("nodeList", `
const __cacheBust = ${Math.random()};
const el = nodeList[50];
let index = -1;
for (var i = 0; i < 1e5 / 2; i++) {
for (var j = 0; j < nodeList.length; j++) {
if (nodeList[j] === el) {
index = j;
break;
}
}
}
return index;
`);
const arrayIndexOfNodeList = new Function("nodeList", `
const __cacheBust = ${Math.random()};
const el = nodeList[50];
const {indexOf} = Array.prototype;
for (var i = 0; i < 1e5; i++) {
var index = indexOf.call(nodeList, el);
}
return index;
`);