summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/dom/collections
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/dom/collections')
-rw-r--r--testing/web-platform/tests/dom/collections/HTMLCollection-as-prototype.html29
-rw-r--r--testing/web-platform/tests/dom/collections/HTMLCollection-delete.html45
-rw-r--r--testing/web-platform/tests/dom/collections/HTMLCollection-empty-name.html65
-rw-r--r--testing/web-platform/tests/dom/collections/HTMLCollection-iterator.html45
-rw-r--r--testing/web-platform/tests/dom/collections/HTMLCollection-live-mutations.window.js93
-rw-r--r--testing/web-platform/tests/dom/collections/HTMLCollection-own-props.html109
-rw-r--r--testing/web-platform/tests/dom/collections/HTMLCollection-supported-property-indices.html179
-rw-r--r--testing/web-platform/tests/dom/collections/HTMLCollection-supported-property-names.html135
-rw-r--r--testing/web-platform/tests/dom/collections/domstringmap-supported-property-names.html54
-rw-r--r--testing/web-platform/tests/dom/collections/namednodemap-supported-property-names.html30
10 files changed, 784 insertions, 0 deletions
diff --git a/testing/web-platform/tests/dom/collections/HTMLCollection-as-prototype.html b/testing/web-platform/tests/dom/collections/HTMLCollection-as-prototype.html
new file mode 100644
index 0000000000..d572d35c04
--- /dev/null
+++ b/testing/web-platform/tests/dom/collections/HTMLCollection-as-prototype.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Objects whose prototype is an HTMLCollection</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+<script>
+test(function() {
+ var obj = Object.create(document.getElementsByTagName("script"));
+ assert_throws_js(TypeError, function() {
+ obj.length;
+ });
+}, "HTMLCollection as a prototype should not allow getting .length on the base object")
+
+test(function() {
+ var element = document.createElement("p");
+ element.id = "named";
+ document.body.appendChild(element);
+ this.add_cleanup(function() { element.remove() });
+
+ var collection = document.getElementsByTagName("p");
+ assert_equals(collection.named, element);
+ var object = Object.create(collection);
+ assert_equals(object.named, element);
+ object.named = "foo";
+ assert_equals(object.named, "foo");
+ assert_equals(collection.named, element);
+}, "HTMLCollection as a prototype and setting own properties")
+</script>
diff --git a/testing/web-platform/tests/dom/collections/HTMLCollection-delete.html b/testing/web-platform/tests/dom/collections/HTMLCollection-delete.html
new file mode 100644
index 0000000000..99420d4319
--- /dev/null
+++ b/testing/web-platform/tests/dom/collections/HTMLCollection-delete.html
@@ -0,0 +1,45 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Deleting properties from HTMLCollection</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+<i id=foo></i>
+<script>
+let c, expected;
+setup(() => {
+ // These might be cached anyway, so explicitly use a single object.
+ c = document.getElementsByTagName("i");
+ expected = document.getElementById("foo");
+});
+
+test(() => {
+ assert_equals(c[0], expected, "before");
+ delete c[0];
+ assert_equals(c[0], expected, "after");
+}, "Loose id");
+
+test(() => {
+ assert_equals(c[0], expected, "before");
+ assert_throws_js(TypeError, function() {
+ "use strict";
+ delete c[0];
+ });
+ assert_equals(c[0], expected, "after");
+}, "Strict id");
+
+test(() => {
+ assert_equals(c.foo, expected, "before");
+ delete c.foo;
+ assert_equals(c.foo, expected, "after");
+}, "Loose name");
+
+test(() => {
+ assert_equals(c.foo, expected, "before");
+ assert_throws_js(TypeError, function() {
+ "use strict";
+ delete c.foo;
+ });
+ assert_equals(c.foo, expected, "after");
+}, "Strict name");
+</script>
diff --git a/testing/web-platform/tests/dom/collections/HTMLCollection-empty-name.html b/testing/web-platform/tests/dom/collections/HTMLCollection-empty-name.html
new file mode 100644
index 0000000000..4fc34db7f5
--- /dev/null
+++ b/testing/web-platform/tests/dom/collections/HTMLCollection-empty-name.html
@@ -0,0 +1,65 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>HTMLCollection and empty names</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+<div id=test>
+<div class=a id></div>
+<div class=a name></div>
+<a class=a name></a>
+</div>
+<script>
+test(function() {
+ var c = document.getElementsByTagName("*");
+ assert_false("" in c, "Empty string should not be in the collection.");
+ assert_equals(c[""], undefined, "Named getter should return undefined for empty string.");
+ assert_equals(c.namedItem(""), null, "namedItem should return null for empty string.");
+}, "Empty string as a name for Document.getElementsByTagName");
+
+test(function() {
+ var div = document.getElementById("test");
+ var c = div.getElementsByTagName("*");
+ assert_false("" in c, "Empty string should not be in the collection.");
+ assert_equals(c[""], undefined, "Named getter should return undefined for empty string.");
+ assert_equals(c.namedItem(""), null, "namedItem should return null for empty string.");
+}, "Empty string as a name for Element.getElementsByTagName");
+
+test(function() {
+ var c = document.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "a");
+ assert_false("" in c, "Empty string should not be in the collection.");
+ assert_equals(c[""], undefined, "Named getter should return undefined for empty string.");
+ assert_equals(c.namedItem(""), null, "namedItem should return null for empty string.");
+}, "Empty string as a name for Document.getElementsByTagNameNS");
+
+test(function() {
+ var div = document.getElementById("test");
+ var c = div.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "a");
+ assert_false("" in c, "Empty string should not be in the collection.");
+ assert_equals(c[""], undefined, "Named getter should return undefined for empty string.");
+ assert_equals(c.namedItem(""), null, "namedItem should return null for empty string.");
+}, "Empty string as a name for Element.getElementsByTagNameNS");
+
+test(function() {
+ var c = document.getElementsByClassName("a");
+ assert_false("" in c, "Empty string should not be in the collection.");
+ assert_equals(c[""], undefined, "Named getter should return undefined for empty string.");
+ assert_equals(c.namedItem(""), null, "namedItem should return null for empty string.");
+}, "Empty string as a name for Document.getElementsByClassName");
+
+test(function() {
+ var div = document.getElementById("test");
+ var c = div.getElementsByClassName("a");
+ assert_false("" in c, "Empty string should not be in the collection.");
+ assert_equals(c[""], undefined, "Named getter should return undefined for empty string.");
+ assert_equals(c.namedItem(""), null, "namedItem should return null for empty string.");
+}, "Empty string as a name for Element.getElementsByClassName");
+
+test(function() {
+ var div = document.getElementById("test");
+ var c = div.children;
+ assert_false("" in c, "Empty string should not be in the collection.");
+ assert_equals(c[""], undefined, "Named getter should return undefined for empty string.");
+ assert_equals(c.namedItem(""), null, "namedItem should return null for empty string.");
+}, "Empty string as a name for Element.children");
+</script>
diff --git a/testing/web-platform/tests/dom/collections/HTMLCollection-iterator.html b/testing/web-platform/tests/dom/collections/HTMLCollection-iterator.html
new file mode 100644
index 0000000000..6296fd1b2d
--- /dev/null
+++ b/testing/web-platform/tests/dom/collections/HTMLCollection-iterator.html
@@ -0,0 +1,45 @@
+<!doctype html>
+<meta charset="utf-8">
+<link rel="help" href="https://dom.spec.whatwg.org/#interface-htmlcollection">
+<link rel="help" href="https://webidl.spec.whatwg.org/#es-iterator">
+<title>HTMLCollection @@iterator 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>
+<script>
+"use strict";
+
+const paragraphs = document.getElementsByTagName("p");
+
+test(() => {
+ assert_true("length" in paragraphs);
+}, "HTMLCollection has length method.");
+
+test(() => {
+ assert_false("values" in paragraphs);
+}, "HTMLCollection does not have iterable's values method.");
+
+test(() => {
+ assert_false("entries" in paragraphs);
+}, "HTMLCollection does not have iterable's entries method.");
+
+test(() => {
+ assert_false("forEach" in paragraphs);
+}, "HTMLCollection does not have iterable's forEach method.");
+
+test(() => {
+ assert_true(Symbol.iterator in paragraphs);
+}, "HTMLCollection has Symbol.iterator.");
+
+test(() => {
+ const ids = "12345";
+ let idx = 0;
+ for (const element of paragraphs) {
+ assert_equals(element.getAttribute("id"), ids[idx++]);
+ }
+}, "HTMLCollection is iterable via for-of loop.");
+</script>
diff --git a/testing/web-platform/tests/dom/collections/HTMLCollection-live-mutations.window.js b/testing/web-platform/tests/dom/collections/HTMLCollection-live-mutations.window.js
new file mode 100644
index 0000000000..7dbfc6ccf6
--- /dev/null
+++ b/testing/web-platform/tests/dom/collections/HTMLCollection-live-mutations.window.js
@@ -0,0 +1,93 @@
+function testHTMLCollection(name, hooks) {
+ test(() => {
+ const nodes = {
+ root: document.createElement("div"),
+ div1: document.createElement("div"),
+ div2: document.createElement("div"),
+ p: document.createElement("p")
+ };
+
+ nodes.div1.id = "div1";
+ nodes.div2.id = "div2";
+
+ const list = nodes.root.getElementsByTagName("div");
+
+ 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);
+ }, `HTMLCollection live mutations: ${name}`);
+}
+
+testHTMLCollection("HTMLCollection.length", {
+ initial(list) {
+ assert_equals(list.length, 0);
+ },
+ afterInsertion(list) {
+ assert_equals(list.length, 2);
+ },
+ afterRemoval(list) {
+ assert_equals(list.length, 1);
+ }
+});
+
+testHTMLCollection("HTMLCollection.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.div2);
+ },
+ afterRemoval(list, nodes) {
+ assert_equals(list.item(0), nodes.div2);
+ }
+});
+
+testHTMLCollection("HTMLCollection[index]", {
+ initial(list) {
+ assert_equals(list[0], undefined);
+ },
+ afterInsertion(list, nodes) {
+ assert_equals(list[0], nodes.div1);
+ assert_equals(list[1], nodes.div2);
+ },
+ afterRemoval(list, nodes) {
+ assert_equals(list[0], nodes.div2);
+ }
+});
+
+testHTMLCollection("HTMLCollection.namedItem(index)", {
+ initial(list) {
+ assert_equals(list.namedItem("div1"), null);
+ assert_equals(list.namedItem("div2"), null);
+ },
+ afterInsertion(list, nodes) {
+ assert_equals(list.namedItem("div1"), nodes.div1);
+ assert_equals(list.namedItem("div2"), nodes.div2);
+ },
+ afterRemoval(list, nodes) {
+ assert_equals(list.namedItem("div1"), null);
+ assert_equals(list.namedItem("div2"), nodes.div2);
+ }
+});
+
+testHTMLCollection("HTMLCollection ownPropertyNames", {
+ initial(list) {
+ assert_object_equals(Object.getOwnPropertyNames(list), []);
+ },
+ afterInsertion(list) {
+ assert_object_equals(Object.getOwnPropertyNames(list), ["0", "1", "div1", "div2"]);
+ },
+ afterRemoval(list) {
+ assert_object_equals(Object.getOwnPropertyNames(list), ["0", "div2"]);
+ }
+});
+
diff --git a/testing/web-platform/tests/dom/collections/HTMLCollection-own-props.html b/testing/web-platform/tests/dom/collections/HTMLCollection-own-props.html
new file mode 100644
index 0000000000..99dc425dbe
--- /dev/null
+++ b/testing/web-platform/tests/dom/collections/HTMLCollection-own-props.html
@@ -0,0 +1,109 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>HTMLCollection getters and own properties</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+<script>
+function append(t, tag, name) {
+ var element = document.createElement(tag);
+ if (name) {
+ element.id = name;
+ }
+ document.body.appendChild(element);
+ t.add_cleanup(function() { element.remove(); });
+ return element;
+}
+
+test(function() {
+ var name = "named", tag = "a";
+ var c = document.getElementsByTagName(tag);
+ var element = append(this, tag, name);
+ assert_equals(c[name], element);
+ c[name] = "foo";
+ assert_equals(c[name], element);
+}, "Setting non-array index while named property exists (loose)");
+
+test(function() {
+ "use strict";
+ var name = "named", tag = "b";
+ var c = document.getElementsByTagName(tag);
+ var element = append(this, tag, name);
+ assert_equals(c[name], element);
+ assert_throws_js(TypeError, function() {
+ c[name] = "foo";
+ });
+ assert_equals(c[name], element);
+}, "Setting non-array index while named property exists (strict)");
+
+test(function() {
+ var name = "named", tag = "i";
+ var c = document.getElementsByTagName(tag);
+ assert_equals(c[name], undefined);
+ c[name] = "foo";
+ assert_equals(c[name], "foo");
+
+ var element = append(this, tag, name);
+ assert_equals(c[name], "foo");
+ assert_equals(c.namedItem(name), element);
+}, "Setting non-array index while named property doesn't exist (loose)");
+
+test(function() {
+ "use strict";
+ var name = "named", tag = "p";
+ var c = document.getElementsByTagName(tag);
+ assert_equals(c[name], undefined);
+ c[name] = "foo";
+ assert_equals(c[name], "foo");
+
+ var element = append(this, tag, name);
+ assert_equals(c[name], "foo");
+ assert_equals(c.namedItem(name), element);
+}, "Setting non-array index while named property doesn't exist (strict)");
+
+test(function() {
+ var tag = "q";
+ var c = document.getElementsByTagName(tag);
+ var element = append(this, tag);
+ assert_equals(c[0], element);
+ c[0] = "foo";
+ assert_equals(c[0], element);
+}, "Setting array index while indexed property exists (loose)");
+
+test(function() {
+ "use strict";
+ var tag = "s";
+ var c = document.getElementsByTagName(tag);
+ var element = append(this, tag);
+ assert_equals(c[0], element);
+ assert_throws_js(TypeError, function() {
+ c[0] = "foo";
+ });
+ assert_equals(c[0], element);
+}, "Setting array index while indexed property exists (strict)");
+
+test(function() {
+ var tag = "u";
+ var c = document.getElementsByTagName(tag);
+ assert_equals(c[0], undefined);
+ c[0] = "foo";
+ assert_equals(c[0], undefined);
+
+ var element = append(this, tag);
+ assert_equals(c[0], element);
+}, "Setting array index while indexed property doesn't exist (loose)");
+
+test(function() {
+ "use strict";
+ var tag = "u";
+ var c = document.getElementsByTagName(tag);
+ assert_equals(c[0], undefined);
+ assert_throws_js(TypeError, function() {
+ c[0] = "foo";
+ });
+ assert_equals(c[0], undefined);
+
+ var element = append(this, tag);
+ assert_equals(c[0], element);
+}, "Setting array index while indexed property doesn't exist (strict)");
+</script>
diff --git a/testing/web-platform/tests/dom/collections/HTMLCollection-supported-property-indices.html b/testing/web-platform/tests/dom/collections/HTMLCollection-supported-property-indices.html
new file mode 100644
index 0000000000..5339ec31ea
--- /dev/null
+++ b/testing/web-platform/tests/dom/collections/HTMLCollection-supported-property-indices.html
@@ -0,0 +1,179 @@
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<!-- We want to use a tag name that will not interact with our test harness,
+ so just make one up. "foo" is a good one -->
+
+<!-- Ids that look like negative indices. These should come first, so we can
+ assert that lookups for nonnegative indices find these by index -->
+<foo id="-2"></foo>
+<foo id="-1"></foo>
+
+<!-- Ids that look like nonnegative indices -->
+<foo id="0"></foo>
+<foo id="1"></foo>
+
+<!-- Ids that look like nonnegative indices near 2^31 = 2147483648 -->
+<foo id="2147483645"></foo> <!-- 2^31 - 3 -->
+<foo id="2147483646"></foo> <!-- 2^31 - 2 -->
+<foo id="2147483647"></foo> <!-- 2^31 - 1 -->
+<foo id="2147483648"></foo> <!-- 2^31 -->
+<foo id="2147483649"></foo> <!-- 2^31 + 1 -->
+
+<!-- Ids that look like nonnegative indices near 2^32 = 4294967296 -->
+<foo id="4294967293"></foo> <!-- 2^32 - 3 -->
+<foo id="4294967294"></foo> <!-- 2^32 - 2 -->
+<foo id="4294967295"></foo> <!-- 2^32 - 1 -->
+<foo id="4294967296"></foo> <!-- 2^32 -->
+<foo id="4294967297"></foo> <!-- 2^32 + 1 -->
+
+<script>
+test(function() {
+ var collection = document.getElementsByTagName("foo");
+ assert_equals(collection.item(-2), null);
+ assert_equals(collection.item(-1), null);
+ assert_equals(collection.namedItem(-2), document.getElementById("-2"));
+ assert_equals(collection.namedItem(-1), document.getElementById("-1"));
+ assert_equals(collection[-2], document.getElementById("-2"));
+ assert_equals(collection[-1], document.getElementById("-1"));
+}, "Handling of property names that look like negative integers");
+
+test(function() {
+ var collection = document.getElementsByTagName("foo");
+ assert_equals(collection.item(0), document.getElementById("-2"));
+ assert_equals(collection.item(1), document.getElementById("-1"));
+ assert_equals(collection.namedItem(0), document.getElementById("0"));
+ assert_equals(collection.namedItem(1), document.getElementById("1"));
+ assert_equals(collection[0], document.getElementById("-2"));
+ assert_equals(collection[1], document.getElementById("-1"));
+}, "Handling of property names that look like small nonnegative integers");
+
+test(function() {
+ var collection = document.getElementsByTagName("foo");
+ assert_equals(collection.item(2147483645), null);
+ assert_equals(collection.item(2147483646), null);
+ assert_equals(collection.item(2147483647), null);
+ assert_equals(collection.item(2147483648), null);
+ assert_equals(collection.item(2147483649), null);
+ assert_equals(collection.namedItem(2147483645),
+ document.getElementById("2147483645"));
+ assert_equals(collection.namedItem(2147483646),
+ document.getElementById("2147483646"));
+ assert_equals(collection.namedItem(2147483647),
+ document.getElementById("2147483647"));
+ assert_equals(collection.namedItem(2147483648),
+ document.getElementById("2147483648"));
+ assert_equals(collection.namedItem(2147483649),
+ document.getElementById("2147483649"));
+ assert_equals(collection[2147483645], undefined);
+ assert_equals(collection[2147483646], undefined);
+ assert_equals(collection[2147483647], undefined);
+ assert_equals(collection[2147483648], undefined);
+ assert_equals(collection[2147483649], undefined);
+}, "Handling of property names that look like integers around 2^31");
+
+test(function() {
+ var collection = document.getElementsByTagName("foo");
+ assert_equals(collection.item(4294967293), null);
+ assert_equals(collection.item(4294967294), null);
+ assert_equals(collection.item(4294967295), null);
+ assert_equals(collection.item(4294967296), document.getElementById("-2"));
+ assert_equals(collection.item(4294967297), document.getElementById("-1"));
+ assert_equals(collection.namedItem(4294967293),
+ document.getElementById("4294967293"));
+ assert_equals(collection.namedItem(4294967294),
+ document.getElementById("4294967294"));
+ assert_equals(collection.namedItem(4294967295),
+ document.getElementById("4294967295"));
+ assert_equals(collection.namedItem(4294967296),
+ document.getElementById("4294967296"));
+ assert_equals(collection.namedItem(4294967297),
+ document.getElementById("4294967297"));
+ assert_equals(collection[4294967293], undefined);
+ assert_equals(collection[4294967294], undefined);
+ assert_equals(collection[4294967295], document.getElementById("4294967295"));
+ assert_equals(collection[4294967296], document.getElementById("4294967296"));
+ assert_equals(collection[4294967297], document.getElementById("4294967297"));
+}, "Handling of property names that look like integers around 2^32");
+
+test(function() {
+ var elements = document.getElementsByTagName("foo");
+ var old_item = elements[0];
+ var old_desc = Object.getOwnPropertyDescriptor(elements, 0);
+ assert_equals(old_desc.value, old_item);
+ assert_true(old_desc.enumerable);
+ assert_true(old_desc.configurable);
+ assert_false(old_desc.writable);
+
+ elements[0] = 5;
+ assert_equals(elements[0], old_item);
+ assert_throws_js(TypeError, function() {
+ "use strict";
+ elements[0] = 5;
+ });
+ assert_throws_js(TypeError, function() {
+ Object.defineProperty(elements, 0, { value: 5 });
+ });
+
+ delete elements[0];
+ assert_equals(elements[0], old_item);
+
+ assert_throws_js(TypeError, function() {
+ "use strict";
+ delete elements[0];
+ });
+ assert_equals(elements[0], old_item);
+}, 'Trying to set an expando that would shadow an already-existing indexed property');
+
+test(function() {
+ var elements = document.getElementsByTagName("foo");
+ var idx = elements.length;
+ var old_item = elements[idx];
+ var old_desc = Object.getOwnPropertyDescriptor(elements, idx);
+ assert_equals(old_item, undefined);
+ assert_equals(old_desc, undefined);
+
+ // [[DefineOwnProperty]] will disallow defining an indexed expando.
+ elements[idx] = 5;
+ assert_equals(elements[idx], undefined);
+ assert_throws_js(TypeError, function() {
+ "use strict";
+ elements[idx] = 5;
+ });
+ assert_throws_js(TypeError, function() {
+ Object.defineProperty(elements, idx, { value: 5 });
+ });
+
+ // Check that deletions out of range do not throw
+ delete elements[idx];
+ (function() {
+ "use strict";
+ delete elements[idx];
+ })();
+}, 'Trying to set an expando with an indexed property name past the end of the list');
+
+test(function(){
+ var elements = document.getElementsByTagName("foo");
+ var old_item = elements[0];
+ var old_desc = Object.getOwnPropertyDescriptor(elements, 0);
+ assert_equals(old_desc.value, old_item);
+ assert_true(old_desc.enumerable);
+ assert_true(old_desc.configurable);
+ assert_false(old_desc.writable);
+
+ Object.prototype[0] = 5;
+ this.add_cleanup(function () { delete Object.prototype[0]; });
+ assert_equals(elements[0], old_item);
+
+ delete elements[0];
+ assert_equals(elements[0], old_item);
+
+ assert_throws_js(TypeError, function() {
+ "use strict";
+ delete elements[0];
+ });
+ assert_equals(elements[0], old_item);
+}, 'Trying to delete an indexed property name should never work');
+</script>
diff --git a/testing/web-platform/tests/dom/collections/HTMLCollection-supported-property-names.html b/testing/web-platform/tests/dom/collections/HTMLCollection-supported-property-names.html
new file mode 100644
index 0000000000..3d21e16692
--- /dev/null
+++ b/testing/web-platform/tests/dom/collections/HTMLCollection-supported-property-names.html
@@ -0,0 +1,135 @@
+<!doctype html>
+<meta charset=utf-8>
+<link rel=help href=https://dom.spec.whatwg.org/#interface-htmlcollection>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+
+<div id=log></div>
+
+<!-- with no attribute -->
+<span></span>
+
+<!-- with `id` attribute -->
+<span id=''></span>
+<span id='some-id'></span>
+<span id='some-id'></span><!-- to ensure no duplicates -->
+
+<!-- with `name` attribute -->
+<span name=''></span>
+<span name='some-name'></span>
+<span name='some-name'></span><!-- to ensure no duplicates -->
+
+<!-- with `name` and `id` attribute -->
+<span id='another-id' name='another-name'></span>
+
+<script>
+test(function () {
+ var elements = document.getElementsByTagName("span");
+ assert_array_equals(
+ Object.getOwnPropertyNames(elements),
+ ['0', '1', '2', '3', '4', '5', '6', '7', 'some-id', 'some-name', 'another-id', 'another-name']
+ );
+}, 'Object.getOwnPropertyNames on HTMLCollection');
+
+test(function () {
+ var elem = document.createElementNS('some-random-namespace', 'foo');
+ this.add_cleanup(function () {elem.remove();});
+ elem.setAttribute("name", "some-name");
+ document.body.appendChild(elem);
+
+ var elements = document.getElementsByTagName("foo");
+ assert_array_equals(Object.getOwnPropertyNames(elements), ['0']);
+}, 'Object.getOwnPropertyNames on HTMLCollection with non-HTML namespace');
+
+test(function () {
+ var elem = document.createElement('foo');
+ this.add_cleanup(function () {elem.remove();});
+ document.body.appendChild(elem);
+
+ var elements = document.getElementsByTagName("foo");
+ elements.someProperty = "some value";
+
+ assert_array_equals(Object.getOwnPropertyNames(elements), ['0', 'someProperty']);
+}, 'Object.getOwnPropertyNames on HTMLCollection with expando object');
+
+test(function() {
+ var elements = document.getElementsByTagName("span");
+ var old_item = elements["some-id"];
+ var old_desc = Object.getOwnPropertyDescriptor(elements, "some-id");
+ assert_equals(old_desc.value, old_item);
+ assert_false(old_desc.enumerable);
+ assert_true(old_desc.configurable);
+ assert_false(old_desc.writable);
+
+ elements["some-id"] = 5;
+ assert_equals(elements["some-id"], old_item);
+ assert_throws_js(TypeError, function() {
+ "use strict";
+ elements["some-id"] = 5;
+ });
+ assert_throws_js(TypeError, function() {
+ Object.defineProperty(elements, "some-id", { value: 5 });
+ });
+
+ delete elements["some-id"];
+ assert_equals(elements["some-id"], old_item);
+
+ assert_throws_js(TypeError, function() {
+ "use strict";
+ delete elements["some-id"];
+ });
+ assert_equals(elements["some-id"], old_item);
+
+}, 'Trying to set an expando that would shadow an already-existing named property');
+
+test(function() {
+ var elements = document.getElementsByTagName("span");
+ var old_item = elements["new-id"];
+ var old_desc = Object.getOwnPropertyDescriptor(elements, "new-id");
+ assert_equals(old_item, undefined);
+ assert_equals(old_desc, undefined);
+
+ elements["new-id"] = 5;
+ assert_equals(elements["new-id"], 5);
+
+ var span = document.createElement("span");
+ this.add_cleanup(function () {span.remove();});
+ span.id = "new-id";
+ document.body.appendChild(span);
+
+ assert_equals(elements.namedItem("new-id"), span);
+ assert_equals(elements["new-id"], 5);
+
+ delete elements["new-id"];
+ assert_equals(elements["new-id"], span);
+}, 'Trying to set an expando that shadows a named property that gets added later');
+
+test(function() {
+ var elements = document.getElementsByTagName("span");
+ var old_item = elements["new-id2"];
+ var old_desc = Object.getOwnPropertyDescriptor(elements, "new-id2");
+ assert_equals(old_item, undefined);
+ assert_equals(old_desc, undefined);
+
+ Object.defineProperty(elements, "new-id2", { configurable: false, writable:
+ false, value: 5 });
+ assert_equals(elements["new-id2"], 5);
+
+ var span = document.createElement("span");
+ this.add_cleanup(function () {span.remove();});
+ span.id = "new-id2";
+ document.body.appendChild(span);
+
+ assert_equals(elements.namedItem("new-id2"), span);
+ assert_equals(elements["new-id2"], 5);
+
+ delete elements["new-id2"];
+ assert_equals(elements["new-id2"], 5);
+
+ assert_throws_js(TypeError, function() {
+ "use strict";
+ delete elements["new-id2"];
+ });
+ assert_equals(elements["new-id2"], 5);
+}, 'Trying to set a non-configurable expando that shadows a named property that gets added later');
+</script>
diff --git a/testing/web-platform/tests/dom/collections/domstringmap-supported-property-names.html b/testing/web-platform/tests/dom/collections/domstringmap-supported-property-names.html
new file mode 100644
index 0000000000..430aa44c3a
--- /dev/null
+++ b/testing/web-platform/tests/dom/collections/domstringmap-supported-property-names.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<meta charset=utf-8>
+<title>DOMStringMap Test: Supported property names</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+
+<div id="edge1" data-="012">Simple</div>
+
+<div id="edge2" data-id-="012">Simple</div>
+
+<div id="user" data-id="1234567890" data-user="johndoe" data-date-of-birth>
+ John Doe
+</div>
+
+<div id="user2" data-unique-id="1234567890"> Jane Doe </div>
+
+<div id="user3" data-unique-id="4324324241"> Jim Doe </div>
+
+<script>
+
+test(function() {
+ var element = document.querySelector('#edge1');
+ assert_array_equals(Object.getOwnPropertyNames(element.dataset),
+ [""]);
+}, "Object.getOwnPropertyNames on DOMStringMap, empty data attribute");
+
+test(function() {
+ var element = document.querySelector('#edge2');
+ assert_array_equals(Object.getOwnPropertyNames(element.dataset),
+ ["id-"]);
+}, "Object.getOwnPropertyNames on DOMStringMap, data attribute trailing hyphen");
+
+test(function() {
+ var element = document.querySelector('#user');
+ assert_array_equals(Object.getOwnPropertyNames(element.dataset),
+ ['id', 'user', 'dateOfBirth']);
+}, "Object.getOwnPropertyNames on DOMStringMap, multiple data attributes");
+
+test(function() {
+ var element = document.querySelector('#user2');
+ element.dataset.middleName = "mark";
+ assert_array_equals(Object.getOwnPropertyNames(element.dataset),
+ ['uniqueId', 'middleName']);
+}, "Object.getOwnPropertyNames on DOMStringMap, attribute set on dataset in JS");
+
+test(function() {
+ var element = document.querySelector('#user3');
+ element.setAttribute("data-age", 30);
+ assert_array_equals(Object.getOwnPropertyNames(element.dataset),
+ ['uniqueId', 'age']);
+}, "Object.getOwnPropertyNames on DOMStringMap, attribute set on element in JS");
+
+</script>
diff --git a/testing/web-platform/tests/dom/collections/namednodemap-supported-property-names.html b/testing/web-platform/tests/dom/collections/namednodemap-supported-property-names.html
new file mode 100644
index 0000000000..2c5dee4efd
--- /dev/null
+++ b/testing/web-platform/tests/dom/collections/namednodemap-supported-property-names.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<meta charset=utf-8>
+<title>NamedNodeMap Test: Supported property names</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<div id="simple" class="fancy">Simple</div>
+<input id="result" type="text" value="" width="200px">
+<script>
+
+test(function() {
+ var elt = document.querySelector('#simple');
+ assert_array_equals(Object.getOwnPropertyNames(elt.attributes),
+ ['0','1','id','class']);
+}, "Object.getOwnPropertyNames on NamedNodeMap");
+
+test(function() {
+ var result = document.getElementById("result");
+ assert_array_equals(Object.getOwnPropertyNames(result.attributes),
+ ['0','1','2','3','id','type','value','width']);
+}, "Object.getOwnPropertyNames on NamedNodeMap of input");
+
+test(function() {
+ var result = document.getElementById("result");
+ result.removeAttribute("width");
+ assert_array_equals(Object.getOwnPropertyNames(result.attributes),
+ ['0','1','2','id','type','value']);
+}, "Object.getOwnPropertyNames on NamedNodeMap after attribute removal");
+
+</script> \ No newline at end of file