diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/dom/nodes/attributes.html | |
parent | Initial commit. (diff) | |
download | firefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/dom/nodes/attributes.html')
-rw-r--r-- | testing/web-platform/tests/dom/nodes/attributes.html | 858 |
1 files changed, 858 insertions, 0 deletions
diff --git a/testing/web-platform/tests/dom/nodes/attributes.html b/testing/web-platform/tests/dom/nodes/attributes.html new file mode 100644 index 0000000000..c6db7eb8aa --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/attributes.html @@ -0,0 +1,858 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Attributes tests</title> +<link rel=help href="https://dom.spec.whatwg.org/#attr"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-setattribute"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-setattributens"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="attributes.js"></script> +<script src="productions.js"></script> +<div id="log"></div> +<span id="test1"></span> +<span class="&<>foo"></span> +<span id="test2"> + <span ~=""></span> + <span ~></span> + <span></span> +</span> +<script> +var XML = "http://www.w3.org/XML/1998/namespace" +var XMLNS = "http://www.w3.org/2000/xmlns/" + +// toggleAttribute exhaustive tests +// Step 1 +test(function() { + var el = document.createElement("foo") + for (var i = 0; i < invalid_names.length; i++) { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { el.toggleAttribute(invalid_names[i], true) }) + } + for (var i = 0; i < invalid_names.length; i++) { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { el.toggleAttribute(invalid_names[i]) }) + } + for (var i = 0; i < invalid_names.length; i++) { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { el.toggleAttribute(invalid_names[i], false) }) + } +}, "When qualifiedName does not match the Name production, an " + + "INVALID_CHARACTER_ERR exception is to be thrown. (toggleAttribute)") +test(function() { + var el = document.getElementById("test2") + for (var i = 0; i < el.children.length; i++) { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { + el.children[i].toggleAttribute("~", false) + }) + } + for (var i = 0; i < el.children.length; i++) { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { + el.children[i].toggleAttribute("~") + }) + } + for (var i = 0; i < el.children.length; i++) { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { + el.children[i].toggleAttribute("~", true) + }) + } +}, "When qualifiedName does not match the Name production, an " + + "INVALID_CHARACTER_ERR exception is to be thrown, even if the attribute " + + "is already present. (toggleAttribute)") + +// Step 2 +test(function() { + var el = document.createElement("div") + assert_true(el.toggleAttribute("ALIGN")) + assert_true(!el.hasAttributeNS("", "ALIGN")) + assert_true(el.hasAttributeNS("", "align")) + assert_true(el.hasAttribute("align")) + assert_true(!el.toggleAttribute("ALIGN")) + assert_true(!el.hasAttributeNS("", "ALIGN")) + assert_true(!el.hasAttributeNS("", "align")) + assert_true(!el.hasAttribute("align")) +}, "toggleAttribute should lowercase its name argument (upper case attribute)") +test(function() { + var el = document.createElement("div") + assert_true(el.toggleAttribute("CHEEseCaKe")) + assert_true(!el.hasAttributeNS("", "CHEEseCaKe")) + assert_true(el.hasAttributeNS("", "cheesecake")) + assert_true(el.hasAttribute("cheesecake")) +}, "toggleAttribute should lowercase its name argument (mixed case attribute)") + +// Step 3 +test(function() { + var el = document.createElement("foo") + var tests = ["xmlns", "xmlns:a", "xmlnsx", "xmlns0"] + for (var i = 0; i < tests.length; i++) { + assert_true(el.toggleAttribute(tests[i])); + assert_true(el.hasAttribute(tests[i])); + } +}, "toggleAttribute should not throw even when qualifiedName starts with 'xmlns'") + +// Step 4 +test(function() { + var el = document.createElement("foo") + for (var i = 0; i < valid_names.length; i++) { + assert_true(el.toggleAttribute(valid_names[i])) + assert_true(el.hasAttribute(valid_names[i])) + assert_true(!el.toggleAttribute(valid_names[i])) + assert_true(!el.hasAttribute(valid_names[i])) + // Check using force attr + assert_true(el.toggleAttribute(valid_names[i], true)) + assert_true(el.hasAttribute(valid_names[i])) + assert_true(el.toggleAttribute(valid_names[i], true)) + assert_true(el.hasAttribute(valid_names[i])) + assert_true(!el.toggleAttribute(valid_names[i], false)) + assert_true(!el.hasAttribute(valid_names[i])) + } +}, "Basic functionality should be intact. (toggleAttribute)") + +// Step 5 +test(function() { + var el = document.createElement("foo") + el.toggleAttribute("a") + el.toggleAttribute("b") + el.setAttribute("a", "thing") + el.toggleAttribute("c") + attributes_are(el, [["a", "thing"], + ["b", ""], + ["c", ""]]) +}, "toggleAttribute should not change the order of previously set attributes.") +test(function() { + var el = document.createElement("baz") + el.setAttributeNS("ab", "attr", "fail") + el.setAttributeNS("kl", "attr", "pass") + el.toggleAttribute("attr") + attributes_are(el, [["attr", "pass", "kl"]]) +}, "toggleAttribute should set the first attribute with the given name") +test(function() { + // Based on a test by David Flanagan. + var el = document.createElement("baz") + el.setAttributeNS("foo", "foo:bar", "1"); + el.setAttributeNS("foo", "foo:bat", "2"); + assert_equals(el.getAttribute("foo:bar"), "1") + assert_equals(el.getAttribute("foo:bat"), "2") + attr_is(el.attributes[0], "1", "bar", "foo", "foo", "foo:bar") + attr_is(el.attributes[1], "2", "bat", "foo", "foo", "foo:bat") + el.toggleAttribute("foo:bar"); + assert_true(!el.hasAttribute("foo:bar")) + attr_is(el.attributes[0], "2", "bat", "foo", "foo", "foo:bat") +}, "toggleAttribute should set the attribute with the given qualified name") + +test(function() { + var el = document.createElement("foo") + el.style = "color: red; background-color: green" + assert_equals(el.toggleAttribute("style"), false) +}, "Toggling element with inline style should make inline style disappear") + +// setAttribute exhaustive tests +// Step 1 +test(function() { + var el = document.createElement("foo") + for (var i = 0; i < invalid_names.length; i++) { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { el.setAttribute(invalid_names[i], "test") }) + } +}, "When qualifiedName does not match the Name production, an " + + "INVALID_CHARACTER_ERR exception is to be thrown. (setAttribute)") +test(function() { + var el = document.getElementById("test2") + for (var i = 0; i < el.children.length; i++) { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { + el.children[i].setAttribute("~", "test") + }) + } +}, "When qualifiedName does not match the Name production, an " + + "INVALID_CHARACTER_ERR exception is to be thrown, even if the attribute " + + "is already present. (setAttribute)") + +// Step 2 +test(function() { + var el = document.createElement("div") + el.setAttribute("ALIGN", "left") + assert_equals(el.getAttributeNS("", "ALIGN"), null) + assert_equals(el.getAttributeNS("", "align"), "left") + assert_equals(el.getAttribute("align"), "left") +}, "setAttribute should lowercase its name argument (upper case attribute)") +test(function() { + var el = document.createElement("div") + el.setAttribute("CHEEseCaKe", "tasty") + assert_equals(el.getAttributeNS("", "CHEEseCaKe"), null) + assert_equals(el.getAttributeNS("", "cheesecake"), "tasty") + assert_equals(el.getAttribute("cheesecake"), "tasty") +}, "setAttribute should lowercase its name argument (mixed case attribute)") + +// Step 3 +test(function() { + var el = document.createElement("foo") + var tests = ["xmlns", "xmlns:a", "xmlnsx", "xmlns0"] + for (var i = 0; i < tests.length; i++) { + el.setAttribute(tests[i], "success"); + } +}, "setAttribute should not throw even when qualifiedName starts with 'xmlns'") + +// Step 4 +test(function() { + var el = document.createElement("foo") + for (var i = 0; i < valid_names.length; i++) { + el.setAttribute(valid_names[i], "test") + assert_equals(el.getAttribute(valid_names[i]), "test") + } +}, "Basic functionality should be intact.") + +// Step 5 +test(function() { + var el = document.createElement("foo") + el.setAttribute("a", "1") + el.setAttribute("b", "2") + el.setAttribute("a", "3") + el.setAttribute("c", "4") + attributes_are(el, [["a", "3"], + ["b", "2"], + ["c", "4"]]) +}, "setAttribute should not change the order of previously set attributes.") +test(function() { + var el = document.createElement("baz") + el.setAttributeNS("ab", "attr", "fail") + el.setAttributeNS("kl", "attr", "pass") + el.setAttribute("attr", "pass") + attributes_are(el, [["attr", "pass", "ab"], + ["attr", "pass", "kl"]]) +}, "setAttribute should set the first attribute with the given name") +test(function() { + // Based on a test by David Flanagan. + var el = document.createElement("baz") + el.setAttributeNS("foo", "foo:bar", "1"); + assert_equals(el.getAttribute("foo:bar"), "1") + attr_is(el.attributes[0], "1", "bar", "foo", "foo", "foo:bar") + el.setAttribute("foo:bar", "2"); + assert_equals(el.getAttribute("foo:bar"), "2") + attr_is(el.attributes[0], "2", "bar", "foo", "foo", "foo:bar") +}, "setAttribute should set the attribute with the given qualified name") + +// setAttributeNS exhaustive tests +// Step 1 +test(function() { + var el = document.createElement("foo") + for (var i = 0, il = invalid_names.length; i < il; ++i) { + assert_throws_dom("INVALID_CHARACTER_ERR", + function() { el.setAttributeNS("a", invalid_names[i], "fail") }) + } +}, "When qualifiedName does not match the Name production, an " + + "INVALID_CHARACTER_ERR exception is to be thrown. (setAttributeNS)") + +test(function() { + var el = document.getElementById("test2") + for (var i = 0; i < el.children.length; i++) { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { + el.children[i].setAttributeNS(null, "~", "test") + }) + } +}, "When qualifiedName does not match the Name production, an " + + "INVALID_CHARACTER_ERR exception is to be thrown, even if the attribute " + + "is already present. (setAttributeNS)") + +// Step 2 +test(function() { + var el = document.createElement("foo") + for (var i = 0, il = invalid_qnames.length; i < il; ++i) { + assert_throws_dom("INVALID_CHARACTER_ERR", + function() { el.setAttributeNS("a", invalid_qnames[i], "fail") }, + "Expected exception for " + invalid_qnames[i] + ".") + } +}, "When qualifiedName does not match the QName production, an " + + "INVALID_CHARACTER_ERR exception is to be thrown.") + +// Step 3 +test(function() { + var el = document.createElement("foo") + el.setAttributeNS(null, "aa", "bb") + el.setAttributeNS("", "xx", "bb") + attributes_are(el, [["aa", "bb"], + ["xx", "bb"]]) +}, "null and the empty string should result in a null namespace.") + +// Step 4 +test(function() { + var el = document.createElement("foo") + assert_throws_dom("NAMESPACE_ERR", + function() { el.setAttributeNS("", "aa:bb", "fail") }) + assert_throws_dom("NAMESPACE_ERR", + function() { el.setAttributeNS(null, "aa:bb", "fail") }) +}, "A namespace is required to use a prefix.") + +// Step 5 +test(function() { + var el = document.createElement("foo") + assert_throws_dom("NAMESPACE_ERR", + function() { el.setAttributeNS("a", "xml:bb", "fail") }) +}, "The xml prefix should not be allowed for arbitrary namespaces") +test(function() { + var el = document.createElement("foo") + el.setAttributeNS(XML, "a:bb", "pass") + assert_equals(el.attributes.length, 1) + attr_is(el.attributes[0], "pass", "bb", XML, "a", "a:bb") +}, "XML-namespaced attributes don't need an xml prefix") + +// Step 6 +test(function() { + var el = document.createElement("foo") + assert_throws_dom("NAMESPACE_ERR", + function() { el.setAttributeNS("a", "xmlns:bb", "fail") }) +}, "The xmlns prefix should not be allowed for arbitrary namespaces") +test(function() { + var el = document.createElement("foo") + assert_throws_dom("NAMESPACE_ERR", + function() { el.setAttributeNS("a", "xmlns", "fail") }) +}, "The xmlns qualified name should not be allowed for arbitrary namespaces") +test(function() { + var el = document.createElement("foo") + el.setAttributeNS("ns", "a:xmlns", "pass") + assert_equals(el.attributes.length, 1) + attr_is(el.attributes[0], "pass", "xmlns", "ns", "a", "a:xmlns") +}, "xmlns should be allowed as local name") + +// Step 7 +test(function() { + var el = document.createElement("foo") + assert_throws_dom("NAMESPACE_ERR", + function() { el.setAttributeNS(XMLNS, "a:xmlns", "fail") }) + assert_throws_dom("NAMESPACE_ERR", + function() { el.setAttributeNS(XMLNS, "b:foo", "fail") }) +}, "The XMLNS namespace should require xmlns as prefix or qualified name") +test(function() { + var el = document.createElement("foo") + el.setAttributeNS(XMLNS, "xmlns:a", "pass") + assert_equals(el.attributes.length, 1) + attr_is(el.attributes[0], "pass", "a", XMLNS, "xmlns", "xmlns:a") +}, "xmlns should be allowed as prefix in the XMLNS namespace") +test(function() { + var el = document.createElement("foo") + el.setAttributeNS(XMLNS, "xmlns", "pass") + assert_equals(el.attributes.length, 1) + attr_is(el.attributes[0], "pass", "xmlns", XMLNS, null, "xmlns") +}, "xmlns should be allowed as qualified name in the XMLNS namespace") + +// Step 8-9 +test(function() { + var el = document.createElement("foo") + el.setAttributeNS("a", "foo:bar", "X") + assert_equals(el.attributes.length, 1) + attr_is(el.attributes[0], "X", "bar", "a", "foo", "foo:bar") + + el.setAttributeNS("a", "quux:bar", "Y") + assert_equals(el.attributes.length, 1) + attr_is(el.attributes[0], "Y", "bar", "a", "foo", "foo:bar") + el.removeAttributeNS("a", "bar") +}, "Setting the same attribute with another prefix should not change the prefix") + +// Miscellaneous tests +test(function() { + var el = document.createElement("iframe") + el.setAttribute("src", "file:///home") + assert_equals(el.getAttribute("src"), "file:///home") +}, "setAttribute should not throw even if a load is not allowed") +test(function() { + var docFragment = document.createDocumentFragment() + var newOne = document.createElement("newElement") + newOne.setAttribute("newdomestic", "Yes") + docFragment.appendChild(newOne) + var domesticNode = docFragment.firstChild + var attr = domesticNode.attributes.item(0) + attr_is(attr, "Yes", "newdomestic", null, null, "newdomestic") +}, "Attributes should work in document fragments.") +test(function() { + var el = document.createElement("foo") + el.setAttribute("x", "y") + var attr = el.attributes[0] + attr.value = "Y<" + attr_is(attr, "Y<", "x", null, null, "x") + assert_equals(el.getAttribute("x"), "Y<") +}, "Attribute values should not be parsed.") +test(function() { + var el = document.getElementsByTagName("span")[0] + attr_is(el.attributes[0], "test1", "id", null, null, "id") +}, "Specified attributes should be accessible.") +test(function() { + var el = document.getElementsByTagName("span")[1] + attr_is(el.attributes[0], "&<>foo", "class", null, null, "class") +}, "Entities in attributes should have been expanded while parsing.") + +test(function() { + var el = document.createElement("div") + assert_equals(el.hasAttribute("bar"), false) + assert_equals(el.hasAttributeNS(null, "bar"), false) + assert_equals(el.hasAttributeNS("", "bar"), false) + assert_equals(el.getAttribute("bar"), null) + assert_equals(el.getAttributeNS(null, "bar"), null) + assert_equals(el.getAttributeNS("", "bar"), null) +}, "Unset attributes return null") +test(function() { + var el = document.createElement("div") + el.setAttributeNS("ab", "attr", "t1") + el.setAttributeNS("kl", "attr", "t2") + assert_equals(el.hasAttribute("attr"), true) + assert_equals(el.hasAttributeNS("ab", "attr"), true) + assert_equals(el.hasAttributeNS("kl", "attr"), true) + assert_equals(el.getAttribute("attr"), "t1") + assert_equals(el.getAttributeNS("ab", "attr"), "t1") + assert_equals(el.getAttributeNS("kl", "attr"), "t2") + assert_equals(el.getAttributeNS(null, "attr"), null) + assert_equals(el.getAttributeNS("", "attr"), null) +}, "First set attribute is returned by getAttribute") +test(function() { + var el = document.createElement("div") + el.setAttribute("style", "color:#fff;") + assert_equals(el.hasAttribute("style"), true) + assert_equals(el.hasAttributeNS(null, "style"), true) + assert_equals(el.hasAttributeNS("", "style"), true) + assert_equals(el.getAttribute("style"), "color:#fff;") + assert_equals(el.getAttributeNS(null, "style"), "color:#fff;") + assert_equals(el.getAttributeNS("", "style"), "color:#fff;") +}, "Style attributes are not normalized") +test(function() { + var el = document.createElement("div") + el.setAttributeNS("", "ALIGN", "left") + assert_equals(el.hasAttribute("ALIGN"), false) + assert_equals(el.hasAttribute("align"), false) + assert_equals(el.hasAttributeNS(null, "ALIGN"), true) + assert_equals(el.hasAttributeNS(null, "align"), false) + assert_equals(el.hasAttributeNS("", "ALIGN"), true) + assert_equals(el.hasAttributeNS("", "align"), false) + assert_equals(el.getAttribute("ALIGN"), null) + assert_equals(el.getAttribute("align"), null) + assert_equals(el.getAttributeNS(null, "ALIGN"), "left") + assert_equals(el.getAttributeNS("", "ALIGN"), "left") + assert_equals(el.getAttributeNS(null, "align"), null) + assert_equals(el.getAttributeNS("", "align"), null) + el.removeAttributeNS("", "ALIGN") +}, "Only lowercase attributes are returned on HTML elements (upper case attribute)") +test(function() { + var el = document.createElement("div") + el.setAttributeNS("", "CHEEseCaKe", "tasty") + assert_equals(el.hasAttribute("CHEESECAKE"), false) + assert_equals(el.hasAttribute("CHEEseCaKe"), false) + assert_equals(el.hasAttribute("cheesecake"), false) + assert_equals(el.hasAttributeNS("", "CHEESECAKE"), false) + assert_equals(el.hasAttributeNS("", "CHEEseCaKe"), true) + assert_equals(el.hasAttributeNS("", "cheesecake"), false) + assert_equals(el.hasAttributeNS(null, "CHEESECAKE"), false) + assert_equals(el.hasAttributeNS(null, "CHEEseCaKe"), true) + assert_equals(el.hasAttributeNS(null, "cheesecake"), false) + assert_equals(el.getAttribute("CHEESECAKE"), null) + assert_equals(el.getAttribute("CHEEseCaKe"), null) + assert_equals(el.getAttribute("cheesecake"), null) + assert_equals(el.getAttributeNS(null, "CHEESECAKE"), null) + assert_equals(el.getAttributeNS("", "CHEESECAKE"), null) + assert_equals(el.getAttributeNS(null, "CHEEseCaKe"), "tasty") + assert_equals(el.getAttributeNS("", "CHEEseCaKe"), "tasty") + assert_equals(el.getAttributeNS(null, "cheesecake"), null) + assert_equals(el.getAttributeNS("", "cheesecake"), null) + el.removeAttributeNS("", "CHEEseCaKe") +}, "Only lowercase attributes are returned on HTML elements (mixed case attribute)") +test(function() { + var el = document.createElement("div") + document.body.appendChild(el) + el.setAttributeNS("", "align", "left") + el.setAttributeNS("xx", "align", "right") + el.setAttributeNS("", "foo", "left") + el.setAttributeNS("xx", "foo", "right") + assert_equals(el.hasAttribute("align"), true) + assert_equals(el.hasAttribute("foo"), true) + assert_equals(el.hasAttributeNS("xx", "align"), true) + assert_equals(el.hasAttributeNS(null, "foo"), true) + assert_equals(el.getAttribute("align"), "left") + assert_equals(el.getAttribute("foo"), "left") + assert_equals(el.getAttributeNS("xx", "align"), "right") + assert_equals(el.getAttributeNS(null, "foo"), "left") + assert_equals(el.getAttributeNS("", "foo"), "left") + el.removeAttributeNS("", "align") + el.removeAttributeNS("xx", "align") + el.removeAttributeNS("", "foo") + el.removeAttributeNS("xx", "foo") + document.body.removeChild(el) +}, "First set attribute is returned with mapped attribute set first") +test(function() { + var el = document.createElement("div") + el.setAttributeNS("xx", "align", "right") + el.setAttributeNS("", "align", "left") + el.setAttributeNS("xx", "foo", "right") + el.setAttributeNS("", "foo", "left") + assert_equals(el.hasAttribute("align"), true) + assert_equals(el.hasAttribute("foo"), true) + assert_equals(el.hasAttributeNS("xx", "align"), true) + assert_equals(el.hasAttributeNS(null, "foo"), true) + assert_equals(el.getAttribute("align"), "right") + assert_equals(el.getAttribute("foo"), "right") + assert_equals(el.getAttributeNS("xx", "align"), "right") + assert_equals(el.getAttributeNS(null, "foo"), "left") + assert_equals(el.getAttributeNS("", "foo"), "left") + el.removeAttributeNS("", "align") + el.removeAttributeNS("xx", "align") + el.removeAttributeNS("", "foo") + el.removeAttributeNS("xx", "foo") +}, "First set attribute is returned with mapped attribute set later") + +test(function() { + var el = document.createElementNS("http://www.example.com", "foo") + el.setAttribute("A", "test") + assert_equals(el.hasAttribute("A"), true, "hasAttribute()") + assert_equals(el.hasAttributeNS("", "A"), true, "el.hasAttributeNS(\"\")") + assert_equals(el.hasAttributeNS(null, "A"), true, "el.hasAttributeNS(null)") + assert_equals(el.hasAttributeNS(undefined, "A"), true, "el.hasAttributeNS(undefined)") + assert_equals(el.hasAttributeNS("foo", "A"), false, "el.hasAttributeNS(\"foo\")") + + assert_equals(el.getAttribute("A"), "test", "getAttribute()") + assert_equals(el.getAttributeNS("", "A"), "test", "el.getAttributeNS(\"\")") + assert_equals(el.getAttributeNS(null, "A"), "test", "el.getAttributeNS(null)") + assert_equals(el.getAttributeNS(undefined, "A"), "test", "el.getAttributeNS(undefined)") + assert_equals(el.getAttributeNS("foo", "A"), null, "el.getAttributeNS(\"foo\")") +}, "Non-HTML element with upper-case attribute") + +test(function() { + var el = document.createElement("div") + el.setAttribute("pre:fix", "value 1") + el.setAttribute("fix", "value 2") + + var prefixed = el.attributes[0] + assert_equals(prefixed.localName, "pre:fix", "prefixed local name") + assert_equals(prefixed.namespaceURI, null, "prefixed namespace") + + var unprefixed = el.attributes[1] + assert_equals(unprefixed.localName, "fix", "unprefixed local name") + assert_equals(unprefixed.namespaceURI, null, "unprefixed namespace") + + el.removeAttributeNS(null, "pre:fix") + assert_equals(el.attributes[0], unprefixed) +}, "Attribute with prefix in local name") + +test(function() { + var el = document.createElement("div") + el.setAttribute("foo", "bar") + var attr = el.attributes[0] + assert_equals(attr.ownerElement, el) + el.removeAttribute("foo") + assert_equals(attr.ownerElement, null) +}, "Attribute loses its owner when removed") + +test(function() { + var el = document.createElement("div") + el.setAttribute("foo", "bar") + var attr = el.attributes[0] + var attrNode = el.getAttributeNode("foo"); + var attrNodeNS = el.getAttributeNodeNS("", "foo"); + assert_equals(attr, attrNode); + assert_equals(attr, attrNodeNS); + el.setAttributeNS("x", "foo2", "bar2"); + var attr2 = el.attributes[1]; + var attrNodeNS2 = el.getAttributeNodeNS("x", "foo2"); + assert_equals(attr2, attrNodeNS2); +}, "Basic functionality of getAttributeNode/getAttributeNodeNS") + +test(function() { + var el = document.createElement("div") + el.setAttribute("foo", "bar") + var attrNode = el.getAttributeNode("foo"); + var attrNodeNS = el.getAttributeNodeNS("", "foo"); + assert_equals(attrNode, attrNodeNS); + el.removeAttribute("foo"); + var el2 = document.createElement("div"); + el2.setAttributeNode(attrNode); + assert_equals(attrNode, el2.getAttributeNode("foo")); + assert_equals(attrNode, el2.attributes[0]); + assert_equals(attrNode.ownerElement, el2); + assert_equals(attrNode.value, "bar"); + + var el3 = document.createElement("div"); + el2.removeAttribute("foo"); + el3.setAttribute("foo", "baz"); + el3.setAttributeNode(attrNode); + assert_equals(el3.getAttribute("foo"), "bar"); +}, "Basic functionality of setAttributeNode") + +test(function() { + var el = document.createElement("div"); + var attr1 = document.createAttributeNS("ns1", "p1:name"); + attr1.value = "value1"; + var attr2 = document.createAttributeNS("ns2", "p2:name"); + attr2.value = "value2"; + el.setAttributeNode(attr1); + el.setAttributeNode(attr2); + assert_equals(el.getAttributeNodeNS("ns1", "name").value, "value1"); + assert_equals(el.getAttributeNodeNS("ns2", "name").value, "value2"); +}, "setAttributeNode should distinguish attributes with same local name and different namespaces") + +test(function() { + var el = document.createElement("div"); + var attr1 = document.createAttributeNS("ns1", "p1:name"); + attr1.value = "value1"; + var attr2 = document.createAttributeNS("ns1", "p1:NAME"); + attr2.value = "VALUE2"; + el.setAttributeNode(attr1); + el.setAttributeNode(attr2); + assert_equals(el.getAttributeNodeNS("ns1", "name").value, "value1"); + assert_equals(el.getAttributeNodeNS("ns1", "NAME").value, "VALUE2"); +}, "setAttributeNode doesn't have case-insensitivity even with an HTMLElement") + +test(function() { + var el = document.createElement("div") + el.setAttributeNS("x", "foo", "bar") + var attrNode = el.getAttributeNodeNS("x", "foo"); + el.removeAttribute("foo"); + var el2 = document.createElement("div"); + el2.setAttributeNS("x", "foo", "baz"); + el2.setAttributeNodeNS(attrNode); + assert_equals(el2.getAttributeNS("x", "foo"), "bar"); +}, "Basic functionality of setAttributeNodeNS") + +test(function() { + var el = document.createElement("div"); + var other = document.createElement("div"); + var attr = document.createAttribute("foo"); + assert_equals(el.setAttributeNode(attr), null); + assert_equals(attr.ownerElement, el); + assert_throws_dom("INUSE_ATTRIBUTE_ERR", + function() { other.setAttributeNode(attr) }, + "Attribute already associated with el") +}, "If attr’s element is neither null nor element, throw an InUseAttributeError."); + +test(function() { + var el = document.createElement("div"); + var attr = document.createAttribute("foo"); + assert_equals(el.setAttributeNode(attr), null); + el.setAttribute("bar", "qux"); + assert_equals(el.setAttributeNode(attr), attr); + assert_equals(el.attributes[0], attr); +}, "Replacing an attr by itself"); + +test(function() { + var el = document.createElement("div") + el.setAttribute("foo", "bar") + var attrNode = el.getAttributeNode("foo"); + el.removeAttributeNode(attrNode); + var el2 = document.createElement("div"); + el2.setAttributeNode(attrNode); + assert_equals(el2.attributes[0], attrNode); + assert_equals(el.attributes.length, 0); +}, "Basic functionality of removeAttributeNode") + +test(function() { + var el = document.createElement("div") + el.setAttribute("foo", "bar") + var attrNode = el.getAttributeNode("foo"); + var el2 = document.createElement("div"); + assert_throws_dom("INUSE_ATTRIBUTE_ERR", function(){el2.setAttributeNode(attrNode)}); +}, "setAttributeNode on bound attribute should throw InUseAttributeError") + +// Have to use an async_test to see what a DOMAttrModified listener sees, +// because otherwise the event dispatch code will swallow our exceptions. And +// we want to make sure this test always happens, even when no mutation events +// run. +var setAttributeNode_mutation_test = async_test("setAttributeNode, if it fires mutation events, should fire one with the new node when resetting an existing attribute"); + +test(function(){ + var el = document.createElement("div") + var attrNode1 = document.createAttribute("foo"); + attrNode1.value = "bar"; + el.setAttributeNode(attrNode1); + var attrNode2 = document.createAttribute("foo"); + attrNode2.value = "baz"; + + el.addEventListener("DOMAttrModified", function(e) { + // If this never gets called, that's OK, I guess. But if it gets called, it + // better represent a single modification with attrNode2 as the relatedNode. + // We have to do an inner test() call here, because otherwise the exceptions + // our asserts trigger will get swallowed by the event dispatch code. + setAttributeNode_mutation_test.step(function() { + assert_equals(e.attrName, "foo"); + assert_equals(e.attrChange, MutationEvent.MODIFICATION); + assert_equals(e.prevValue, "bar"); + assert_equals(e.newValue, "baz"); + assert_equals(e.relatedNode, attrNode2); + }); + }); + + var oldNode = el.setAttributeNode(attrNode2); + assert_equals(oldNode, attrNode1, + "Must return the old attr node from a setAttributeNode call"); +}, "setAttributeNode, if it fires mutation events, should fire one with the new node when resetting an existing attribute (outer shell)"); +setAttributeNode_mutation_test.done(); + +test(function(){ + var el = document.createElement("div") + el.setAttribute("a", "b"); + el.setAttribute("c", "d"); + + assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.name }), + ["a", "c"]); + assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.value }), + ["b", "d"]); + + var attrNode = document.createAttribute("a"); + attrNode.value = "e"; + el.setAttributeNode(attrNode); + + assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.name }), + ["a", "c"]); + assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.value }), + ["e", "d"]); +}, "setAttributeNode called with an Attr that has the same name as an existing one should not change attribute order"); + +test(function() { + var el = document.createElement("div"); + el.setAttribute("foo", "bar"); + assert_equals(el.getAttributeNames().length, 1); + assert_equals(el.getAttributeNames()[0], el.attributes[0].name); + assert_equals(el.getAttributeNames()[0], "foo"); + + el.removeAttribute("foo"); + assert_equals(el.getAttributeNames().length, 0); + + el.setAttribute("foo", "bar"); + el.setAttributeNS("", "FOO", "bar"); + el.setAttributeNS("dummy1", "foo", "bar"); + el.setAttributeNS("dummy2", "dummy:foo", "bar"); + assert_equals(el.getAttributeNames().length, 4); + assert_equals(el.getAttributeNames()[0], "foo"); + assert_equals(el.getAttributeNames()[1], "FOO"); + assert_equals(el.getAttributeNames()[2], "foo"); + assert_equals(el.getAttributeNames()[3], "dummy:foo"); + assert_equals(el.getAttributeNames()[0], el.attributes[0].name); + assert_equals(el.getAttributeNames()[1], el.attributes[1].name); + assert_equals(el.getAttributeNames()[2], el.attributes[2].name); + assert_equals(el.getAttributeNames()[3], el.attributes[3].name); + + el.removeAttributeNS("", "FOO"); + assert_equals(el.getAttributeNames().length, 3); + assert_equals(el.getAttributeNames()[0], "foo"); + assert_equals(el.getAttributeNames()[1], "foo"); + assert_equals(el.getAttributeNames()[2], "dummy:foo"); + assert_equals(el.getAttributeNames()[0], el.attributes[0].name); + assert_equals(el.getAttributeNames()[1], el.attributes[1].name); + assert_equals(el.getAttributeNames()[2], el.attributes[2].name); +}, "getAttributeNames tests"); + +function getEnumerableOwnProps1(obj) { + var arr = []; + for (var prop in obj) { + if (obj.hasOwnProperty(prop)) { + arr.push(prop); + } + } + return arr; +} + +function getEnumerableOwnProps2(obj) { + return Object.getOwnPropertyNames(obj).filter( + function (name) { return Object.getOwnPropertyDescriptor(obj, name).enumerable; }) +} + +test(function() { + var el = document.createElement("div"); + el.setAttribute("a", ""); + el.setAttribute("b", ""); + assert_array_equals(getEnumerableOwnProps1(el.attributes), + ["0", "1"]) + assert_array_equals(getEnumerableOwnProps2(el.attributes), + ["0", "1"]) + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "a", "b"]) +}, "Own property correctness with basic attributes"); + +test(function() { + var el = document.createElement("div"); + el.setAttributeNS("", "a", ""); + el.setAttribute("b", ""); + el.setAttributeNS("foo", "a", ""); + assert_array_equals(getEnumerableOwnProps1(el.attributes), + ["0", "1", "2"]) + assert_array_equals(getEnumerableOwnProps2(el.attributes), + ["0", "1", "2"]) + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "a", "b"]) + for (var propName of Object.getOwnPropertyNames(el.attributes)) { + assert_true(el.attributes[propName] instanceof Attr, + "el.attributes has an Attr for property name " + propName); + } +}, "Own property correctness with non-namespaced attribute before same-name namespaced one"); + +test(function() { + var el = document.createElement("div"); + el.setAttributeNS("foo", "a", ""); + el.setAttribute("b", ""); + el.setAttributeNS("", "a", ""); + assert_array_equals(getEnumerableOwnProps1(el.attributes), + ["0", "1", "2"]) + assert_array_equals(getEnumerableOwnProps2(el.attributes), + ["0", "1", "2"]) + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "a", "b"]) + for (var propName of Object.getOwnPropertyNames(el.attributes)) { + assert_true(el.attributes[propName] instanceof Attr, + "el.attributes has an Attr for property name " + propName); + } +}, "Own property correctness with namespaced attribute before same-name non-namespaced one"); + +test(function() { + var el = document.createElement("div"); + el.setAttributeNS("foo", "a:b", ""); + el.setAttributeNS("foo", "c:d", ""); + el.setAttributeNS("bar", "a:b", ""); + assert_array_equals(getEnumerableOwnProps1(el.attributes), + ["0", "1", "2"]) + assert_array_equals(getEnumerableOwnProps2(el.attributes), + ["0", "1", "2"]) + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "a:b", "c:d"]) + for (var propName of Object.getOwnPropertyNames(el.attributes)) { + assert_true(el.attributes[propName] instanceof Attr, + "el.attributes has an Attr for property name " + propName); + } +}, "Own property correctness with two namespaced attributes with the same name-with-prefix"); + +test(function() { + var el = document.createElement("div"); + el.setAttributeNS("foo", "A:B", ""); + el.setAttributeNS("bar", "c:D", ""); + el.setAttributeNS("baz", "e:F", ""); + el.setAttributeNS("qux", "g:h", ""); + el.setAttributeNS("", "I", ""); + el.setAttributeNS("", "j", ""); + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "3", "4", "5", "g:h", "j"]) + for (var propName of Object.getOwnPropertyNames(el.attributes)) { + assert_true(el.attributes[propName] instanceof Attr, + "el.attributes has an Attr for property name " + propName); + } +}, "Own property names should only include all-lowercase qualified names for an HTML element in an HTML document"); + +test(function() { + var el = document.createElementNS("", "div"); + el.setAttributeNS("foo", "A:B", ""); + el.setAttributeNS("bar", "c:D", ""); + el.setAttributeNS("baz", "e:F", ""); + el.setAttributeNS("qux", "g:h", ""); + el.setAttributeNS("", "I", ""); + el.setAttributeNS("", "j", ""); + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "3", "4", "5", "A:B", "c:D", "e:F", "g:h", "I", "j"]) + for (var propName of Object.getOwnPropertyNames(el.attributes)) { + assert_true(el.attributes[propName] instanceof Attr, + "el.attributes has an Attr for property name " + propName); + } +}, "Own property names should include all qualified names for a non-HTML element in an HTML document"); + +test(function() { + var doc = document.implementation.createDocument(null, ""); + assert_equals(doc.contentType, "application/xml"); + var el = doc.createElementNS("http://www.w3.org/1999/xhtml", "div"); + el.setAttributeNS("foo", "A:B", ""); + el.setAttributeNS("bar", "c:D", ""); + el.setAttributeNS("baz", "e:F", ""); + el.setAttributeNS("qux", "g:h", ""); + el.setAttributeNS("", "I", ""); + el.setAttributeNS("", "j", ""); + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "3", "4", "5", "A:B", "c:D", "e:F", "g:h", "I", "j"]) + for (var propName of Object.getOwnPropertyNames(el.attributes)) { + assert_true(el.attributes[propName] instanceof Attr, + "el.attributes has an Attr for property name " + propName); + } +}, "Own property names should include all qualified names for an HTML element in a non-HTML document"); +</script> |