Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
1 <!DOCTYPE HTML>
2 <html>
3 <!--
4 https://bugzilla.mozilla.org/show_bug.cgi?id=501257
5 -->
6 <head>
7 <title>Test for the classList element attribute</title>
8 <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
9 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
10 </head>
11 <body>
12 <a target="_blank" href="http://www.whatwg.org/specs/web-apps/current-work/#dom-classlist">classList DOM attribute</a>
13 <p id="display"></p>
14 <div id="content" style="display: none">
15 </div>
16 <pre id="test">
17 <script type="application/javascript">
19 /** Test for Bug 501257 **/
21 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
22 const SVG_NS = "http://www.w3.org/2000/svg";
23 const XHTML_NS = "http://www.w3.org/1999/xhtml"
24 const MATHML_NS = "http://www.w3.org/1998/Math/MathML";
26 var gMutationEvents = [];
28 function onAttrModified(event) {
29 is(event.attrName, "class", "mutation on unexpected attribute");
31 gMutationEvents.push({
32 attrChange: event.attrChange,
33 prevValue: event.prevValue,
34 newValue: event.newValue,
35 });
36 }
38 function checkModification(e, funcName, args, expectedRes, before, after, expectedException) {
39 if (!Array.isArray(args)) {
40 args = [args];
41 }
43 var shouldThrow = typeof(expectedException) === "string";
44 if (shouldThrow) {
45 // If an exception is thrown, the class attribute shouldn't change.
46 after = before;
47 }
48 if (before === null)
49 e.removeAttribute("class");
50 else
51 e.setAttribute("class", before);
53 var contextMsg = "(checkModification: funcName=" + funcName + ",args=" +
54 JSON.stringify(args) + ",expectedRes=" + expectedRes +
55 ",before=" + before + ",after=" + after + ")";
57 gMutationEvents = [];
58 e.addEventListener("DOMAttrModified", onAttrModified, false);
59 try {
60 var list = e.classList;
61 var res = list[funcName].apply(list, args);
62 if (shouldThrow)
63 ok(false, "classList modification didn't throw " + contextMsg);
64 } catch (e) {
65 if (!shouldThrow)
66 ok(false, "classList modification threw an exception " + contextMsg);
67 is(e.name, expectedException, "wrong exception thrown " + contextMsg);
68 }
69 e.removeEventListener("DOMAttrModified", onAttrModified, false);
70 if (expectedRes !== null)
71 is(res, expectedRes, "wrong return value from " + funcName +
72 " " + contextMsg);
74 var expectedAfter = after;
75 // XUL returns an empty string when getting a nonexistent class attribute.
76 if (e.namespaceURI == XUL_NS && expectedAfter === null)
77 expectedAfter = "";
79 is(e.getAttribute("class"), expectedAfter, "wrong class after modification " +
80 contextMsg);
81 var expectedMutation = before != after;
82 is(gMutationEvents.length, expectedMutation ? 1 : 0,
83 "unexpected mutation event count " + contextMsg);
84 if (expectedMutation && gMutationEvents.length) {
85 is(gMutationEvents[0].attrChange,
86 before == null ? MutationEvent.ADDITION : MutationEvent.MODIFICATION,
87 "wrong type of attribute change " + contextMsg);
88 // If there wasn't any previous attribute, prevValue will return an empty
89 // string.
90 var expectedPrevValue = before === null ? "" : before;
91 is(gMutationEvents[0].prevValue, expectedPrevValue,
92 "wrong previous value " + contextMsg);
93 is(gMutationEvents[0].newValue, after, "wrong new value " + contextMsg);
94 }
95 }
97 function assignToClassListStrict(e) {
98 "use strict";
99 try {
100 e.classList = "foo";
101 ok(false, "assigning to classList didn't throw");
102 } catch (e) { }
103 }
105 function assignToClassList(e) {
106 try {
107 var expect = e.classList;
108 e.classList = "foo";
109 is(e.classList, expect, "classList should be unchanged after assignment");
110 } catch (e) {
111 ok(false, "assigning to classList threw");
112 }
113 }
115 function testClassList(e) {
117 // basic tests
119 isnot(e.classList, undefined, "no classList attribute");
120 is(typeof(e.classList.contains), "function",
121 "no classList.contains function");
122 is(typeof(e.classList.add), "function", "no classList.add function");
123 is(typeof(e.classList.remove), "function", "no classList.remove function");
124 is(typeof(e.classList.toggle), "function", "no classList.toggle function");
126 assignToClassListStrict(e);
127 assignToClassList(e);
129 // length attribute
131 is(e.classList.length, 0, "wrong classList.length value");
132 e.setAttribute("class", "");
133 is(e.classList.length, 0, "wrong classList.length value");
134 e.setAttribute("class", " \t \f");
135 is(e.classList.length, 0, "wrong classList.length value");
137 e.setAttribute("class", "a");
138 is(e.classList.length, 1, "wrong classList.length value");
139 e.setAttribute("class", "a A");
140 is(e.classList.length, 2, "wrong classList.length value");
141 e.setAttribute("class", "\r\na\t\f");
142 is(e.classList.length, 1, "wrong classList.length value");
144 e.setAttribute("class", "a a");
145 is(e.classList.length, 2, "wrong classList.length value");
147 e.setAttribute("class", "a a a a a a");
148 is(e.classList.length, 6, "wrong classList.length value");
150 e.setAttribute("class", "a a b b");
151 is(e.classList.length, 4, "wrong classList.length value");
153 e.setAttribute("class", "a A B b");
154 is(e.classList.length, 4, "wrong classList.length value");
156 e.setAttribute("class", "a b c c b a a b c c");
157 is(e.classList.length, 10, "wrong classList.length value");
159 // [Stringifies]
161 ok(DOMTokenList.prototype.hasOwnProperty("toString"),
162 "Should have own toString on DOMTokenList")
163 ok(!DOMSettableTokenList.prototype.hasOwnProperty("toString"),
164 "Should not have own toString on DOMSettableTokenList")
166 e.removeAttribute("class");
167 is(e.classList.toString(), "", "wrong classList.toString() value");
168 is(e.classList + "", "", "wrong classList string conversion value");
170 e.setAttribute("class", "foo");
171 is(e.classList.toString(), "foo", "wrong classList.toString() value");
172 is(e.classList + "", "foo", "wrong classList string conversion value");
174 // item() method
176 e.setAttribute("class", "a");
177 is(e.classList.item(-1), null, "wrong classList.item() result");
178 is(e.classList[-1], undefined, "wrong classList[] result");
179 is(e.classList.item(0), "a", "wrong classList.item() result");
180 is(e.classList[0], "a", "wrong classList[] result");
181 is(e.classList.item(1), null, "wrong classList.item() result");
182 is(e.classList[1], undefined, "wrong classList[] result");
184 e.setAttribute("class", "aa AA aa");
185 is(e.classList.item(-1), null, "wrong classList.item() result");
186 is(e.classList[-1], undefined, "wrong classList[] result");
187 is(e.classList.item(0), "aa", "wrong classList.item() result");
188 is(e.classList[0], "aa", "wrong classList[] result");
189 is(e.classList.item(1), "AA", "wrong classList.item() result");
190 is(e.classList[1], "AA", "wrong classList[] result");
191 is(e.classList.item(2), "aa", "wrong classList.item() result");
192 is(e.classList[2], "aa", "wrong classList[] result");
193 is(e.classList.item(3), null, "wrong classList.item() result");
194 is(e.classList[3], undefined, "wrong classList[] result");
195 is(e.classList.item(0xffffffff), null, "wrong classList.item() result");
196 is(e.classList[0xffffffff], undefined, "wrong classList[] result");
197 is(e.classList.item(0xfffffffe), null, "wrong classList.item() result");
198 is(e.classList[0xffffffe], undefined, "wrong classList[] result");
200 e.setAttribute("class", "a b");
201 is(e.classList.item(-1), null, "wrong classList.item() result");
202 is(e.classList[-1], undefined, "wrong classList[] result");
203 is(e.classList.item(0), "a", "wrong classList.item() result");
204 is(e.classList[0], "a", "wrong classList[] result");
205 is(e.classList.item(1), "b", "wrong classList.item() result");
206 is(e.classList[1], "b", "wrong classList[] result");
207 is(e.classList.item(2), null, "wrong classList.item() result");
208 is(e.classList[2], undefined, "wrong classList[] result");
210 // contains() method
212 e.removeAttribute("class");
213 is(e.classList.contains("a"), false, "wrong classList.contains() result");
214 try {
215 e.classList.contains("");
216 ok(false, "classList.contains() didn't throw");
217 } catch (e) {
218 is(e.name, "SyntaxError", "wrong exception thrown");
219 is(e.code, DOMException.SYNTAX_ERR, "wrong exception thrown");
220 }
221 try {
222 e.classList.contains(" ");
223 ok(false, "classList.contains() didn't throw");
224 } catch (e) {
225 is(e.name, "InvalidCharacterError", "wrong exception thrown");
226 is(e.code, DOMException.INVALID_CHARACTER_ERR, "wrong exception thrown");
227 }
228 try {
229 e.classList.contains("aa ");
230 ok(false, "classList.contains() didn't throw");
231 } catch (e) {
232 is(e.name, "InvalidCharacterError", "wrong exception thrown");
233 is(e.code, DOMException.INVALID_CHARACTER_ERR, "wrong exception thrown");
234 }
236 e.setAttribute("class", "");
237 is(e.classList.contains("a"), false, "wrong classList.contains() result");
239 e.setAttribute("class", "a");
240 is(e.classList.contains("a"), true, "wrong classList.contains() result");
241 is(e.classList.contains("aa"), false, "wrong classList.contains() result");
242 is(e.classList.contains("b"), false, "wrong classList.contains() result");
244 e.setAttribute("class", "aa AA");
245 is(e.classList.contains("aa"), true, "wrong classList.contains() result");
246 is(e.classList.contains("AA"), true, "wrong classList.contains() result");
247 is(e.classList.contains("aA"), false, "wrong classList.contains() result");
249 e.setAttribute("class", "a a a");
250 is(e.classList.contains("a"), true, "wrong classList.contains() result");
251 is(e.classList.contains("aa"), false, "wrong classList.contains() result");
252 is(e.classList.contains("b"), false, "wrong classList.contains() result");
254 e.setAttribute("class", "a b c");
255 is(e.classList.contains("a"), true, "wrong classList.contains() result");
256 is(e.classList.contains("b"), true, "wrong classList.contains() result");
258 // Test for bug 530171
259 e.setAttribute("class", "null undefined");
260 is(e.classList.contains(null), true, "wrong classList.contains() result");
261 is(e.classList.contains(undefined), true, "wrong classList.contains() result");
263 // add() method
265 function checkAdd(before, argument, after, expectedException) {
266 checkModification(e, "add", argument, null, before, after, expectedException);
267 }
269 checkAdd(null, "", null, "SyntaxError");
270 checkAdd(null, ["a", ""], null, "SyntaxError");
271 checkAdd(null, " ", null, "InvalidCharacterError");
272 checkAdd(null, ["a", " "], null, "InvalidCharacterError");
273 checkAdd(null, ["a", "aa "], null, "InvalidCharacterError");
275 checkAdd("a", "a", "a");
276 checkAdd("aa", "AA", "aa AA");
277 checkAdd("a b c", "a", "a b c");
278 checkAdd("a a a b", "a", "a a a b");
279 checkAdd(null, "a", "a");
280 checkAdd("", "a", "a");
281 checkAdd(" ", "a", " a");
282 checkAdd(" \f", "a", " \fa");
283 checkAdd("a", "b", "a b");
284 checkAdd("a b c", "d", "a b c d");
285 checkAdd("a b c ", "d", "a b c d");
287 // multiple add
288 checkAdd("a b c ", ["d", "e"], "a b c d e");
289 checkAdd("a b c ", ["a", "a"], "a b c ");
290 checkAdd("a b c ", ["d", "d"], "a b c d");
291 checkAdd("a b c ", [], "a b c ");
292 checkAdd(null, ["a", "b"], "a b");
293 checkAdd("", ["a", "b"], "a b");
295 // Test for bug 530171
296 checkAdd(null, null, "null");
297 checkAdd(null, undefined, "undefined");
299 // remove() method
301 function checkRemove(before, argument, after, expectedException) {
302 checkModification(e, "remove", argument, null, before, after, expectedException);
303 }
305 checkRemove(null, "", null, "SyntaxError");
306 checkRemove(null, " ", null, "InvalidCharacterError");
307 checkRemove(null, "aa ", null, "InvalidCharacterError");
309 checkRemove(null, "a", null);
310 checkRemove("", "a", "");
311 checkRemove("a b c", "d", "a b c");
312 checkRemove("a b c", "A", "a b c");
313 checkRemove(" a a a ", "a", "");
314 checkRemove("a b", "a", "b");
315 checkRemove("a b ", "a", "b ");
316 checkRemove("a a b", "a", "b");
317 checkRemove("aa aa bb", "aa", "bb");
318 checkRemove("a a b a a c a a", "a", "b c");
320 checkRemove("a b c", "b", "a c");
321 checkRemove("aaa bbb ccc", "bbb", "aaa ccc");
322 checkRemove(" a b c ", "b", " a c ");
323 checkRemove("a b b b c", "b", "a c");
325 checkRemove("a b c", "c", "a b");
326 checkRemove(" a b c ", "c", " a b");
327 checkRemove("a b c c c", "c", "a b");
329 checkRemove("a b a c a d a", "a", "b c d");
330 checkRemove("AA BB aa CC AA dd aa", "AA", "BB aa CC dd aa");
332 checkRemove("\ra\na\ta\f", "a", "");
334 // multiple remove
335 checkRemove("a b c ", ["d", "e"], "a b c ");
336 checkRemove("a b c ", ["a", "b"], "c ");
337 checkRemove("a b c ", ["a", "c"], "b");
338 checkRemove("a b c ", ["a", "a"], "b c ");
339 checkRemove("a b c ", ["d", "d"], "a b c ");
340 checkRemove("a b c ", [], "a b c ");
341 checkRemove(null, ["a", "b"], null);
342 checkRemove("", ["a", "b"], "");
344 // Test for bug 530171
345 checkRemove("null", null, "");
346 checkRemove("undefined", undefined, "");
348 // toggle() method
350 function checkToggle(before, argument, expectedRes, after, expectedException) {
351 checkModification(e, "toggle", argument, expectedRes, before, after, expectedException);
352 }
354 checkToggle(null, "", null, null, "SyntaxError");
355 checkToggle(null, "aa ", null, null, "InvalidCharacterError");
357 checkToggle(null, "a", true, "a");
358 checkToggle("", "a", true, "a");
359 checkToggle(" ", "a", true, " a");
360 checkToggle(" \f", "a", true, " \fa");
361 checkToggle("a", "b", true, "a b");
362 checkToggle("a", "A", true, "a A");
363 checkToggle("a b c", "d", true, "a b c d");
364 checkToggle("a b c", "d", true, "a b c d");
366 checkToggle("a", "a", false, "");
367 checkToggle(" a a a ", "a", false, "");
368 checkToggle(" A A A ", "a", true, " A A A a");
369 checkToggle(" a b c ", "b", false, " a c ");
370 checkToggle(" a b c b b", "b", false, " a c");
371 checkToggle(" a b c ", "c", false, " a b");
372 checkToggle(" a b c ", "a", false, "b c ");
374 // Test for bug 530171
375 checkToggle("null", null, false, "");
376 checkToggle("", null, true, "null");
377 checkToggle("undefined", undefined, false, "");
378 checkToggle("", undefined, true, "undefined");
381 // tests for the force argument handling
383 function checkForceToggle(before, argument, force, expectedRes, after, expectedException) {
384 checkModification(e, "toggle", [argument, force], expectedRes, before, after, expectedException);
385 }
387 checkForceToggle("", "a", true, true, "a");
388 checkForceToggle("a", "a", true, true, "a");
389 checkForceToggle("a", "b", true, true, "a b");
390 checkForceToggle("a b", "b", true, true, "a b");
391 checkForceToggle("", "a", false, false, "");
392 checkForceToggle("a", "a", false, false, "");
393 checkForceToggle("a", "b", false, false, "a");
394 checkForceToggle("a b", "b", false, false, "a");
395 }
397 var content = document.getElementById("content");
399 var htmlNode = document.createElement("div");
400 content.appendChild(htmlNode);
401 testClassList(htmlNode);
403 var xhtmlNode = document.createElementNS(XHTML_NS, "div");
404 content.appendChild(xhtmlNode);
405 testClassList(xhtmlNode);
407 var xulNode = document.createElementNS(XUL_NS, "box");
408 content.appendChild(xulNode);
409 testClassList(xulNode);
411 var mathMLNode = document.createElementNS(MATHML_NS, "math");
412 content.appendChild(mathMLNode);
413 testClassList(mathMLNode);
415 // Nodes not meant to be styled have a null classList property.
417 var xmlNode = document.createElementNS(null, "foo");
418 content.appendChild(xmlNode);
419 is(xmlNode.classList, null, "classList is not null for plain XML nodes");
421 var fooNode = document.createElementNS("http://example.org/foo", "foo");
422 content.appendChild(fooNode);
423 is(fooNode.classList, null, "classList is not null for nodes in " +
424 " http://example.org/foo namespace");
426 </script>
427 </pre>
428 </body>
429 </html>