1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/base/test/test_classList.html Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,429 @@ 1.4 +<!DOCTYPE HTML> 1.5 +<html> 1.6 +<!-- 1.7 +https://bugzilla.mozilla.org/show_bug.cgi?id=501257 1.8 +--> 1.9 +<head> 1.10 + <title>Test for the classList element attribute</title> 1.11 + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> 1.12 + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> 1.13 +</head> 1.14 +<body> 1.15 +<a target="_blank" href="http://www.whatwg.org/specs/web-apps/current-work/#dom-classlist">classList DOM attribute</a> 1.16 +<p id="display"></p> 1.17 +<div id="content" style="display: none"> 1.18 +</div> 1.19 +<pre id="test"> 1.20 +<script type="application/javascript"> 1.21 + 1.22 +/** Test for Bug 501257 **/ 1.23 + 1.24 +const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; 1.25 +const SVG_NS = "http://www.w3.org/2000/svg"; 1.26 +const XHTML_NS = "http://www.w3.org/1999/xhtml" 1.27 +const MATHML_NS = "http://www.w3.org/1998/Math/MathML"; 1.28 + 1.29 +var gMutationEvents = []; 1.30 + 1.31 +function onAttrModified(event) { 1.32 + is(event.attrName, "class", "mutation on unexpected attribute"); 1.33 + 1.34 + gMutationEvents.push({ 1.35 + attrChange: event.attrChange, 1.36 + prevValue: event.prevValue, 1.37 + newValue: event.newValue, 1.38 + }); 1.39 +} 1.40 + 1.41 +function checkModification(e, funcName, args, expectedRes, before, after, expectedException) { 1.42 + if (!Array.isArray(args)) { 1.43 + args = [args]; 1.44 + } 1.45 + 1.46 + var shouldThrow = typeof(expectedException) === "string"; 1.47 + if (shouldThrow) { 1.48 + // If an exception is thrown, the class attribute shouldn't change. 1.49 + after = before; 1.50 + } 1.51 + if (before === null) 1.52 + e.removeAttribute("class"); 1.53 + else 1.54 + e.setAttribute("class", before); 1.55 + 1.56 + var contextMsg = "(checkModification: funcName=" + funcName + ",args=" + 1.57 + JSON.stringify(args) + ",expectedRes=" + expectedRes + 1.58 + ",before=" + before + ",after=" + after + ")"; 1.59 + 1.60 + gMutationEvents = []; 1.61 + e.addEventListener("DOMAttrModified", onAttrModified, false); 1.62 + try { 1.63 + var list = e.classList; 1.64 + var res = list[funcName].apply(list, args); 1.65 + if (shouldThrow) 1.66 + ok(false, "classList modification didn't throw " + contextMsg); 1.67 + } catch (e) { 1.68 + if (!shouldThrow) 1.69 + ok(false, "classList modification threw an exception " + contextMsg); 1.70 + is(e.name, expectedException, "wrong exception thrown " + contextMsg); 1.71 + } 1.72 + e.removeEventListener("DOMAttrModified", onAttrModified, false); 1.73 + if (expectedRes !== null) 1.74 + is(res, expectedRes, "wrong return value from " + funcName + 1.75 + " " + contextMsg); 1.76 + 1.77 + var expectedAfter = after; 1.78 + // XUL returns an empty string when getting a nonexistent class attribute. 1.79 + if (e.namespaceURI == XUL_NS && expectedAfter === null) 1.80 + expectedAfter = ""; 1.81 + 1.82 + is(e.getAttribute("class"), expectedAfter, "wrong class after modification " + 1.83 + contextMsg); 1.84 + var expectedMutation = before != after; 1.85 + is(gMutationEvents.length, expectedMutation ? 1 : 0, 1.86 + "unexpected mutation event count " + contextMsg); 1.87 + if (expectedMutation && gMutationEvents.length) { 1.88 + is(gMutationEvents[0].attrChange, 1.89 + before == null ? MutationEvent.ADDITION : MutationEvent.MODIFICATION, 1.90 + "wrong type of attribute change " + contextMsg); 1.91 + // If there wasn't any previous attribute, prevValue will return an empty 1.92 + // string. 1.93 + var expectedPrevValue = before === null ? "" : before; 1.94 + is(gMutationEvents[0].prevValue, expectedPrevValue, 1.95 + "wrong previous value " + contextMsg); 1.96 + is(gMutationEvents[0].newValue, after, "wrong new value " + contextMsg); 1.97 + } 1.98 +} 1.99 + 1.100 +function assignToClassListStrict(e) { 1.101 + "use strict"; 1.102 + try { 1.103 + e.classList = "foo"; 1.104 + ok(false, "assigning to classList didn't throw"); 1.105 + } catch (e) { } 1.106 +} 1.107 + 1.108 +function assignToClassList(e) { 1.109 + try { 1.110 + var expect = e.classList; 1.111 + e.classList = "foo"; 1.112 + is(e.classList, expect, "classList should be unchanged after assignment"); 1.113 + } catch (e) { 1.114 + ok(false, "assigning to classList threw"); 1.115 + } 1.116 +} 1.117 + 1.118 +function testClassList(e) { 1.119 + 1.120 + // basic tests 1.121 + 1.122 + isnot(e.classList, undefined, "no classList attribute"); 1.123 + is(typeof(e.classList.contains), "function", 1.124 + "no classList.contains function"); 1.125 + is(typeof(e.classList.add), "function", "no classList.add function"); 1.126 + is(typeof(e.classList.remove), "function", "no classList.remove function"); 1.127 + is(typeof(e.classList.toggle), "function", "no classList.toggle function"); 1.128 + 1.129 + assignToClassListStrict(e); 1.130 + assignToClassList(e); 1.131 + 1.132 + // length attribute 1.133 + 1.134 + is(e.classList.length, 0, "wrong classList.length value"); 1.135 + e.setAttribute("class", ""); 1.136 + is(e.classList.length, 0, "wrong classList.length value"); 1.137 + e.setAttribute("class", " \t \f"); 1.138 + is(e.classList.length, 0, "wrong classList.length value"); 1.139 + 1.140 + e.setAttribute("class", "a"); 1.141 + is(e.classList.length, 1, "wrong classList.length value"); 1.142 + e.setAttribute("class", "a A"); 1.143 + is(e.classList.length, 2, "wrong classList.length value"); 1.144 + e.setAttribute("class", "\r\na\t\f"); 1.145 + is(e.classList.length, 1, "wrong classList.length value"); 1.146 + 1.147 + e.setAttribute("class", "a a"); 1.148 + is(e.classList.length, 2, "wrong classList.length value"); 1.149 + 1.150 + e.setAttribute("class", "a a a a a a"); 1.151 + is(e.classList.length, 6, "wrong classList.length value"); 1.152 + 1.153 + e.setAttribute("class", "a a b b"); 1.154 + is(e.classList.length, 4, "wrong classList.length value"); 1.155 + 1.156 + e.setAttribute("class", "a A B b"); 1.157 + is(e.classList.length, 4, "wrong classList.length value"); 1.158 + 1.159 + e.setAttribute("class", "a b c c b a a b c c"); 1.160 + is(e.classList.length, 10, "wrong classList.length value"); 1.161 + 1.162 + // [Stringifies] 1.163 + 1.164 + ok(DOMTokenList.prototype.hasOwnProperty("toString"), 1.165 + "Should have own toString on DOMTokenList") 1.166 + ok(!DOMSettableTokenList.prototype.hasOwnProperty("toString"), 1.167 + "Should not have own toString on DOMSettableTokenList") 1.168 + 1.169 + e.removeAttribute("class"); 1.170 + is(e.classList.toString(), "", "wrong classList.toString() value"); 1.171 + is(e.classList + "", "", "wrong classList string conversion value"); 1.172 + 1.173 + e.setAttribute("class", "foo"); 1.174 + is(e.classList.toString(), "foo", "wrong classList.toString() value"); 1.175 + is(e.classList + "", "foo", "wrong classList string conversion value"); 1.176 + 1.177 + // item() method 1.178 + 1.179 + e.setAttribute("class", "a"); 1.180 + is(e.classList.item(-1), null, "wrong classList.item() result"); 1.181 + is(e.classList[-1], undefined, "wrong classList[] result"); 1.182 + is(e.classList.item(0), "a", "wrong classList.item() result"); 1.183 + is(e.classList[0], "a", "wrong classList[] result"); 1.184 + is(e.classList.item(1), null, "wrong classList.item() result"); 1.185 + is(e.classList[1], undefined, "wrong classList[] result"); 1.186 + 1.187 + e.setAttribute("class", "aa AA aa"); 1.188 + is(e.classList.item(-1), null, "wrong classList.item() result"); 1.189 + is(e.classList[-1], undefined, "wrong classList[] result"); 1.190 + is(e.classList.item(0), "aa", "wrong classList.item() result"); 1.191 + is(e.classList[0], "aa", "wrong classList[] result"); 1.192 + is(e.classList.item(1), "AA", "wrong classList.item() result"); 1.193 + is(e.classList[1], "AA", "wrong classList[] result"); 1.194 + is(e.classList.item(2), "aa", "wrong classList.item() result"); 1.195 + is(e.classList[2], "aa", "wrong classList[] result"); 1.196 + is(e.classList.item(3), null, "wrong classList.item() result"); 1.197 + is(e.classList[3], undefined, "wrong classList[] result"); 1.198 + is(e.classList.item(0xffffffff), null, "wrong classList.item() result"); 1.199 + is(e.classList[0xffffffff], undefined, "wrong classList[] result"); 1.200 + is(e.classList.item(0xfffffffe), null, "wrong classList.item() result"); 1.201 + is(e.classList[0xffffffe], undefined, "wrong classList[] result"); 1.202 + 1.203 + e.setAttribute("class", "a b"); 1.204 + is(e.classList.item(-1), null, "wrong classList.item() result"); 1.205 + is(e.classList[-1], undefined, "wrong classList[] result"); 1.206 + is(e.classList.item(0), "a", "wrong classList.item() result"); 1.207 + is(e.classList[0], "a", "wrong classList[] result"); 1.208 + is(e.classList.item(1), "b", "wrong classList.item() result"); 1.209 + is(e.classList[1], "b", "wrong classList[] result"); 1.210 + is(e.classList.item(2), null, "wrong classList.item() result"); 1.211 + is(e.classList[2], undefined, "wrong classList[] result"); 1.212 + 1.213 + // contains() method 1.214 + 1.215 + e.removeAttribute("class"); 1.216 + is(e.classList.contains("a"), false, "wrong classList.contains() result"); 1.217 + try { 1.218 + e.classList.contains(""); 1.219 + ok(false, "classList.contains() didn't throw"); 1.220 + } catch (e) { 1.221 + is(e.name, "SyntaxError", "wrong exception thrown"); 1.222 + is(e.code, DOMException.SYNTAX_ERR, "wrong exception thrown"); 1.223 + } 1.224 + try { 1.225 + e.classList.contains(" "); 1.226 + ok(false, "classList.contains() didn't throw"); 1.227 + } catch (e) { 1.228 + is(e.name, "InvalidCharacterError", "wrong exception thrown"); 1.229 + is(e.code, DOMException.INVALID_CHARACTER_ERR, "wrong exception thrown"); 1.230 + } 1.231 + try { 1.232 + e.classList.contains("aa "); 1.233 + ok(false, "classList.contains() didn't throw"); 1.234 + } catch (e) { 1.235 + is(e.name, "InvalidCharacterError", "wrong exception thrown"); 1.236 + is(e.code, DOMException.INVALID_CHARACTER_ERR, "wrong exception thrown"); 1.237 + } 1.238 + 1.239 + e.setAttribute("class", ""); 1.240 + is(e.classList.contains("a"), false, "wrong classList.contains() result"); 1.241 + 1.242 + e.setAttribute("class", "a"); 1.243 + is(e.classList.contains("a"), true, "wrong classList.contains() result"); 1.244 + is(e.classList.contains("aa"), false, "wrong classList.contains() result"); 1.245 + is(e.classList.contains("b"), false, "wrong classList.contains() result"); 1.246 + 1.247 + e.setAttribute("class", "aa AA"); 1.248 + is(e.classList.contains("aa"), true, "wrong classList.contains() result"); 1.249 + is(e.classList.contains("AA"), true, "wrong classList.contains() result"); 1.250 + is(e.classList.contains("aA"), false, "wrong classList.contains() result"); 1.251 + 1.252 + e.setAttribute("class", "a a a"); 1.253 + is(e.classList.contains("a"), true, "wrong classList.contains() result"); 1.254 + is(e.classList.contains("aa"), false, "wrong classList.contains() result"); 1.255 + is(e.classList.contains("b"), false, "wrong classList.contains() result"); 1.256 + 1.257 + e.setAttribute("class", "a b c"); 1.258 + is(e.classList.contains("a"), true, "wrong classList.contains() result"); 1.259 + is(e.classList.contains("b"), true, "wrong classList.contains() result"); 1.260 + 1.261 + // Test for bug 530171 1.262 + e.setAttribute("class", "null undefined"); 1.263 + is(e.classList.contains(null), true, "wrong classList.contains() result"); 1.264 + is(e.classList.contains(undefined), true, "wrong classList.contains() result"); 1.265 + 1.266 + // add() method 1.267 + 1.268 + function checkAdd(before, argument, after, expectedException) { 1.269 + checkModification(e, "add", argument, null, before, after, expectedException); 1.270 + } 1.271 + 1.272 + checkAdd(null, "", null, "SyntaxError"); 1.273 + checkAdd(null, ["a", ""], null, "SyntaxError"); 1.274 + checkAdd(null, " ", null, "InvalidCharacterError"); 1.275 + checkAdd(null, ["a", " "], null, "InvalidCharacterError"); 1.276 + checkAdd(null, ["a", "aa "], null, "InvalidCharacterError"); 1.277 + 1.278 + checkAdd("a", "a", "a"); 1.279 + checkAdd("aa", "AA", "aa AA"); 1.280 + checkAdd("a b c", "a", "a b c"); 1.281 + checkAdd("a a a b", "a", "a a a b"); 1.282 + checkAdd(null, "a", "a"); 1.283 + checkAdd("", "a", "a"); 1.284 + checkAdd(" ", "a", " a"); 1.285 + checkAdd(" \f", "a", " \fa"); 1.286 + checkAdd("a", "b", "a b"); 1.287 + checkAdd("a b c", "d", "a b c d"); 1.288 + checkAdd("a b c ", "d", "a b c d"); 1.289 + 1.290 + // multiple add 1.291 + checkAdd("a b c ", ["d", "e"], "a b c d e"); 1.292 + checkAdd("a b c ", ["a", "a"], "a b c "); 1.293 + checkAdd("a b c ", ["d", "d"], "a b c d"); 1.294 + checkAdd("a b c ", [], "a b c "); 1.295 + checkAdd(null, ["a", "b"], "a b"); 1.296 + checkAdd("", ["a", "b"], "a b"); 1.297 + 1.298 + // Test for bug 530171 1.299 + checkAdd(null, null, "null"); 1.300 + checkAdd(null, undefined, "undefined"); 1.301 + 1.302 + // remove() method 1.303 + 1.304 + function checkRemove(before, argument, after, expectedException) { 1.305 + checkModification(e, "remove", argument, null, before, after, expectedException); 1.306 + } 1.307 + 1.308 + checkRemove(null, "", null, "SyntaxError"); 1.309 + checkRemove(null, " ", null, "InvalidCharacterError"); 1.310 + checkRemove(null, "aa ", null, "InvalidCharacterError"); 1.311 + 1.312 + checkRemove(null, "a", null); 1.313 + checkRemove("", "a", ""); 1.314 + checkRemove("a b c", "d", "a b c"); 1.315 + checkRemove("a b c", "A", "a b c"); 1.316 + checkRemove(" a a a ", "a", ""); 1.317 + checkRemove("a b", "a", "b"); 1.318 + checkRemove("a b ", "a", "b "); 1.319 + checkRemove("a a b", "a", "b"); 1.320 + checkRemove("aa aa bb", "aa", "bb"); 1.321 + checkRemove("a a b a a c a a", "a", "b c"); 1.322 + 1.323 + checkRemove("a b c", "b", "a c"); 1.324 + checkRemove("aaa bbb ccc", "bbb", "aaa ccc"); 1.325 + checkRemove(" a b c ", "b", " a c "); 1.326 + checkRemove("a b b b c", "b", "a c"); 1.327 + 1.328 + checkRemove("a b c", "c", "a b"); 1.329 + checkRemove(" a b c ", "c", " a b"); 1.330 + checkRemove("a b c c c", "c", "a b"); 1.331 + 1.332 + checkRemove("a b a c a d a", "a", "b c d"); 1.333 + checkRemove("AA BB aa CC AA dd aa", "AA", "BB aa CC dd aa"); 1.334 + 1.335 + checkRemove("\ra\na\ta\f", "a", ""); 1.336 + 1.337 + // multiple remove 1.338 + checkRemove("a b c ", ["d", "e"], "a b c "); 1.339 + checkRemove("a b c ", ["a", "b"], "c "); 1.340 + checkRemove("a b c ", ["a", "c"], "b"); 1.341 + checkRemove("a b c ", ["a", "a"], "b c "); 1.342 + checkRemove("a b c ", ["d", "d"], "a b c "); 1.343 + checkRemove("a b c ", [], "a b c "); 1.344 + checkRemove(null, ["a", "b"], null); 1.345 + checkRemove("", ["a", "b"], ""); 1.346 + 1.347 + // Test for bug 530171 1.348 + checkRemove("null", null, ""); 1.349 + checkRemove("undefined", undefined, ""); 1.350 + 1.351 + // toggle() method 1.352 + 1.353 + function checkToggle(before, argument, expectedRes, after, expectedException) { 1.354 + checkModification(e, "toggle", argument, expectedRes, before, after, expectedException); 1.355 + } 1.356 + 1.357 + checkToggle(null, "", null, null, "SyntaxError"); 1.358 + checkToggle(null, "aa ", null, null, "InvalidCharacterError"); 1.359 + 1.360 + checkToggle(null, "a", true, "a"); 1.361 + checkToggle("", "a", true, "a"); 1.362 + checkToggle(" ", "a", true, " a"); 1.363 + checkToggle(" \f", "a", true, " \fa"); 1.364 + checkToggle("a", "b", true, "a b"); 1.365 + checkToggle("a", "A", true, "a A"); 1.366 + checkToggle("a b c", "d", true, "a b c d"); 1.367 + checkToggle("a b c", "d", true, "a b c d"); 1.368 + 1.369 + checkToggle("a", "a", false, ""); 1.370 + checkToggle(" a a a ", "a", false, ""); 1.371 + checkToggle(" A A A ", "a", true, " A A A a"); 1.372 + checkToggle(" a b c ", "b", false, " a c "); 1.373 + checkToggle(" a b c b b", "b", false, " a c"); 1.374 + checkToggle(" a b c ", "c", false, " a b"); 1.375 + checkToggle(" a b c ", "a", false, "b c "); 1.376 + 1.377 + // Test for bug 530171 1.378 + checkToggle("null", null, false, ""); 1.379 + checkToggle("", null, true, "null"); 1.380 + checkToggle("undefined", undefined, false, ""); 1.381 + checkToggle("", undefined, true, "undefined"); 1.382 + 1.383 + 1.384 + // tests for the force argument handling 1.385 + 1.386 + function checkForceToggle(before, argument, force, expectedRes, after, expectedException) { 1.387 + checkModification(e, "toggle", [argument, force], expectedRes, before, after, expectedException); 1.388 + } 1.389 + 1.390 + checkForceToggle("", "a", true, true, "a"); 1.391 + checkForceToggle("a", "a", true, true, "a"); 1.392 + checkForceToggle("a", "b", true, true, "a b"); 1.393 + checkForceToggle("a b", "b", true, true, "a b"); 1.394 + checkForceToggle("", "a", false, false, ""); 1.395 + checkForceToggle("a", "a", false, false, ""); 1.396 + checkForceToggle("a", "b", false, false, "a"); 1.397 + checkForceToggle("a b", "b", false, false, "a"); 1.398 +} 1.399 + 1.400 +var content = document.getElementById("content"); 1.401 + 1.402 +var htmlNode = document.createElement("div"); 1.403 +content.appendChild(htmlNode); 1.404 +testClassList(htmlNode); 1.405 + 1.406 +var xhtmlNode = document.createElementNS(XHTML_NS, "div"); 1.407 +content.appendChild(xhtmlNode); 1.408 +testClassList(xhtmlNode); 1.409 + 1.410 +var xulNode = document.createElementNS(XUL_NS, "box"); 1.411 +content.appendChild(xulNode); 1.412 +testClassList(xulNode); 1.413 + 1.414 +var mathMLNode = document.createElementNS(MATHML_NS, "math"); 1.415 +content.appendChild(mathMLNode); 1.416 +testClassList(mathMLNode); 1.417 + 1.418 +// Nodes not meant to be styled have a null classList property. 1.419 + 1.420 +var xmlNode = document.createElementNS(null, "foo"); 1.421 +content.appendChild(xmlNode); 1.422 +is(xmlNode.classList, null, "classList is not null for plain XML nodes"); 1.423 + 1.424 +var fooNode = document.createElementNS("http://example.org/foo", "foo"); 1.425 +content.appendChild(fooNode); 1.426 +is(fooNode.classList, null, "classList is not null for nodes in " + 1.427 + " http://example.org/foo namespace"); 1.428 + 1.429 +</script> 1.430 +</pre> 1.431 +</body> 1.432 +</html>