tor-browser

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

Element-classlist.html (17163B)


      1 <!doctype html>
      2 <meta charset=utf-8>
      3 <title>Test for the classList element attribute</title>
      4 <script src=/resources/testharness.js></script>
      5 <script src=/resources/testharnessreport.js></script>
      6 <div id="content"></div>
      7 <script>
      8 const SVG_NS = "http://www.w3.org/2000/svg";
      9 const XHTML_NS = "http://www.w3.org/1999/xhtml"
     10 const MATHML_NS = "http://www.w3.org/1998/Math/MathML";
     11 
     12 function setClass(e, newVal) {
     13  if (newVal === null) {
     14    e.removeAttribute("class");
     15  } else {
     16    e.setAttribute("class", newVal);
     17  }
     18 }
     19 
     20 function checkModification(e, funcName, args, expectedRes, before, after,
     21                           expectedException, desc) {
     22  if (!Array.isArray(args)) {
     23    args = [args];
     24  }
     25 
     26  test(function() {
     27    var shouldThrow = typeof(expectedException) === "string";
     28    if (shouldThrow) {
     29      // If an exception is thrown, the class attribute shouldn't change.
     30      after = before;
     31    }
     32    setClass(e, before);
     33 
     34    var obs;
     35    // If we have MutationObservers available,  do some checks to make
     36    // sure attribute sets are happening at sane times.
     37    if (self.MutationObserver) {
     38      obs = new MutationObserver(() => {});
     39      obs.observe(e, { attributes: true });
     40    }
     41    if (shouldThrow) {
     42      assert_throws_dom(expectedException, function() {
     43        var list = e.classList;
     44        var res = list[funcName].apply(list, args);
     45      });
     46    } else {
     47      var list = e.classList;
     48      var res = list[funcName].apply(list, args);
     49    }
     50    if (obs) {
     51      var mutationRecords = obs.takeRecords();
     52      obs.disconnect();
     53      if (shouldThrow) {
     54        assert_equals(mutationRecords.length, 0,
     55                      "There should have been no mutation");
     56      } else if (funcName == "replace") {
     57        assert_equals(mutationRecords.length == 1,
     58                      expectedRes,
     59                      "Should have a mutation exactly when replace() returns true");
     60      } else {
     61        // For other functions, would need to check when exactly
     62        // mutations are supposed to happen.
     63      }
     64    }
     65    if (!shouldThrow) {
     66      assert_equals(res, expectedRes, "wrong return value");
     67    }
     68 
     69    var expectedAfter = after;
     70 
     71    assert_equals(e.getAttribute("class"), expectedAfter,
     72                  "wrong class after modification");
     73  }, "classList." + funcName + "(" + args.map(format_value).join(", ") +
     74  ") with attribute value " + format_value(before) + desc);
     75 }
     76 
     77 function assignToClassListStrict(e) {
     78  "use strict";
     79  e.classList = "foo";
     80  e.removeAttribute("class");
     81 }
     82 
     83 function assignToClassList(e) {
     84  var expect = e.classList;
     85  e.classList = "foo";
     86  assert_equals(e.classList, expect,
     87                "classList should be unchanged after assignment");
     88  e.removeAttribute("class");
     89 }
     90 
     91 function testClassList(e, desc) {
     92 
     93  // assignment
     94 
     95  test(function() {
     96    assignToClassListStrict(e);
     97    assignToClassList(e);
     98  }, "Assigning to classList" + desc);
     99 
    100  // supports
    101  test(function() {
    102    assert_throws_js(TypeError, function() {
    103      e.classList.supports("a");
    104    })
    105  }, ".supports() must throw TypeError" + desc);
    106 
    107  // length attribute
    108 
    109  function checkLength(value, length) {
    110    test(function() {
    111      setClass(e, value);
    112      assert_equals(e.classList.length, length);
    113    }, "classList.length when " +
    114    (value === null ? "removed" : "set to " + format_value(value)) + desc);
    115  }
    116 
    117  checkLength(null, 0);
    118  checkLength("", 0);
    119  checkLength("   \t  \f", 0);
    120  checkLength("a", 1);
    121  checkLength("a A", 2);
    122  checkLength("\r\na\t\f", 1);
    123  checkLength("a a", 1);
    124  checkLength("a a a a a a", 1);
    125  checkLength("a a b b", 2);
    126  checkLength("a A B b", 4);
    127  checkLength("a b c c b a a b c c", 3);
    128  checkLength("   a  a b", 2);
    129  checkLength("a\tb\nc\fd\re f", 6);
    130 
    131  // [Stringifies]
    132 
    133  function checkStringifier(value, expected) {
    134    test(function() {
    135      setClass(e, value);
    136      assert_equals(e.classList.toString(), expected);
    137    }, "classList.toString() when " +
    138    (value === null ? "removed" : "set to " + format_value(value)) + desc);
    139  }
    140 
    141  checkStringifier(null, "");
    142  checkStringifier("foo", "foo");
    143  checkStringifier("   a  a b", "   a  a b");
    144 
    145  // item() method
    146 
    147  function checkItems(attributeValue, expectedValues) {
    148    function checkItemFunction(index, expected) {
    149      assert_equals(e.classList.item(index), expected,
    150                    "classList.item(" + index + ")");
    151    }
    152 
    153    function checkItemArray(index, expected) {
    154      assert_equals(e.classList[index], expected, "classList[" + index + "]");
    155    }
    156 
    157    test(function() {
    158      setClass(e, attributeValue);
    159 
    160      checkItemFunction(-1, null);
    161      checkItemArray(-1, undefined);
    162 
    163      var i = 0;
    164      while (i < expectedValues.length) {
    165        checkItemFunction(i, expectedValues[i]);
    166        checkItemArray(i, expectedValues[i]);
    167        i++;
    168      }
    169 
    170      checkItemFunction(i, null);
    171      checkItemArray(i, undefined);
    172 
    173      checkItemFunction(0xffffffff, null);
    174      checkItemArray(0xffffffff, undefined);
    175 
    176      checkItemFunction(0xfffffffe, null);
    177      checkItemArray(0xfffffffe, undefined);
    178    }, "classList.item() when set to " + format_value(attributeValue) + desc);
    179  }
    180 
    181  checkItems(null, []);
    182  checkItems("a", ["a"]);
    183  checkItems("aa AA aa", ["aa", "AA"]);
    184  checkItems("a b", ["a", "b"]);
    185  checkItems("   a  a b", ["a", "b"]);
    186  checkItems("\t\n\f\r a\t\n\f\r b\t\n\f\r ", ["a", "b"]);
    187 
    188  // contains() method
    189 
    190  function checkContains(attributeValue, args, expectedRes) {
    191    if (!Array.isArray(expectedRes)) {
    192      expectedRes = Array(args.length).fill(expectedRes);
    193    }
    194    setClass(e, attributeValue);
    195    for (var i = 0; i < args.length; i++) {
    196      test(function() {
    197        assert_equals(e.classList.contains(args[i]), expectedRes[i],
    198                      "classList.contains(\"" + args[i] + "\")");
    199      }, "classList.contains(" + format_value(args[i]) + ") when set to " +
    200      format_value(attributeValue) + desc);
    201    }
    202  }
    203 
    204  checkContains(null, ["a", "", "  "], false);
    205  checkContains("", ["a"], false);
    206 
    207  checkContains("a", ["a"], true);
    208  checkContains("a", ["aa", "b", "A", "a.", "a)",, "a'", 'a"', "a$", "a~",
    209                      "a?", "a\\"], false);
    210 
    211  // All "ASCII whitespace" per spec, before and after
    212  checkContains("a", ["a\t", "\ta", "a\n", "\na", "a\f", "\fa", "a\r", "\ra",
    213                      "a ", " a"], false);
    214 
    215  checkContains("aa AA", ["aa", "AA", "aA"], [true, true, false]);
    216  checkContains("a a a", ["a", "aa", "b"], [true, false, false]);
    217  checkContains("a b c", ["a", "b"], true);
    218 
    219  checkContains("null undefined", [null, undefined], true);
    220  checkContains("\t\n\f\r a\t\n\f\r b\t\n\f\r ", ["a", "b"], true);
    221 
    222  // add() method
    223 
    224  function checkAdd(before, argument, after, param) {
    225    var expectedException = undefined;
    226    var noop = false;
    227    if (param == "noop") {
    228      noop = true;
    229    } else {
    230      expectedException = param;
    231    }
    232    checkModification(e, "add", argument, undefined, before, after,
    233                      expectedException, desc);
    234    // Also check force toggle.  The only difference is that it doesn't run the
    235    // update steps for a no-op.
    236    if (!Array.isArray(argument)) {
    237      checkModification(e, "toggle", [argument, true], true, before,
    238                        noop ? before : after, expectedException, desc);
    239    }
    240  }
    241 
    242  checkAdd(null, "", null, "SyntaxError");
    243  checkAdd(null, ["a", ""], null, "SyntaxError");
    244  checkAdd(null, " ", null, "InvalidCharacterError");
    245  checkAdd(null, "\ta", null, "InvalidCharacterError");
    246  checkAdd(null, "a\t", null, "InvalidCharacterError");
    247  checkAdd(null, "\na", null, "InvalidCharacterError");
    248  checkAdd(null, "a\n", null, "InvalidCharacterError");
    249  checkAdd(null, "\fa", null, "InvalidCharacterError");
    250  checkAdd(null, "a\f", null, "InvalidCharacterError");
    251  checkAdd(null, "\ra", null, "InvalidCharacterError");
    252  checkAdd(null, "a\r", null, "InvalidCharacterError");
    253  checkAdd(null, " a", null, "InvalidCharacterError");
    254  checkAdd(null, "a ", null, "InvalidCharacterError");
    255  checkAdd(null, ["a", " "], null, "InvalidCharacterError");
    256  checkAdd(null, ["a", "aa "], null, "InvalidCharacterError");
    257 
    258  checkAdd("a", "a", "a");
    259  checkAdd("aa", "AA", "aa AA");
    260  checkAdd("a b c", "a", "a b c");
    261  checkAdd("a a a  b", "a", "a b", "noop");
    262  checkAdd(null, "a", "a");
    263  checkAdd("", "a", "a");
    264  checkAdd(" ", "a", "a");
    265  checkAdd("   \f", "a", "a");
    266  checkAdd("a", "b", "a b");
    267  checkAdd("a b c", "d", "a b c d");
    268  checkAdd("a b c ", "d", "a b c d");
    269  checkAdd("   a  a b", "c", "a b c");
    270  checkAdd("   a  a b", "a", "a b", "noop");
    271  checkAdd("\t\n\f\r a\t\n\f\r b\t\n\f\r ", "c", "a b c");
    272 
    273  // multiple add
    274  checkAdd("a b c ", ["d", "e"], "a b c d e");
    275  checkAdd("a b c ", ["a", "a"], "a b c");
    276  checkAdd("a b c ", ["d", "d"], "a b c d");
    277  checkAdd("a b c a ", [], "a b c");
    278  checkAdd(null, ["a", "b"], "a b");
    279  checkAdd("", ["a", "b"], "a b");
    280 
    281  checkAdd(null, null, "null");
    282  checkAdd(null, undefined, "undefined");
    283 
    284  // remove() method
    285 
    286  function checkRemove(before, argument, after, param) {
    287    var expectedException = undefined;
    288    var noop = false;
    289    if (param == "noop") {
    290      noop = true;
    291    } else {
    292      expectedException = param;
    293    }
    294    checkModification(e, "remove", argument, undefined, before, after,
    295                      expectedException, desc);
    296    // Also check force toggle.  The only difference is that it doesn't run the
    297    // update steps for a no-op.
    298    if (!Array.isArray(argument)) {
    299      checkModification(e, "toggle", [argument, false], false, before,
    300                        noop ? before : after, expectedException, desc);
    301    }
    302  }
    303 
    304  checkRemove(null, "", null, "SyntaxError");
    305  checkRemove(null, " ", null, "InvalidCharacterError");
    306  checkRemove("\ta", "\ta", "\ta", "InvalidCharacterError");
    307  checkRemove("a\t", "a\t", "a\t", "InvalidCharacterError");
    308  checkRemove("\na", "\na", "\na", "InvalidCharacterError");
    309  checkRemove("a\n", "a\n", "a\n", "InvalidCharacterError");
    310  checkRemove("\fa", "\fa", "\fa", "InvalidCharacterError");
    311  checkRemove("a\f", "a\f", "a\f", "InvalidCharacterError");
    312  checkRemove("\ra", "\ra", "\ra", "InvalidCharacterError");
    313  checkRemove("a\r", "a\r", "a\r", "InvalidCharacterError");
    314  checkRemove(" a", " a", " a", "InvalidCharacterError");
    315  checkRemove("a ", "a ", "a ", "InvalidCharacterError");
    316  checkRemove("aa ", "aa ", null, "InvalidCharacterError");
    317 
    318  checkRemove(null, "a", null);
    319  checkRemove("", "a", "");
    320  checkRemove("a b  c", "d", "a b c", "noop");
    321  checkRemove("a b  c", "A", "a b c", "noop");
    322  checkRemove(" a a a ", "a", "");
    323  checkRemove("a  b", "a", "b");
    324  checkRemove("a  b  ", "a", "b");
    325  checkRemove("a a b", "a", "b");
    326  checkRemove("aa aa bb", "aa", "bb");
    327  checkRemove("a a b a a c a a", "a", "b c");
    328 
    329  checkRemove("a  b  c", "b", "a c");
    330  checkRemove("aaa  bbb  ccc", "bbb", "aaa ccc");
    331  checkRemove(" a  b  c ", "b", "a c");
    332  checkRemove("a b b b c", "b", "a c");
    333 
    334  checkRemove("a  b  c", "c", "a b");
    335  checkRemove(" a  b  c ", "c", "a b");
    336  checkRemove("a b c c c", "c", "a b");
    337 
    338  checkRemove("a b a c a d a", "a", "b c d");
    339  checkRemove("AA BB aa CC AA dd aa", "AA", "BB aa CC dd");
    340 
    341  checkRemove("\ra\na\ta\f", "a", "");
    342  checkRemove("\t\n\f\r a\t\n\f\r b\t\n\f\r ", "a", "b");
    343 
    344  // multiple remove
    345  checkRemove("a b c ", ["d", "e"], "a b c");
    346  checkRemove("a b c ", ["a", "b"], "c");
    347  checkRemove("a b c ", ["a", "c"], "b");
    348  checkRemove("a b c ", ["a", "a"], "b c");
    349  checkRemove("a b c ", ["d", "d"], "a b c");
    350  checkRemove("a b c ", [], "a b c");
    351  checkRemove(null, ["a", "b"], null);
    352  checkRemove("", ["a", "b"], "");
    353  checkRemove("a a", [], "a");
    354 
    355  checkRemove("null", null, "");
    356  checkRemove("undefined", undefined, "");
    357 
    358  // toggle() method
    359 
    360  function checkToggle(before, argument, expectedRes, after, expectedException) {
    361    checkModification(e, "toggle", argument, expectedRes, before, after,
    362                      expectedException, desc);
    363  }
    364 
    365  checkToggle(null, "", null, null, "SyntaxError");
    366  checkToggle(null, "aa ", null, null, "InvalidCharacterError");
    367 
    368  checkToggle(null, "a", true, "a");
    369  checkToggle("", "a", true, "a");
    370  checkToggle(" ", "a", true, "a");
    371  checkToggle("   \f", "a", true, "a");
    372  checkToggle("a", "b", true, "a b");
    373  checkToggle("a", "A", true, "a A");
    374  checkToggle("a b c", "d", true, "a b c d");
    375  checkToggle("   a  a b", "d", true, "a b d");
    376 
    377  checkToggle("a", "a", false, "");
    378  checkToggle(" a a a ", "a", false, "");
    379  checkToggle(" A A A ", "a", true, "A a");
    380  checkToggle(" a b c ", "b", false, "a c");
    381  checkToggle(" a b c b b", "b", false, "a c");
    382  checkToggle(" a b  c  ", "c", false, "a b");
    383  checkToggle(" a b c ", "a", false, "b c");
    384  checkToggle("   a  a b", "b", false, "a");
    385  checkToggle("\t\n\f\r a\t\n\f\r b\t\n\f\r ", "a", false, "b");
    386  checkToggle("\t\n\f\r a\t\n\f\r b\t\n\f\r ", "c", true, "a b c");
    387 
    388  checkToggle("null", null, false, "");
    389  checkToggle("", null, true, "null");
    390  checkToggle("undefined", undefined, false, "");
    391  checkToggle("", undefined, true, "undefined");
    392 
    393 
    394  // replace() method
    395  function checkReplace(before, token, newToken, expectedRes, after, expectedException) {
    396    checkModification(e, "replace", [token, newToken], expectedRes, before,
    397                      after, expectedException, desc);
    398  }
    399 
    400  checkReplace(null, "", "a", null, null, "SyntaxError");
    401  checkReplace(null, "", " ", null, null, "SyntaxError");
    402  checkReplace(null, " ", "a", null, null, "InvalidCharacterError");
    403  checkReplace(null, "\ta", "b", null, null, "InvalidCharacterError");
    404  checkReplace(null, "a\t", "b", null, null, "InvalidCharacterError");
    405  checkReplace(null, "\na", "b", null, null, "InvalidCharacterError");
    406  checkReplace(null, "a\n", "b", null, null, "InvalidCharacterError");
    407  checkReplace(null, "\fa", "b", null, null, "InvalidCharacterError");
    408  checkReplace(null, "a\f", "b", null, null, "InvalidCharacterError");
    409  checkReplace(null, "\ra", "b", null, null, "InvalidCharacterError");
    410  checkReplace(null, "a\r", "b", null, null, "InvalidCharacterError");
    411  checkReplace(null, " a", "b", null, null, "InvalidCharacterError");
    412  checkReplace(null, "a ", "b", null, null, "InvalidCharacterError");
    413 
    414  checkReplace(null, "a", "", null, null, "SyntaxError");
    415  checkReplace(null, " ", "", null, null, "SyntaxError");
    416  checkReplace(null, "a", " ", null, null, "InvalidCharacterError");
    417  checkReplace(null, "b", "\ta", null, null, "InvalidCharacterError");
    418  checkReplace(null, "b", "a\t", null, null, "InvalidCharacterError");
    419  checkReplace(null, "b", "\na", null, null, "InvalidCharacterError");
    420  checkReplace(null, "b", "a\n", null, null, "InvalidCharacterError");
    421  checkReplace(null, "b", "\fa", null, null, "InvalidCharacterError");
    422  checkReplace(null, "b", "a\f", null, null, "InvalidCharacterError");
    423  checkReplace(null, "b", "\ra", null, null, "InvalidCharacterError");
    424  checkReplace(null, "b", "a\r", null, null, "InvalidCharacterError");
    425  checkReplace(null, "b", " a", null, null, "InvalidCharacterError");
    426  checkReplace(null, "b", "a ", null, null, "InvalidCharacterError");
    427 
    428  checkReplace("a", "a", "a", true, "a");
    429  checkReplace("a", "a", "b", true, "b");
    430  checkReplace("a", "A", "b", false, "a");
    431  checkReplace("a b", "b", "A", true, "a A");
    432  checkReplace("a b", "c", "a", false, "a b");
    433  checkReplace("a b c", "d", "e", false, "a b c");
    434  // https://github.com/whatwg/dom/issues/443
    435  checkReplace("a a a  b", "a", "a", true, "a b");
    436  checkReplace("a a a  b", "c", "d", false, "a a a  b");
    437  checkReplace(null, "a", "b", false, null);
    438  checkReplace("", "a", "b", false, "");
    439  checkReplace(" ", "a", "b", false, " ");
    440  checkReplace(" a  \f", "a", "b", true, "b");
    441  checkReplace("a b c", "b", "d", true, "a d c");
    442  checkReplace("a b c", "c", "a", true, "a b");
    443  checkReplace("c b a", "c", "a", true, "a b");
    444  checkReplace("a b a", "a", "c", true, "c b");
    445  checkReplace("a b a", "b", "c", true, "a c");
    446  checkReplace("   a  a b", "a", "c", true, "c b");
    447  checkReplace("   a  a b", "b", "c", true, "a c");
    448  checkReplace("\t\n\f\r a\t\n\f\r b\t\n\f\r ", "a", "c", true, "c b");
    449  checkReplace("\t\n\f\r a\t\n\f\r b\t\n\f\r ", "b", "c", true, "a c");
    450 
    451  checkReplace("a null", null, "b", true, "a b");
    452  checkReplace("a b", "a", null, true, "null b");
    453  checkReplace("a undefined", undefined, "b", true, "a b");
    454  checkReplace("a b", "a", undefined, true, "undefined b");
    455 }
    456 
    457 var content = document.getElementById("content");
    458 
    459 var htmlNode = document.createElement("div");
    460 content.appendChild(htmlNode);
    461 testClassList(htmlNode, " (HTML node)");
    462 
    463 var xhtmlNode = document.createElementNS(XHTML_NS, "div");
    464 content.appendChild(xhtmlNode);
    465 testClassList(xhtmlNode, " (XHTML node)");
    466 
    467 var mathMLNode = document.createElementNS(MATHML_NS, "math");
    468 content.appendChild(mathMLNode);
    469 testClassList(mathMLNode, " (MathML node)");
    470 
    471 var xmlNode = document.createElementNS(null, "foo");
    472 content.appendChild(xmlNode);
    473 testClassList(xmlNode, " (XML node with null namespace)");
    474 
    475 var fooNode = document.createElementNS("http://example.org/foo", "foo");
    476 content.appendChild(fooNode);
    477 testClassList(fooNode, " (foo node)");
    478 </script>