| OLD | NEW |
| (Empty) |
| 1 description('Tests the classList attribute and its properties.'); | |
| 2 | |
| 3 var element; | |
| 4 | |
| 5 function createElement(className) | |
| 6 { | |
| 7 element = document.createElement('p'); | |
| 8 element.className = className; | |
| 9 } | |
| 10 | |
| 11 debug('Tests from http://simon.html5.org/test/html/dom/reflecting/DOMTokenList/'
); | |
| 12 | |
| 13 // Even though classList is readonly, PutForwards=value means that its value is
forwarded. | |
| 14 createElement('x'); | |
| 15 try { | |
| 16 element.classList = 'y'; | |
| 17 shouldBeEqualToString('String(element.classList)', 'y'); | |
| 18 shouldBeEqualToString('String(element.className)', 'y'); | |
| 19 } catch (ex) { | |
| 20 testFailed('Throwing on set should not happen'); | |
| 21 } | |
| 22 | |
| 23 // http://simon.html5.org/test/html/dom/reflecting/DOMTokenList/getting/001.htm | |
| 24 createElement(''); | |
| 25 shouldEvaluateTo('element.classList.length', 0); | |
| 26 | |
| 27 // http://simon.html5.org/test/html/dom/reflecting/DOMTokenList/getting/002.htm | |
| 28 createElement('x'); | |
| 29 shouldEvaluateTo('element.classList.length', 1); | |
| 30 | |
| 31 // http://simon.html5.org/test/html/dom/reflecting/DOMTokenList/getting/003.htm | |
| 32 createElement('x x'); | |
| 33 shouldEvaluateTo('element.classList.length', 2); | |
| 34 | |
| 35 // http://simon.html5.org/test/html/dom/reflecting/DOMTokenList/getting/004.htm | |
| 36 createElement('x y'); | |
| 37 shouldEvaluateTo('element.classList.length', 2); | |
| 38 | |
| 39 // http://simon.html5.org/test/html/dom/reflecting/DOMTokenList/getting/005.htm | |
| 40 createElement(''); | |
| 41 element.classList.add('x'); | |
| 42 shouldBeEqualToString('element.className', 'x'); | |
| 43 | |
| 44 // http://simon.html5.org/test/html/dom/reflecting/DOMTokenList/getting/006.htm | |
| 45 createElement('x'); | |
| 46 element.classList.add('x'); | |
| 47 shouldBeEqualToString('element.className', 'x'); | |
| 48 | |
| 49 // http://simon.html5.org/test/html/dom/reflecting/DOMTokenList/getting/007.htm | |
| 50 createElement('x x'); | |
| 51 element.classList.add('x'); | |
| 52 shouldBeEqualToString('element.className', 'x x'); | |
| 53 | |
| 54 // http://simon.html5.org/test/html/dom/reflecting/DOMTokenList/getting/008.htm | |
| 55 createElement('y'); | |
| 56 element.classList.add('x'); | |
| 57 shouldBeEqualToString('element.className', 'y x'); | |
| 58 | |
| 59 // http://simon.html5.org/test/html/dom/reflecting/DOMTokenList/getting/009.htm | |
| 60 createElement(''); | |
| 61 element.classList.remove('x'); | |
| 62 shouldBeEqualToString('element.className', ''); | |
| 63 | |
| 64 // http://simon.html5.org/test/html/dom/reflecting/DOMTokenList/getting/010.htm | |
| 65 createElement('x'); | |
| 66 element.classList.remove('x'); | |
| 67 shouldBeEqualToString('element.className', ''); | |
| 68 | |
| 69 // http://simon.html5.org/test/html/dom/reflecting/DOMTokenList/getting/011.htm | |
| 70 createElement(' y x y '); | |
| 71 element.classList.remove('x'); | |
| 72 shouldBeEqualToString('element.className', 'y y'); | |
| 73 | |
| 74 // http://simon.html5.org/test/html/dom/reflecting/DOMTokenList/getting/012.htm | |
| 75 createElement(' x y x '); | |
| 76 element.classList.remove('x'); | |
| 77 shouldBeEqualToString('element.className', 'y'); | |
| 78 | |
| 79 | |
| 80 debug('Ensure that we can handle empty class name correctly'); | |
| 81 element = document.createElement('span'); | |
| 82 shouldBeTrue("element.classList.toggle('x')"); | |
| 83 shouldBeEqualToString('element.className', 'x'); | |
| 84 shouldBeFalse("element.classList.toggle('x')"); | |
| 85 shouldBeEqualToString('element.className', ''); | |
| 86 | |
| 87 element = document.createElement('span'); | |
| 88 shouldBeFalse('element.classList.contains(\'x\')'); | |
| 89 shouldBeUndefined('element.classList[1]'); | |
| 90 element.classList.remove('x'); | |
| 91 element.classList.add('x') | |
| 92 | |
| 93 | |
| 94 debug('Test toggle with force argument') | |
| 95 | |
| 96 createElement(''); | |
| 97 shouldBeTrue("element.classList.toggle('x', true)"); | |
| 98 shouldBeEqualToString('element.className', 'x'); | |
| 99 shouldBeTrue("element.classList.toggle('x', true)"); | |
| 100 shouldBeEqualToString('element.className', 'x'); | |
| 101 shouldBeFalse("element.classList.toggle('x', false)"); | |
| 102 shouldBeEqualToString('element.className', ''); | |
| 103 shouldBeFalse("element.classList.toggle('x', false)"); | |
| 104 shouldBeEqualToString('element.className', ''); | |
| 105 | |
| 106 shouldThrowDOMException(function() { | |
| 107 element.classList.toggle('', true); | |
| 108 }, DOMException.SYNTAX_ERR); | |
| 109 | |
| 110 shouldThrowDOMException(function() { | |
| 111 element.classList.toggle('x y', false); | |
| 112 }, DOMException.INVALID_CHARACTER_ERR); | |
| 113 | |
| 114 | |
| 115 debug('Testing add in presence of trailing white spaces.'); | |
| 116 | |
| 117 createElement('x '); | |
| 118 element.classList.add('y'); | |
| 119 shouldBeEqualToString('element.className', 'x y'); | |
| 120 | |
| 121 createElement('x\t'); | |
| 122 element.classList.add('y'); | |
| 123 shouldBeEqualToString('element.className', 'x\ty'); | |
| 124 | |
| 125 createElement(' '); | |
| 126 element.classList.add('y'); | |
| 127 shouldBeEqualToString('element.className', ' y'); | |
| 128 | |
| 129 | |
| 130 debug('Test invalid tokens'); | |
| 131 | |
| 132 // Testing exception due to invalid token | |
| 133 | |
| 134 // shouldThrow from js-test.js is not sufficient. | |
| 135 function shouldThrowDOMException(f, ec) | |
| 136 { | |
| 137 try { | |
| 138 f(); | |
| 139 testFailed('Expected an exception'); | |
| 140 } catch (ex) { | |
| 141 if (!(ex instanceof DOMException)) { | |
| 142 testFailed('Exception is not an instance of DOMException, found: ' + | |
| 143 Object.toString.call(ex)); | |
| 144 return; | |
| 145 } | |
| 146 if (ec !== ex.code) { | |
| 147 testFailed('Wrong exception code: ' + ex.code); | |
| 148 return; | |
| 149 } | |
| 150 } | |
| 151 var formattedFunction = String(f).replace(/^function.+\{\s*/m, ''). | |
| 152 replace(/;?\s+\}/m, ''); | |
| 153 testPassed(formattedFunction + ' threw expected DOMException with code ' + e
c); | |
| 154 } | |
| 155 | |
| 156 createElement('x'); | |
| 157 shouldThrowDOMException(function() { | |
| 158 element.classList.contains(''); | |
| 159 }, DOMException.SYNTAX_ERR); | |
| 160 | |
| 161 createElement('x y'); | |
| 162 shouldThrowDOMException(function() { | |
| 163 element.classList.contains('x y'); | |
| 164 }, DOMException.INVALID_CHARACTER_ERR); | |
| 165 | |
| 166 createElement(''); | |
| 167 shouldThrowDOMException(function() { | |
| 168 element.classList.add(''); | |
| 169 }, DOMException.SYNTAX_ERR); | |
| 170 | |
| 171 createElement(''); | |
| 172 shouldThrowDOMException(function() { | |
| 173 element.classList.add('x y'); | |
| 174 }, DOMException.INVALID_CHARACTER_ERR); | |
| 175 | |
| 176 createElement(''); | |
| 177 shouldThrowDOMException(function() { | |
| 178 element.classList.remove(''); | |
| 179 }, DOMException.SYNTAX_ERR); | |
| 180 | |
| 181 createElement(''); | |
| 182 shouldThrowDOMException(function() { | |
| 183 element.classList.remove('x y'); | |
| 184 }, DOMException.INVALID_CHARACTER_ERR); | |
| 185 | |
| 186 | |
| 187 | |
| 188 createElement(''); | |
| 189 shouldThrowDOMException(function() { | |
| 190 element.classList.toggle(''); | |
| 191 }, DOMException.SYNTAX_ERR); | |
| 192 | |
| 193 createElement('x y'); | |
| 194 shouldThrowDOMException(function() { | |
| 195 element.classList.toggle('x y'); | |
| 196 }, DOMException.INVALID_CHARACTER_ERR); | |
| 197 | |
| 198 createElement(''); | |
| 199 shouldThrow("element.classList.toggle()"); | |
| 200 | |
| 201 debug('Indexing'); | |
| 202 | |
| 203 createElement('x'); | |
| 204 shouldBeEqualToString('element.classList[0]', 'x'); | |
| 205 shouldBeEqualToString('element.classList.item(0)', 'x'); | |
| 206 | |
| 207 createElement('x x'); | |
| 208 shouldBeEqualToString('element.classList[1]', 'x'); | |
| 209 shouldBeEqualToString('element.classList.item(1)', 'x'); | |
| 210 | |
| 211 createElement('x y'); | |
| 212 shouldBeEqualToString('element.classList[1]', 'y'); | |
| 213 shouldBeEqualToString('element.classList.item(1)', 'y'); | |
| 214 | |
| 215 createElement(''); | |
| 216 shouldBeUndefined('element.classList[0]'); | |
| 217 shouldBeNull('element.classList.item(0)'); | |
| 218 | |
| 219 createElement('x y z'); | |
| 220 shouldBeUndefined('element.classList[4]'); | |
| 221 shouldBeNull('element.classList.item(4)'); | |
| 222 shouldBeUndefined('element.classList[-1]'); // Not a valid index so should not
trigger item(). | |
| 223 shouldBeNull('element.classList.item(-1)'); | |
| 224 shouldThrow('element.classList.item()'); | |
| 225 | |
| 226 debug('Test case since DOMTokenList is case sensitive'); | |
| 227 | |
| 228 createElement('x'); | |
| 229 shouldBeTrue('element.classList.contains(\'x\')'); | |
| 230 shouldBeFalse('element.classList.contains(\'X\')'); | |
| 231 shouldBeEqualToString('element.classList[0]', 'x'); | |
| 232 shouldThrow('element.classList.contains()'); | |
| 233 | |
| 234 createElement('X'); | |
| 235 shouldBeTrue('element.classList.contains(\'X\')'); | |
| 236 shouldBeFalse('element.classList.contains(\'x\')'); | |
| 237 shouldBeEqualToString('element.classList[0]', 'X'); | |
| 238 | |
| 239 | |
| 240 debug('Testing whitespace'); | |
| 241 // U+0020 SPACE, U+0009 CHARACTER TABULATION (tab), U+000A LINE FEED (LF), | |
| 242 // U+000C FORM FEED (FF), and U+000D CARRIAGE RETURN (CR) | |
| 243 | |
| 244 createElement('x\u0020y'); | |
| 245 shouldEvaluateTo('element.classList.length', 2); | |
| 246 | |
| 247 createElement('x\u0009y'); | |
| 248 shouldEvaluateTo('element.classList.length', 2); | |
| 249 | |
| 250 createElement('x\u000Ay'); | |
| 251 shouldEvaluateTo('element.classList.length', 2); | |
| 252 | |
| 253 createElement('x\u000Cy'); | |
| 254 shouldEvaluateTo('element.classList.length', 2); | |
| 255 | |
| 256 createElement('x\u000Dy'); | |
| 257 shouldEvaluateTo('element.classList.length', 2); | |
| 258 | |
| 259 | |
| 260 debug('DOMTokenList presence and type'); | |
| 261 | |
| 262 | |
| 263 // Safari returns object | |
| 264 // Firefox returns object | |
| 265 // IE8 returns object | |
| 266 // Chrome returns function | |
| 267 // assertEquals('object', typeof DOMTokenList); | |
| 268 shouldBeTrue('\'undefined\' != typeof DOMTokenList'); | |
| 269 | |
| 270 shouldBeEqualToString('typeof DOMTokenList.prototype', 'object'); | |
| 271 | |
| 272 createElement('x'); | |
| 273 shouldBeEqualToString('typeof element.classList', 'object'); | |
| 274 | |
| 275 shouldEvaluateTo('element.classList.constructor', 'DOMTokenList'); | |
| 276 | |
| 277 shouldBeTrue('element.classList === element.classList'); | |
| 278 | |
| 279 // Bug 93628 | |
| 280 document.body.classList.add('FAIL'); | |
| 281 shouldBeTrue('document.body.classList.contains("FAIL")'); | |
| 282 document.body.classList.remove('FAIL'); | |
| 283 shouldBeEqualToString('document.body.className', ''); | |
| 284 | |
| 285 // Variadic | |
| 286 | |
| 287 debug('Variadic calls'); | |
| 288 | |
| 289 createElement(''); | |
| 290 element.classList.add('a', 'b'); | |
| 291 shouldBeEqualToString('element.className', 'a b'); | |
| 292 | |
| 293 element.classList.add('a', 'b', 'c'); | |
| 294 shouldBeEqualToString('element.className', 'a b c'); | |
| 295 | |
| 296 element.classList.add(null, {toString: function() { return 'd' }}, undefined, 0,
false); | |
| 297 shouldBeEqualToString('element.className', 'a b c null d undefined 0 false'); | |
| 298 | |
| 299 createElement(''); | |
| 300 element.classList.add('a', 'b', 'a'); | |
| 301 shouldBeEqualToString('element.className', 'a b'); | |
| 302 | |
| 303 createElement(''); | |
| 304 shouldThrowDOMException(function() { | |
| 305 element.classList.add('a', 'b', ''); | |
| 306 }, DOMException.SYNTAX_ERR); | |
| 307 shouldBeEqualToString('element.className', ''); | |
| 308 | |
| 309 shouldThrowDOMException(function() { | |
| 310 element.classList.add('a', 'b', 'c d'); | |
| 311 }, DOMException.INVALID_CHARACTER_ERR); | |
| 312 shouldBeEqualToString('element.className', ''); | |
| 313 | |
| 314 shouldThrow('element.classList.add("a", {toString: function() { throw new Error(
"user error"); }}, "b")', '"Error: user error"'); | |
| 315 shouldBeEqualToString('element.className', ''); | |
| 316 | |
| 317 createElement(''); | |
| 318 shouldNotThrow('element.classList.add()'); | |
| 319 | |
| 320 createElement(''); | |
| 321 var observer = new WebKitMutationObserver(function() {}); | |
| 322 observer.observe(element, {attributes: true}); | |
| 323 element.classList.add('a', 'c'); | |
| 324 shouldBe('observer.takeRecords().length', '1'); | |
| 325 | |
| 326 createElement(' a b c '); | |
| 327 element.classList.remove('a'); | |
| 328 shouldBeEqualToString("element.className", "b c"); | |
| 329 | |
| 330 createElement(' a b c '); | |
| 331 element.classList.remove('b'); | |
| 332 shouldBeEqualToString("element.className", "a c"); | |
| 333 | |
| 334 createElement(' a b c '); | |
| 335 element.classList.remove('c'); | |
| 336 shouldBeEqualToString("element.className", "a b"); | |
| 337 | |
| 338 createElement('a b c d '); | |
| 339 element.classList.remove('a', 'c'); | |
| 340 shouldBeEqualToString('element.className', 'b d'); | |
| 341 | |
| 342 element.classList.remove('b', 'b'); | |
| 343 shouldBeEqualToString('element.className', 'd'); | |
| 344 | |
| 345 createElement('a b c null d undefined 0 false'); | |
| 346 element.classList.remove(null, {toString: function() { return 'd' }}, undefined,
0, false); | |
| 347 shouldBeEqualToString('element.className', 'a b c'); | |
| 348 | |
| 349 createElement('a b'); | |
| 350 shouldThrowDOMException(function() { | |
| 351 element.classList.remove('a', 'b', ''); | |
| 352 }, DOMException.SYNTAX_ERR); | |
| 353 shouldBeEqualToString('element.className', 'a b'); | |
| 354 | |
| 355 shouldThrowDOMException(function() { | |
| 356 element.classList.remove('a', 'b', 'c d'); | |
| 357 }, DOMException.INVALID_CHARACTER_ERR); | |
| 358 shouldBeEqualToString('element.className', 'a b'); | |
| 359 | |
| 360 shouldThrow('element.classList.remove("a", {toString: function() { throw new Err
or("user error"); }}, "b")', '"Error: user error"'); | |
| 361 shouldBeEqualToString('element.className', 'a b'); | |
| 362 | |
| 363 shouldNotThrow('element.classList.remove()'); | |
| 364 | |
| 365 createElement('a b c'); | |
| 366 observer = new WebKitMutationObserver(function() {}); | |
| 367 observer.observe(element, {attributes: true}); | |
| 368 element.classList.remove('a', 'c'); | |
| 369 shouldBe('observer.takeRecords().length', '1'); | |
| 370 | |
| 371 // iterable<DOMString>; | |
| 372 createElement('a b c'); | |
| 373 var seen = []; | |
| 374 for (var t of element.classList) { | |
| 375 seen.push(t); | |
| 376 } | |
| 377 shouldBeTrue("areArraysEqual(seen, ['a', 'b', 'c'])"); | |
| OLD | NEW |