tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

attributes.html (35775B)


      1 <!DOCTYPE html>
      2 <meta charset=utf-8>
      3 <title>Attributes tests</title>
      4 <link rel=help href="https://dom.spec.whatwg.org/#attr">
      5 <link rel=help href="https://dom.spec.whatwg.org/#dom-element-setattribute">
      6 <link rel=help href="https://dom.spec.whatwg.org/#dom-element-setattributens">
      7 <script src="/resources/testharness.js"></script>
      8 <script src="/resources/testharnessreport.js"></script>
      9 <script src="attributes.js"></script>
     10 <script src="productions.js"></script>
     11 <div id="log"></div>
     12 <span id="test1"></span>
     13 <span class="&amp;&lt;&gt;foo"></span>
     14 <script>
     15 var XML = "http://www.w3.org/XML/1998/namespace"
     16 var XMLNS = "http://www.w3.org/2000/xmlns/"
     17 
     18 // toggleAttribute exhaustive tests
     19 // Step 1
     20 test(function() {
     21  var el = document.createElement("foo")
     22  for (var i = 0; i < invalid_names.length; i++) {
     23    assert_throws_dom(
     24      "INVALID_CHARACTER_ERR",
     25      function() { el.toggleAttribute(invalid_names[i], true) },
     26      `toggleAttribute("${invalid_names[i]}", true)`);
     27  }
     28  for (var i = 0; i < invalid_names.length; i++) {
     29    assert_throws_dom(
     30      "INVALID_CHARACTER_ERR",
     31      function() { el.toggleAttribute(invalid_names[i]) },
     32      `toggleAttribute("${invalid_names[i]}")`);
     33  }
     34  for (var i = 0; i < invalid_names.length; i++) {
     35    assert_throws_dom(
     36      "INVALID_CHARACTER_ERR",
     37      function() { el.toggleAttribute(invalid_names[i], false) },
     38      `toggleAttribute("${invalid_names[i]}", false)`);
     39  }
     40 }, "When qualifiedName does not match the Name production, an " +
     41   "INVALID_CHARACTER_ERR exception is to be thrown. (toggleAttribute)")
     42 
     43 // Step 2
     44 test(function() {
     45  var el = document.createElement("div")
     46  assert_true(el.toggleAttribute("ALIGN"))
     47  assert_true(!el.hasAttributeNS("", "ALIGN"))
     48  assert_true(el.hasAttributeNS("", "align"))
     49  assert_true(el.hasAttribute("align"))
     50  assert_true(!el.toggleAttribute("ALIGN"))
     51  assert_true(!el.hasAttributeNS("", "ALIGN"))
     52  assert_true(!el.hasAttributeNS("", "align"))
     53  assert_true(!el.hasAttribute("align"))
     54 }, "toggleAttribute should lowercase its name argument (upper case attribute)")
     55 test(function() {
     56  var el = document.createElement("div")
     57  assert_true(el.toggleAttribute("CHEEseCaKe"))
     58  assert_true(!el.hasAttributeNS("", "CHEEseCaKe"))
     59  assert_true(el.hasAttributeNS("", "cheesecake"))
     60  assert_true(el.hasAttribute("cheesecake"))
     61 }, "toggleAttribute should lowercase its name argument (mixed case attribute)")
     62 
     63 // Step 3
     64 test(function() {
     65  var el = document.createElement("foo")
     66  var tests = ["xmlns", "xmlns:a", "xmlnsx", "xmlns0"]
     67  for (var i = 0; i < tests.length; i++) {
     68    assert_true(el.toggleAttribute(tests[i]));
     69    assert_true(el.hasAttribute(tests[i]));
     70  }
     71 }, "toggleAttribute should not throw even when qualifiedName starts with 'xmlns'")
     72 
     73 // Step 4
     74 test(function() {
     75  var el = document.createElement("foo")
     76  for (var i = 0; i < valid_names.length; i++) {
     77    assert_true(el.toggleAttribute(valid_names[i]))
     78    assert_true(el.hasAttribute(valid_names[i]))
     79    assert_true(!el.toggleAttribute(valid_names[i]))
     80    assert_true(!el.hasAttribute(valid_names[i]))
     81    // Check using force attr
     82    assert_true(el.toggleAttribute(valid_names[i], true))
     83    assert_true(el.hasAttribute(valid_names[i]))
     84    assert_true(el.toggleAttribute(valid_names[i], true))
     85    assert_true(el.hasAttribute(valid_names[i]))
     86    assert_true(!el.toggleAttribute(valid_names[i], false))
     87    assert_true(!el.hasAttribute(valid_names[i]))
     88  }
     89 }, "Basic functionality should be intact. (toggleAttribute)")
     90 
     91 // Step 5
     92 test(function() {
     93  var el = document.createElement("foo")
     94  el.toggleAttribute("a")
     95  el.toggleAttribute("b")
     96  el.setAttribute("a", "thing")
     97  el.toggleAttribute("c")
     98  attributes_are(el, [["a", "thing"],
     99                      ["b", ""],
    100                      ["c", ""]])
    101 }, "toggleAttribute should not change the order of previously set attributes.")
    102 test(function() {
    103  var el = document.createElement("baz")
    104  el.setAttributeNS("ab", "attr", "fail")
    105  el.setAttributeNS("kl", "attr", "pass")
    106  el.toggleAttribute("attr")
    107  attributes_are(el, [["attr", "pass", "kl"]])
    108 }, "toggleAttribute should set the first attribute with the given name")
    109 test(function() {
    110  // Based on a test by David Flanagan.
    111  var el = document.createElement("baz")
    112  el.setAttributeNS("foo", "foo:bar", "1");
    113  el.setAttributeNS("foo", "foo:bat", "2");
    114  assert_equals(el.getAttribute("foo:bar"), "1")
    115  assert_equals(el.getAttribute("foo:bat"), "2")
    116  attr_is(el.attributes[0], "1", "bar", "foo", "foo", "foo:bar")
    117  attr_is(el.attributes[1], "2", "bat", "foo", "foo", "foo:bat")
    118  el.toggleAttribute("foo:bar");
    119  assert_true(!el.hasAttribute("foo:bar"))
    120  attr_is(el.attributes[0], "2", "bat", "foo", "foo", "foo:bat")
    121 }, "toggleAttribute should set the attribute with the given qualified name")
    122 
    123 test(function() {
    124  var el = document.createElement("foo")
    125  el.style = "color: red; background-color: green"
    126  assert_equals(el.toggleAttribute("style"), false)
    127 }, "Toggling element with inline style should make inline style disappear")
    128 
    129 // setAttribute exhaustive tests
    130 // Step 1
    131 test(function() {
    132  var el = document.createElement("foo")
    133  for (var i = 0; i < invalid_names.length; i++) {
    134    assert_throws_dom("INVALID_CHARACTER_ERR", function() { el.setAttribute(invalid_names[i], "test") })
    135  }
    136 }, "When qualifiedName does not match the Name production, an " +
    137   "INVALID_CHARACTER_ERR exception is to be thrown. (setAttribute)")
    138 
    139 // Step 2
    140 test(function() {
    141  var el = document.createElement("div")
    142  el.setAttribute("ALIGN", "left")
    143  assert_equals(el.getAttributeNS("", "ALIGN"), null)
    144  assert_equals(el.getAttributeNS("", "align"), "left")
    145  assert_equals(el.getAttribute("align"), "left")
    146 }, "setAttribute should lowercase its name argument (upper case attribute)")
    147 test(function() {
    148  var el = document.createElement("div")
    149  el.setAttribute("CHEEseCaKe", "tasty")
    150  assert_equals(el.getAttributeNS("", "CHEEseCaKe"), null)
    151  assert_equals(el.getAttributeNS("", "cheesecake"), "tasty")
    152  assert_equals(el.getAttribute("cheesecake"), "tasty")
    153 }, "setAttribute should lowercase its name argument (mixed case attribute)")
    154 
    155 // Step 3
    156 test(function() {
    157  var el = document.createElement("foo")
    158  var tests = ["xmlns", "xmlns:a", "xmlnsx", "xmlns0"]
    159  for (var i = 0; i < tests.length; i++) {
    160    el.setAttribute(tests[i], "success");
    161  }
    162 }, "setAttribute should not throw even when qualifiedName starts with 'xmlns'")
    163 
    164 // Step 4
    165 test(function() {
    166  var el = document.createElement("foo")
    167  for (var i = 0; i < valid_names.length; i++) {
    168    el.setAttribute(valid_names[i], "test")
    169    assert_equals(el.getAttribute(valid_names[i]), "test")
    170  }
    171 }, "Basic functionality should be intact.")
    172 
    173 // Step 5
    174 test(function() {
    175  var el = document.createElement("foo")
    176  el.setAttribute("a", "1")
    177  el.setAttribute("b", "2")
    178  el.setAttribute("a", "3")
    179  el.setAttribute("c", "4")
    180  attributes_are(el, [["a", "3"],
    181                      ["b", "2"],
    182                      ["c", "4"]])
    183 }, "setAttribute should not change the order of previously set attributes.")
    184 test(function() {
    185  var el = document.createElement("baz")
    186  el.setAttributeNS("ab", "attr", "fail")
    187  el.setAttributeNS("kl", "attr", "pass")
    188  el.setAttribute("attr", "pass")
    189  attributes_are(el, [["attr", "pass", "ab"],
    190                      ["attr", "pass", "kl"]])
    191 }, "setAttribute should set the first attribute with the given name")
    192 test(function() {
    193  // Based on a test by David Flanagan.
    194  var el = document.createElement("baz")
    195  el.setAttributeNS("foo", "foo:bar", "1");
    196  assert_equals(el.getAttribute("foo:bar"), "1")
    197  attr_is(el.attributes[0], "1", "bar", "foo", "foo", "foo:bar")
    198  el.setAttribute("foo:bar", "2");
    199  assert_equals(el.getAttribute("foo:bar"), "2")
    200  attr_is(el.attributes[0], "2", "bar", "foo", "foo", "foo:bar")
    201 }, "setAttribute should set the attribute with the given qualified name")
    202 
    203 // setAttributeNS exhaustive tests
    204 // Step 1
    205 test(function() {
    206  var el = document.createElement("foo")
    207  for (var i = 0, il = invalid_names.length; i < il; ++i) {
    208    assert_throws_dom("INVALID_CHARACTER_ERR",
    209                      function() { el.setAttributeNS("a", invalid_names[i], "fail") })
    210  }
    211 }, "When qualifiedName does not match the Name production, an " +
    212   "INVALID_CHARACTER_ERR exception is to be thrown. (setAttributeNS)")
    213 
    214 // Step 2
    215 test(function() {
    216  var el = document.createElement("foo")
    217  for (var i = 0, il = invalid_qnames.length; i < il; ++i) {
    218    assert_throws_dom("INVALID_CHARACTER_ERR",
    219                      function() { el.setAttributeNS("a", invalid_qnames[i], "fail") },
    220                      "Expected exception for " + invalid_qnames[i] + ".")
    221  }
    222 }, "When qualifiedName does not match the QName production, an " +
    223   "INVALID_CHARACTER_ERR exception is to be thrown.")
    224 
    225 // Step 3
    226 test(function() {
    227  var el = document.createElement("foo")
    228  el.setAttributeNS(null, "aa", "bb")
    229  el.setAttributeNS("", "xx", "bb")
    230  attributes_are(el, [["aa", "bb"],
    231                      ["xx", "bb"]])
    232 }, "null and the empty string should result in a null namespace.")
    233 
    234 // Step 4
    235 test(function() {
    236  var el = document.createElement("foo")
    237  assert_throws_dom("NAMESPACE_ERR",
    238                    function() { el.setAttributeNS("", "aa:bb", "fail") })
    239  assert_throws_dom("NAMESPACE_ERR",
    240                    function() { el.setAttributeNS(null, "aa:bb", "fail") })
    241 }, "A namespace is required to use a prefix.")
    242 
    243 // Step 5
    244 test(function() {
    245  var el = document.createElement("foo")
    246  assert_throws_dom("NAMESPACE_ERR",
    247                    function() { el.setAttributeNS("a", "xml:bb", "fail") })
    248 }, "The xml prefix should not be allowed for arbitrary namespaces")
    249 test(function() {
    250  var el = document.createElement("foo")
    251  el.setAttributeNS(XML, "a:bb", "pass")
    252  assert_equals(el.attributes.length, 1)
    253  attr_is(el.attributes[0], "pass", "bb", XML, "a", "a:bb")
    254 }, "XML-namespaced attributes don't need an xml prefix")
    255 
    256 // Step 6
    257 test(function() {
    258  var el = document.createElement("foo")
    259  assert_throws_dom("NAMESPACE_ERR",
    260                    function() { el.setAttributeNS("a", "xmlns:bb", "fail") })
    261 }, "The xmlns prefix should not be allowed for arbitrary namespaces")
    262 test(function() {
    263  var el = document.createElement("foo")
    264  assert_throws_dom("NAMESPACE_ERR",
    265                    function() { el.setAttributeNS("a", "xmlns", "fail") })
    266 }, "The xmlns qualified name should not be allowed for arbitrary namespaces")
    267 test(function() {
    268  var el = document.createElement("foo")
    269  el.setAttributeNS("ns", "a:xmlns", "pass")
    270  assert_equals(el.attributes.length, 1)
    271  attr_is(el.attributes[0], "pass", "xmlns", "ns", "a", "a:xmlns")
    272 }, "xmlns should be allowed as local name")
    273 
    274 // Step 7
    275 test(function() {
    276  var el = document.createElement("foo")
    277  assert_throws_dom("NAMESPACE_ERR",
    278                    function() { el.setAttributeNS(XMLNS, "a:xmlns", "fail") })
    279  assert_throws_dom("NAMESPACE_ERR",
    280                    function() { el.setAttributeNS(XMLNS, "b:foo", "fail") })
    281 }, "The XMLNS namespace should require xmlns as prefix or qualified name")
    282 test(function() {
    283  var el = document.createElement("foo")
    284  el.setAttributeNS(XMLNS, "xmlns:a", "pass")
    285  assert_equals(el.attributes.length, 1)
    286  attr_is(el.attributes[0], "pass", "a", XMLNS, "xmlns", "xmlns:a")
    287 }, "xmlns should be allowed as prefix in the XMLNS namespace")
    288 test(function() {
    289  var el = document.createElement("foo")
    290  el.setAttributeNS(XMLNS, "xmlns", "pass")
    291  assert_equals(el.attributes.length, 1)
    292  attr_is(el.attributes[0], "pass", "xmlns", XMLNS, null, "xmlns")
    293 }, "xmlns should be allowed as qualified name in the XMLNS namespace")
    294 
    295 // Step 8-9
    296 test(function() {
    297  var el = document.createElement("foo")
    298  el.setAttributeNS("a", "foo:bar", "X")
    299  assert_equals(el.attributes.length, 1)
    300  attr_is(el.attributes[0], "X", "bar", "a", "foo", "foo:bar")
    301 
    302  el.setAttributeNS("a", "quux:bar", "Y")
    303  assert_equals(el.attributes.length, 1)
    304  attr_is(el.attributes[0], "Y", "bar", "a", "foo", "foo:bar")
    305  el.removeAttributeNS("a", "bar")
    306 }, "Setting the same attribute with another prefix should not change the prefix")
    307 
    308 // Miscellaneous tests
    309 test(function() {
    310  var el = document.createElement("iframe")
    311  el.setAttribute("src", "file:///home")
    312  assert_equals(el.getAttribute("src"), "file:///home")
    313 }, "setAttribute should not throw even if a load is not allowed")
    314 test(function() {
    315  var docFragment = document.createDocumentFragment()
    316  var newOne = document.createElement("newElement")
    317  newOne.setAttribute("newdomestic", "Yes")
    318  docFragment.appendChild(newOne)
    319  var domesticNode = docFragment.firstChild
    320  var attr = domesticNode.attributes.item(0)
    321  attr_is(attr, "Yes", "newdomestic", null, null, "newdomestic")
    322 }, "Attributes should work in document fragments.")
    323 test(function() {
    324  var el = document.createElement("foo")
    325  el.setAttribute("x", "y")
    326  var attr = el.attributes[0]
    327  attr.value = "Y&lt;"
    328  attr_is(attr, "Y&lt;", "x", null, null, "x")
    329  assert_equals(el.getAttribute("x"), "Y&lt;")
    330 }, "Attribute values should not be parsed.")
    331 test(function() {
    332  var el = document.getElementsByTagName("span")[0]
    333  attr_is(el.attributes[0], "test1", "id", null, null, "id")
    334 }, "Specified attributes should be accessible.")
    335 test(function() {
    336  var el = document.getElementsByTagName("span")[1]
    337  attr_is(el.attributes[0], "&<>foo", "class", null, null, "class")
    338 }, "Entities in attributes should have been expanded while parsing.")
    339 
    340 test(function() {
    341  var el = document.createElement("div")
    342  assert_equals(el.hasAttribute("bar"), false)
    343  assert_equals(el.hasAttributeNS(null, "bar"), false)
    344  assert_equals(el.hasAttributeNS("", "bar"), false)
    345  assert_equals(el.getAttribute("bar"), null)
    346  assert_equals(el.getAttributeNS(null, "bar"), null)
    347  assert_equals(el.getAttributeNS("", "bar"), null)
    348 }, "Unset attributes return null")
    349 test(function() {
    350  var el = document.createElement("div")
    351  el.setAttributeNS("ab", "attr", "t1")
    352  el.setAttributeNS("kl", "attr", "t2")
    353  assert_equals(el.hasAttribute("attr"), true)
    354  assert_equals(el.hasAttributeNS("ab", "attr"), true)
    355  assert_equals(el.hasAttributeNS("kl", "attr"), true)
    356  assert_equals(el.getAttribute("attr"), "t1")
    357  assert_equals(el.getAttributeNS("ab", "attr"), "t1")
    358  assert_equals(el.getAttributeNS("kl", "attr"), "t2")
    359  assert_equals(el.getAttributeNS(null, "attr"), null)
    360  assert_equals(el.getAttributeNS("", "attr"), null)
    361 }, "First set attribute is returned by getAttribute")
    362 test(function() {
    363  var el = document.createElement("div")
    364  el.setAttribute("style", "color:#fff;")
    365  assert_equals(el.hasAttribute("style"), true)
    366  assert_equals(el.hasAttributeNS(null, "style"), true)
    367  assert_equals(el.hasAttributeNS("", "style"), true)
    368  assert_equals(el.getAttribute("style"), "color:#fff;")
    369  assert_equals(el.getAttributeNS(null, "style"), "color:#fff;")
    370  assert_equals(el.getAttributeNS("", "style"), "color:#fff;")
    371 }, "Style attributes are not normalized")
    372 test(function() {
    373  var el = document.createElement("div")
    374  el.setAttributeNS("", "ALIGN", "left")
    375  assert_equals(el.hasAttribute("ALIGN"), false)
    376  assert_equals(el.hasAttribute("align"), false)
    377  assert_equals(el.hasAttributeNS(null, "ALIGN"), true)
    378  assert_equals(el.hasAttributeNS(null, "align"), false)
    379  assert_equals(el.hasAttributeNS("", "ALIGN"), true)
    380  assert_equals(el.hasAttributeNS("", "align"), false)
    381  assert_equals(el.getAttribute("ALIGN"), null)
    382  assert_equals(el.getAttribute("align"), null)
    383  assert_equals(el.getAttributeNS(null, "ALIGN"), "left")
    384  assert_equals(el.getAttributeNS("", "ALIGN"), "left")
    385  assert_equals(el.getAttributeNS(null, "align"), null)
    386  assert_equals(el.getAttributeNS("", "align"), null)
    387  el.removeAttributeNS("", "ALIGN")
    388 }, "Only lowercase attributes are returned on HTML elements (upper case attribute)")
    389 test(function() {
    390  var el = document.createElement("div")
    391  el.setAttributeNS("", "CHEEseCaKe", "tasty")
    392  assert_equals(el.hasAttribute("CHEESECAKE"), false)
    393  assert_equals(el.hasAttribute("CHEEseCaKe"), false)
    394  assert_equals(el.hasAttribute("cheesecake"), false)
    395  assert_equals(el.hasAttributeNS("", "CHEESECAKE"), false)
    396  assert_equals(el.hasAttributeNS("", "CHEEseCaKe"), true)
    397  assert_equals(el.hasAttributeNS("", "cheesecake"), false)
    398  assert_equals(el.hasAttributeNS(null, "CHEESECAKE"), false)
    399  assert_equals(el.hasAttributeNS(null, "CHEEseCaKe"), true)
    400  assert_equals(el.hasAttributeNS(null, "cheesecake"), false)
    401  assert_equals(el.getAttribute("CHEESECAKE"), null)
    402  assert_equals(el.getAttribute("CHEEseCaKe"), null)
    403  assert_equals(el.getAttribute("cheesecake"), null)
    404  assert_equals(el.getAttributeNS(null, "CHEESECAKE"), null)
    405  assert_equals(el.getAttributeNS("", "CHEESECAKE"), null)
    406  assert_equals(el.getAttributeNS(null, "CHEEseCaKe"), "tasty")
    407  assert_equals(el.getAttributeNS("", "CHEEseCaKe"), "tasty")
    408  assert_equals(el.getAttributeNS(null, "cheesecake"), null)
    409  assert_equals(el.getAttributeNS("", "cheesecake"), null)
    410  el.removeAttributeNS("", "CHEEseCaKe")
    411 }, "Only lowercase attributes are returned on HTML elements (mixed case attribute)")
    412 test(function() {
    413  var el = document.createElement("div")
    414  document.body.appendChild(el)
    415  el.setAttributeNS("", "align", "left")
    416  el.setAttributeNS("xx", "align", "right")
    417  el.setAttributeNS("", "foo", "left")
    418  el.setAttributeNS("xx", "foo", "right")
    419  assert_equals(el.hasAttribute("align"), true)
    420  assert_equals(el.hasAttribute("foo"), true)
    421  assert_equals(el.hasAttributeNS("xx", "align"), true)
    422  assert_equals(el.hasAttributeNS(null, "foo"), true)
    423  assert_equals(el.getAttribute("align"), "left")
    424  assert_equals(el.getAttribute("foo"), "left")
    425  assert_equals(el.getAttributeNS("xx", "align"), "right")
    426  assert_equals(el.getAttributeNS(null, "foo"), "left")
    427  assert_equals(el.getAttributeNS("", "foo"), "left")
    428  el.removeAttributeNS("", "align")
    429  el.removeAttributeNS("xx", "align")
    430  el.removeAttributeNS("", "foo")
    431  el.removeAttributeNS("xx", "foo")
    432  document.body.removeChild(el)
    433 }, "First set attribute is returned with mapped attribute set first")
    434 test(function() {
    435  var el = document.createElement("div")
    436  el.setAttributeNS("xx", "align", "right")
    437  el.setAttributeNS("", "align", "left")
    438  el.setAttributeNS("xx", "foo", "right")
    439  el.setAttributeNS("", "foo", "left")
    440  assert_equals(el.hasAttribute("align"), true)
    441  assert_equals(el.hasAttribute("foo"), true)
    442  assert_equals(el.hasAttributeNS("xx", "align"), true)
    443  assert_equals(el.hasAttributeNS(null, "foo"), true)
    444  assert_equals(el.getAttribute("align"), "right")
    445  assert_equals(el.getAttribute("foo"), "right")
    446  assert_equals(el.getAttributeNS("xx", "align"), "right")
    447  assert_equals(el.getAttributeNS(null, "foo"), "left")
    448  assert_equals(el.getAttributeNS("", "foo"), "left")
    449  el.removeAttributeNS("", "align")
    450  el.removeAttributeNS("xx", "align")
    451  el.removeAttributeNS("", "foo")
    452  el.removeAttributeNS("xx", "foo")
    453 }, "First set attribute is returned with mapped attribute set later")
    454 
    455 test(function() {
    456  var el = document.createElementNS("http://www.example.com", "foo")
    457  el.setAttribute("A", "test")
    458  assert_equals(el.hasAttribute("A"), true, "hasAttribute()")
    459  assert_equals(el.hasAttributeNS("", "A"), true, "el.hasAttributeNS(\"\")")
    460  assert_equals(el.hasAttributeNS(null, "A"), true, "el.hasAttributeNS(null)")
    461  assert_equals(el.hasAttributeNS(undefined, "A"), true, "el.hasAttributeNS(undefined)")
    462  assert_equals(el.hasAttributeNS("foo", "A"), false, "el.hasAttributeNS(\"foo\")")
    463 
    464  assert_equals(el.getAttribute("A"), "test", "getAttribute()")
    465  assert_equals(el.getAttributeNS("", "A"), "test", "el.getAttributeNS(\"\")")
    466  assert_equals(el.getAttributeNS(null, "A"), "test", "el.getAttributeNS(null)")
    467  assert_equals(el.getAttributeNS(undefined, "A"), "test", "el.getAttributeNS(undefined)")
    468  assert_equals(el.getAttributeNS("foo", "A"), null, "el.getAttributeNS(\"foo\")")
    469 }, "Non-HTML element with upper-case attribute")
    470 
    471 test(function() {
    472  var el = document.createElement("div")
    473  el.setAttribute("pre:fix", "value 1")
    474  el.setAttribute("fix", "value 2")
    475 
    476  var prefixed = el.attributes[0]
    477  assert_equals(prefixed.localName, "pre:fix", "prefixed local name")
    478  assert_equals(prefixed.namespaceURI, null, "prefixed namespace")
    479 
    480  var unprefixed = el.attributes[1]
    481  assert_equals(unprefixed.localName, "fix", "unprefixed local name")
    482  assert_equals(unprefixed.namespaceURI, null, "unprefixed namespace")
    483 
    484  el.removeAttributeNS(null, "pre:fix")
    485  assert_equals(el.attributes[0], unprefixed)
    486 }, "Attribute with prefix in local name")
    487 
    488 test(function() {
    489  var el = document.createElement("div")
    490  el.setAttribute("foo", "bar")
    491  var attr = el.attributes[0]
    492  assert_equals(attr.ownerElement, el)
    493  el.removeAttribute("foo")
    494  assert_equals(attr.ownerElement, null)
    495 }, "Attribute loses its owner when removed")
    496 
    497 test(function() {
    498  var el = document.createElement("div")
    499  el.setAttribute("foo", "bar")
    500  var attr = el.attributes[0]
    501  var attrNode = el.getAttributeNode("foo");
    502  var attrNodeNS = el.getAttributeNodeNS("", "foo");
    503  assert_equals(attr, attrNode);
    504  assert_equals(attr, attrNodeNS);
    505  el.setAttributeNS("x", "foo2", "bar2");
    506  var attr2 = el.attributes[1];
    507  var attrNodeNS2 = el.getAttributeNodeNS("x", "foo2");
    508  assert_equals(attr2, attrNodeNS2);
    509 }, "Basic functionality of getAttributeNode/getAttributeNodeNS")
    510 
    511 test(function() {
    512  var el = document.createElement("div")
    513  el.setAttribute("foo", "bar")
    514  var attrNode = el.getAttributeNode("foo");
    515  var attrNodeNS = el.getAttributeNodeNS("", "foo");
    516  assert_equals(attrNode, attrNodeNS);
    517  el.removeAttribute("foo");
    518  var el2 = document.createElement("div");
    519  el2.setAttributeNode(attrNode);
    520  assert_equals(attrNode, el2.getAttributeNode("foo"));
    521  assert_equals(attrNode, el2.attributes[0]);
    522  assert_equals(attrNode.ownerElement, el2);
    523  assert_equals(attrNode.value, "bar");
    524 
    525   var el3 = document.createElement("div");
    526   el2.removeAttribute("foo");
    527   el3.setAttribute("foo", "baz");
    528   el3.setAttributeNode(attrNode);
    529   assert_equals(el3.getAttribute("foo"), "bar");
    530 }, "Basic functionality of setAttributeNode")
    531 
    532 test(function() {
    533  var el = document.createElement("div");
    534  var attr1 = document.createAttributeNS("ns1", "p1:name");
    535  attr1.value = "value1";
    536  var attr2 = document.createAttributeNS("ns2", "p2:name");
    537  attr2.value = "value2";
    538  el.setAttributeNode(attr1);
    539  el.setAttributeNode(attr2);
    540  assert_equals(el.getAttributeNodeNS("ns1", "name").value, "value1");
    541  assert_equals(el.getAttributeNodeNS("ns2", "name").value, "value2");
    542 }, "setAttributeNode should distinguish attributes with same local name and different namespaces")
    543 
    544 test(function() {
    545  var el = document.createElement("div");
    546  var attr1 = document.createAttributeNS("ns1", "p1:name");
    547  attr1.value = "value1";
    548  var attr2 = document.createAttributeNS("ns1", "p1:NAME");
    549  attr2.value = "VALUE2";
    550  el.setAttributeNode(attr1);
    551  el.setAttributeNode(attr2);
    552  assert_equals(el.getAttributeNodeNS("ns1", "name").value, "value1");
    553  assert_equals(el.getAttributeNodeNS("ns1", "NAME").value, "VALUE2");
    554 }, "setAttributeNode doesn't have case-insensitivity even with an HTMLElement 1")
    555 
    556 test(function() {
    557  var el = document.createElement("div");
    558  var attr1 = document.createAttributeNS("ns1", "FOOBAR");
    559  var attr2 = document.createAttributeNS("ns1", "FOOBAR");
    560  assert_equals(el.setAttributeNode(attr1), null);
    561  assert_equals(attr1.ownerElement, el);
    562  assert_equals(attr2.ownerElement, null);
    563  var oldAttr = el.setAttributeNode(attr2);
    564  assert_equals(oldAttr, attr1);
    565  assert_equals(attr1.ownerElement, null);
    566  assert_equals(attr2.ownerElement, el);
    567 }, "setAttributeNode doesn't have case-insensitivity even with an HTMLElement 2")
    568 
    569 test(function() {
    570  var el = document.createElement("div");
    571  var attr1 = document.createAttributeNS("ns1", "foobar");
    572  var attr2 = document.createAttributeNS("ns1", "FOOBAR");
    573  assert_equals(el.setAttributeNode(attr1), null);
    574  assert_equals(attr1.ownerElement, el);
    575  assert_equals(attr2.ownerElement, null);
    576  assert_equals(el.setAttributeNode(attr2), null);
    577  assert_equals(attr1.ownerElement, el);
    578  assert_equals(attr2.ownerElement, el);
    579 }, "setAttributeNode doesn't have case-insensitivity even with an HTMLElement 3")
    580 
    581 test(function() {
    582  var el = document.createElement("div")
    583  el.setAttributeNS("x", "foo", "bar")
    584  var attrNode = el.getAttributeNodeNS("x", "foo");
    585  el.removeAttribute("foo");
    586  var el2 = document.createElement("div");
    587  el2.setAttributeNS("x", "foo", "baz");
    588  el2.setAttributeNodeNS(attrNode);
    589  assert_equals(el2.getAttributeNS("x", "foo"), "bar");
    590 }, "Basic functionality of setAttributeNodeNS")
    591 
    592 test(function() {
    593  var el = document.createElement("div");
    594  var other = document.createElement("div");
    595  var attr = document.createAttribute("foo");
    596  assert_equals(el.setAttributeNode(attr), null);
    597  assert_equals(attr.ownerElement, el);
    598  assert_throws_dom("INUSE_ATTRIBUTE_ERR",
    599                  function() { other.setAttributeNode(attr) },
    600                  "Attribute already associated with el")
    601 }, "If attr’s element is neither null nor element, throw an InUseAttributeError.");
    602 
    603 test(function() {
    604  var el = document.createElement("div");
    605  var attr = document.createAttribute("foo");
    606  assert_equals(el.setAttributeNode(attr), null);
    607  el.setAttribute("bar", "qux");
    608  assert_equals(el.setAttributeNode(attr), attr);
    609  assert_equals(el.attributes[0], attr);
    610 }, "Replacing an attr by itself");
    611 
    612 test(function() {
    613  var el = document.createElement("div")
    614  el.setAttribute("foo", "bar")
    615  var attrNode = el.getAttributeNode("foo");
    616  el.removeAttributeNode(attrNode);
    617  var el2 = document.createElement("div");
    618  el2.setAttributeNode(attrNode);
    619  assert_equals(el2.attributes[0], attrNode);
    620  assert_equals(el.attributes.length, 0);
    621 }, "Basic functionality of removeAttributeNode")
    622 
    623 test(function() {
    624  var el = document.createElement("div")
    625  el.setAttribute("foo", "bar")
    626  var attrNode = el.getAttributeNode("foo");
    627  var el2 = document.createElement("div");
    628  assert_throws_dom("INUSE_ATTRIBUTE_ERR", function(){el2.setAttributeNode(attrNode)});
    629 }, "setAttributeNode on bound attribute should throw InUseAttributeError")
    630 
    631 // Have to use an async_test to see what a DOMAttrModified listener sees,
    632 // because otherwise the event dispatch code will swallow our exceptions.  And
    633 // we want to make sure this test always happens, even when no mutation events
    634 // run.
    635 var setAttributeNode_mutation_test = async_test("setAttributeNode, if it fires mutation events, should fire one with the new node when resetting an existing attribute");
    636 
    637 test(function(){
    638  var el = document.createElement("div")
    639  var attrNode1 = document.createAttribute("foo");
    640  attrNode1.value = "bar";
    641  el.setAttributeNode(attrNode1);
    642  var attrNode2 = document.createAttribute("foo");
    643  attrNode2.value = "baz";
    644 
    645  el.addEventListener("DOMAttrModified", function(e) {
    646    // If this never gets called, that's OK, I guess.  But if it gets called, it
    647    // better represent a single modification with attrNode2 as the relatedNode.
    648    // We have to do an inner test() call here, because otherwise the exceptions
    649    // our asserts trigger will get swallowed by the event dispatch code.
    650    setAttributeNode_mutation_test.step(function() {
    651      assert_equals(e.attrName, "foo");
    652      assert_equals(e.attrChange, MutationEvent.MODIFICATION);
    653      assert_equals(e.prevValue, "bar");
    654      assert_equals(e.newValue, "baz");
    655      assert_equals(e.relatedNode, attrNode2);
    656    });
    657  });
    658 
    659  var oldNode = el.setAttributeNode(attrNode2);
    660  assert_equals(oldNode, attrNode1,
    661                "Must return the old attr node from a setAttributeNode call");
    662 }, "setAttributeNode, if it fires mutation events, should fire one with the new node when resetting an existing attribute (outer shell)");
    663 setAttributeNode_mutation_test.done();
    664 
    665 test(function(){
    666  var el = document.createElement("div")
    667  el.setAttribute("a", "b");
    668  el.setAttribute("c", "d");
    669 
    670  assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.name }),
    671                      ["a", "c"]);
    672  assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.value }),
    673                      ["b", "d"]);
    674 
    675  var attrNode = document.createAttribute("a");
    676  attrNode.value = "e";
    677  el.setAttributeNode(attrNode);
    678 
    679  assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.name }),
    680                      ["a", "c"]);
    681  assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.value }),
    682                      ["e", "d"]);
    683 }, "setAttributeNode called with an Attr that has the same name as an existing one should not change attribute order");
    684 
    685 test(function() {
    686  var el = document.createElement("div");
    687  el.setAttribute("foo", "bar");
    688  assert_equals(el.getAttributeNames().length, 1);
    689  assert_equals(el.getAttributeNames()[0], el.attributes[0].name);
    690  assert_equals(el.getAttributeNames()[0], "foo");
    691 
    692  el.removeAttribute("foo");
    693  assert_equals(el.getAttributeNames().length, 0);
    694 
    695  el.setAttribute("foo", "bar");
    696  el.setAttributeNS("", "FOO", "bar");
    697  el.setAttributeNS("dummy1", "foo", "bar");
    698  el.setAttributeNS("dummy2", "dummy:foo", "bar");
    699  assert_equals(el.getAttributeNames().length, 4);
    700  assert_equals(el.getAttributeNames()[0], "foo");
    701  assert_equals(el.getAttributeNames()[1], "FOO");
    702  assert_equals(el.getAttributeNames()[2], "foo");
    703  assert_equals(el.getAttributeNames()[3], "dummy:foo");
    704  assert_equals(el.getAttributeNames()[0], el.attributes[0].name);
    705  assert_equals(el.getAttributeNames()[1], el.attributes[1].name);
    706  assert_equals(el.getAttributeNames()[2], el.attributes[2].name);
    707  assert_equals(el.getAttributeNames()[3], el.attributes[3].name);
    708 
    709  el.removeAttributeNS("", "FOO");
    710  assert_equals(el.getAttributeNames().length, 3);
    711  assert_equals(el.getAttributeNames()[0], "foo");
    712  assert_equals(el.getAttributeNames()[1], "foo");
    713  assert_equals(el.getAttributeNames()[2], "dummy:foo");
    714  assert_equals(el.getAttributeNames()[0], el.attributes[0].name);
    715  assert_equals(el.getAttributeNames()[1], el.attributes[1].name);
    716  assert_equals(el.getAttributeNames()[2], el.attributes[2].name);
    717 }, "getAttributeNames tests");
    718 
    719 function getEnumerableOwnProps1(obj) {
    720  var arr = [];
    721  for (var prop in obj) {
    722    if (obj.hasOwnProperty(prop)) {
    723      arr.push(prop);
    724    }
    725  }
    726  return arr;
    727 }
    728 
    729 function getEnumerableOwnProps2(obj) {
    730  return Object.getOwnPropertyNames(obj).filter(
    731    function (name) { return Object.getOwnPropertyDescriptor(obj, name).enumerable; })
    732 }
    733 
    734 test(function() {
    735  var el = document.createElement("div");
    736  el.setAttribute("a", "");
    737  el.setAttribute("b", "");
    738  assert_array_equals(getEnumerableOwnProps1(el.attributes),
    739                      ["0", "1"])
    740  assert_array_equals(getEnumerableOwnProps2(el.attributes),
    741                      ["0", "1"])
    742  assert_array_equals(Object.getOwnPropertyNames(el.attributes),
    743                      ["0", "1", "a", "b"])
    744 }, "Own property correctness with basic attributes");
    745 
    746 test(function() {
    747  var el = document.createElement("div");
    748  el.setAttributeNS("", "a", "");
    749  el.setAttribute("b", "");
    750  el.setAttributeNS("foo", "a", "");
    751  assert_array_equals(getEnumerableOwnProps1(el.attributes),
    752                      ["0", "1", "2"])
    753  assert_array_equals(getEnumerableOwnProps2(el.attributes),
    754                      ["0", "1", "2"])
    755  assert_array_equals(Object.getOwnPropertyNames(el.attributes),
    756                      ["0", "1", "2", "a", "b"])
    757  for (var propName of Object.getOwnPropertyNames(el.attributes)) {
    758    assert_true(el.attributes[propName] instanceof Attr,
    759                "el.attributes has an Attr for property name " + propName);
    760  }
    761 }, "Own property correctness with non-namespaced attribute before same-name namespaced one");
    762 
    763 test(function() {
    764  var el = document.createElement("div");
    765  el.setAttributeNS("foo", "a", "");
    766  el.setAttribute("b", "");
    767  el.setAttributeNS("", "a", "");
    768  assert_array_equals(getEnumerableOwnProps1(el.attributes),
    769                      ["0", "1", "2"])
    770  assert_array_equals(getEnumerableOwnProps2(el.attributes),
    771                      ["0", "1", "2"])
    772  assert_array_equals(Object.getOwnPropertyNames(el.attributes),
    773                      ["0", "1", "2", "a", "b"])
    774  for (var propName of Object.getOwnPropertyNames(el.attributes)) {
    775    assert_true(el.attributes[propName] instanceof Attr,
    776                "el.attributes has an Attr for property name " + propName);
    777  }
    778 }, "Own property correctness with namespaced attribute before same-name non-namespaced one");
    779 
    780 test(function() {
    781  var el = document.createElement("div");
    782  el.setAttributeNS("foo", "a:b", "");
    783  el.setAttributeNS("foo", "c:d", "");
    784  el.setAttributeNS("bar", "a:b", "");
    785  assert_array_equals(getEnumerableOwnProps1(el.attributes),
    786                      ["0", "1", "2"])
    787  assert_array_equals(getEnumerableOwnProps2(el.attributes),
    788                      ["0", "1", "2"])
    789  assert_array_equals(Object.getOwnPropertyNames(el.attributes),
    790                      ["0", "1", "2", "a:b", "c:d"])
    791  for (var propName of Object.getOwnPropertyNames(el.attributes)) {
    792    assert_true(el.attributes[propName] instanceof Attr,
    793                "el.attributes has an Attr for property name " + propName);
    794  }
    795 }, "Own property correctness with two namespaced attributes with the same name-with-prefix");
    796 
    797 test(function() {
    798  var el = document.createElement("div");
    799  el.setAttributeNS("foo", "A:B", "");
    800  el.setAttributeNS("bar", "c:D", "");
    801  el.setAttributeNS("baz", "e:F", "");
    802  el.setAttributeNS("qux", "g:h", "");
    803  el.setAttributeNS("", "I", "");
    804  el.setAttributeNS("", "j", "");
    805  assert_array_equals(Object.getOwnPropertyNames(el.attributes),
    806                      ["0", "1", "2", "3", "4", "5", "g:h", "j"])
    807  for (var propName of Object.getOwnPropertyNames(el.attributes)) {
    808    assert_true(el.attributes[propName] instanceof Attr,
    809                "el.attributes has an Attr for property name " + propName);
    810  }
    811 }, "Own property names should only include all-lowercase qualified names for an HTML element in an HTML document");
    812 
    813 test(function() {
    814  var el = document.createElementNS("", "div");
    815  el.setAttributeNS("foo", "A:B", "");
    816  el.setAttributeNS("bar", "c:D", "");
    817  el.setAttributeNS("baz", "e:F", "");
    818  el.setAttributeNS("qux", "g:h", "");
    819  el.setAttributeNS("", "I", "");
    820  el.setAttributeNS("", "j", "");
    821  assert_array_equals(Object.getOwnPropertyNames(el.attributes),
    822                      ["0", "1", "2", "3", "4", "5", "A:B", "c:D", "e:F", "g:h", "I", "j"])
    823  for (var propName of Object.getOwnPropertyNames(el.attributes)) {
    824    assert_true(el.attributes[propName] instanceof Attr,
    825                "el.attributes has an Attr for property name " + propName);
    826  }
    827 }, "Own property names should include all qualified names for a non-HTML element in an HTML document");
    828 
    829 test(function() {
    830  var doc = document.implementation.createDocument(null, "");
    831  assert_equals(doc.contentType, "application/xml");
    832  var el = doc.createElementNS("http://www.w3.org/1999/xhtml", "div");
    833  el.setAttributeNS("foo", "A:B", "");
    834  el.setAttributeNS("bar", "c:D", "");
    835  el.setAttributeNS("baz", "e:F", "");
    836  el.setAttributeNS("qux", "g:h", "");
    837  el.setAttributeNS("", "I", "");
    838  el.setAttributeNS("", "j", "");
    839  assert_array_equals(Object.getOwnPropertyNames(el.attributes),
    840                      ["0", "1", "2", "3", "4", "5", "A:B", "c:D", "e:F", "g:h", "I", "j"])
    841  for (var propName of Object.getOwnPropertyNames(el.attributes)) {
    842    assert_true(el.attributes[propName] instanceof Attr,
    843                "el.attributes has an Attr for property name " + propName);
    844  }
    845 }, "Own property names should include all qualified names for an HTML element in a non-HTML document");
    846 </script>