OLD | NEW |
(Empty) | |
| 1 <!doctype html> |
| 2 <html> |
| 3 <head class="test test"> |
| 4 <title class=" ">Element.classList in case-sensitive documents</title> |
| 5 <link rel="help" href="https://dom.spec.whatwg.org/#concept-class"> |
| 6 <script type="text/javascript" src="../../../../resources/testharness.js"></
script> |
| 7 <script type="text/javascript" src="../../../../resources/testharnessreport.
js"></script> |
| 8 <style type="text/css"> |
| 9 .foo { font-style: italic; } |
| 10 </style> |
| 11 <script type="text/javascript"> |
| 12 var elem = document.getElementsByTagName('title')[0], secondelem = document.getE
lementsByTagName('head')[0]; |
| 13 test(function () { |
| 14 assert_equals( typeof elem.classList, 'object', 'critical test; ignore any res
ults after this' ); |
| 15 }, 'Element.classList must exist as an object'); |
| 16 test(function () { |
| 17 assert_equals( typeof document.documentElement.classList, 'object' ); |
| 18 }, 'Element.classList must exist as an object even if the element has no class a
ttribute'); |
| 19 test(function () { |
| 20 assert_true( !!window.DOMTokenList ); |
| 21 }, 'DOMTokenList should be exposed for prototyping'); |
| 22 test(function () { |
| 23 DOMTokenList.prototype.customProperty = true; |
| 24 assert_true( elem.classList.customProperty ); |
| 25 }, 'prototyping DOMTokenList should work'); |
| 26 test(function () { |
| 27 assert_true( elem.classList instanceof window.DOMTokenList ); |
| 28 assert_equals( elem.classList.constructor, window.DOMTokenList ); |
| 29 }, 'Element.classList must implement DOMTokenList'); |
| 30 test(function () { |
| 31 assert_not_equals( getComputedStyle(elem,null).fontStyle, 'italic', 'critical
test; required by the testsuite' ); |
| 32 }, 'CSS .foo selectors must not match elements without any class'); |
| 33 test(function () { |
| 34 assert_equals( secondelem.classList.length, 1, 'duplicates in initial string s
hould be removed per https://dom.spec.whatwg.org/#concept-class' ); |
| 35 assert_equals( secondelem.classList.item(0), 'test' ); |
| 36 assert_true( secondelem.classList.contains('test') ); |
| 37 }, 'classList must be correct for an element that has classes'); |
| 38 test(function () { |
| 39 assert_equals( elem.classList.length, 0 ); |
| 40 }, 'classList.length must be 0 for an element that has no classes'); |
| 41 test(function () { |
| 42 assert_false( elem.classList.contains('foo') ); |
| 43 }, 'classList must not contain an undefined class'); |
| 44 test(function () { |
| 45 assert_equals( elem.classList.item(0), null ); |
| 46 }, 'classList.item() must return null for out-of-range index'); |
| 47 test(function () { |
| 48 assert_equals( elem.classList.item(-1), null ); |
| 49 }, 'classList.item() must return null for negative index'); |
| 50 test(function () { |
| 51 /* the normative part of the spec states that: |
| 52 "unless tokens is empty, in which case there are no supported property indices
" |
| 53 ... |
| 54 "The term[...] supported property indices [is] used as defined in the WebIDL s
pecification." |
| 55 WebIDL creates actual OwnProperties and then [] just acts as a normal property
lookup */ |
| 56 assert_equals( elem.classList[0], undefined ); |
| 57 }, 'classList[index] must be undefined for out-of-range index'); |
| 58 test(function () { |
| 59 assert_equals( elem.classList[-1], undefined ); |
| 60 }, 'classList[index] must be undefined for negative index'); |
| 61 test(function () { |
| 62 assert_equals( elem.className, ' ' ); |
| 63 }, 'className should contain initial markup whitespace'); |
| 64 test(function () { |
| 65 assert_equals( elem.classList + '', '', 'implicit' ); |
| 66 assert_equals( elem.classList.toString(), '', 'explicit' ); |
| 67 }, 'empty classList should return the empty string since the ordered set parser
skip the whitespaces'); |
| 68 test(function () { |
| 69 assert_throws( 'SYNTAX_ERR', function () { elem.classList.contains(''); } ); |
| 70 }, '.contains(empty_string) must throw a SYNTAX_ERR'); |
| 71 test(function () { |
| 72 assert_throws( 'SYNTAX_ERR', function () { elem.classList.add(''); } ); |
| 73 }, '.add(empty_string) must throw a SYNTAX_ERR'); |
| 74 test(function () { |
| 75 assert_throws( 'SYNTAX_ERR', function () { elem.classList.remove(''); } ); |
| 76 }, '.remove(empty_string) must throw a SYNTAX_ERR'); |
| 77 test(function () { |
| 78 assert_throws( 'SYNTAX_ERR', function () { elem.classList.toggle(''); } ); |
| 79 }, '.toggle(empty_string) must throw a SYNTAX_ERR'); |
| 80 test(function () { |
| 81 assert_throws( 'INVALID_CHARACTER_ERR', function () { elem.classList.contains(
'a b'); } ); |
| 82 }, '.contains(string_with_spaces) must throw an INVALID_CHARACTER_ERR'); |
| 83 test(function () { |
| 84 assert_throws( 'INVALID_CHARACTER_ERR', function () { elem.classList.add('a b'
); } ); |
| 85 }, '.add(string_with_spaces) must throw an INVALID_CHARACTER_ERR'); |
| 86 test(function () { |
| 87 assert_throws( 'INVALID_CHARACTER_ERR', function () { elem.classList.remove('a
b'); } ); |
| 88 }, '.remove(string_with_spaces) must throw an INVALID_CHARACTER_ERR'); |
| 89 test(function () { |
| 90 assert_throws( 'INVALID_CHARACTER_ERR', function () { elem.classList.toggle('a
b'); } ); |
| 91 }, '.toggle(string_with_spaces) must throw an INVALID_CHARACTER_ERR'); |
| 92 elem.className = 'foo'; |
| 93 test(function () { |
| 94 assert_equals( getComputedStyle(elem,null).fontStyle, 'italic', 'critical test
; required by the testsuite' ); |
| 95 }, 'computed style must update when setting .className'); |
| 96 test(function () { |
| 97 assert_true( elem.classList.contains('foo') ); |
| 98 }, 'classList.contains must update when .className is changed'); |
| 99 test(function () { |
| 100 assert_false( elem.classList.contains('FOO') ); |
| 101 }, 'classList.contains must be case sensitive'); |
| 102 test(function () { |
| 103 assert_false( elem.classList.contains('foo.') ); |
| 104 assert_false( elem.classList.contains('foo)') ); |
| 105 assert_false( elem.classList.contains('foo\'') ); |
| 106 assert_false( elem.classList.contains('foo$') ); |
| 107 assert_false( elem.classList.contains('foo~') ); |
| 108 assert_false( elem.classList.contains('foo?') ); |
| 109 assert_false( elem.classList.contains('foo\\') ); |
| 110 }, 'classList.contains must not match when punctuation characters are added'); |
| 111 test(function () { |
| 112 elem.classList.add('FOO'); |
| 113 assert_equals( getComputedStyle(elem,null).fontStyle, 'italic' ); |
| 114 }, 'classList.add must not cause the CSS selector to stop matching'); |
| 115 test(function () { |
| 116 assert_true( elem.classList.contains('foo') ); |
| 117 }, 'classList.add must not remove existing classes'); |
| 118 test(function () { |
| 119 assert_true( elem.classList.contains('FOO') ); |
| 120 }, 'classList.contains case sensitivity must match a case-specific string'); |
| 121 test(function () { |
| 122 assert_equals( elem.classList.length, 2 ); |
| 123 }, 'classList.length must correctly reflect the number of tokens'); |
| 124 test(function () { |
| 125 assert_equals( elem.classList.item(0), 'foo' ); |
| 126 }, 'classList.item(0) must return the first token'); |
| 127 test(function () { |
| 128 assert_equals( elem.classList.item(1), 'FOO' ); |
| 129 }, 'classList.item must return case-sensitive strings and preserve token order')
; |
| 130 test(function () { |
| 131 assert_equals( elem.classList[0], 'foo' ); |
| 132 }, 'classList[0] must return the first token'); |
| 133 test(function () { |
| 134 assert_equals( elem.classList[1], 'FOO' ); |
| 135 }, 'classList[index] must return case-sensitive strings and preserve token order
'); |
| 136 test(function () { |
| 137 /* the normative part of the spec states that: |
| 138 "The object's supported property indices are the numbers in the range zero to
the number of tokens in tokens minus one" |
| 139 ... |
| 140 "The term[...] supported property indices [is] used as defined in the WebIDL s
pecification." |
| 141 WebIDL creates actual OwnProperties and then [] just acts as a normal property
lookup */ |
| 142 assert_equals( elem.classList[2], undefined ); |
| 143 }, 'classList[index] must still be undefined for out-of-range index when earlier
indexes exist'); |
| 144 test(function () { |
| 145 assert_equals( elem.className, 'foo FOO' ); |
| 146 }, 'className must update correctly when items have been added through classList
'); |
| 147 test(function () { |
| 148 assert_equals( elem.classList + '', 'foo FOO', 'implicit' ); |
| 149 assert_equals( elem.classList.toString(), 'foo FOO', 'explicit' ); |
| 150 }, 'classList must stringify correctly when items have been added'); |
| 151 test(function () { |
| 152 elem.classList.add('foo'); |
| 153 assert_equals( elem.classList.length, 2 ); |
| 154 assert_equals( elem.classList + '', 'foo FOO', 'implicit' ); |
| 155 assert_equals( elem.classList.toString(), 'foo FOO', 'explicit' ); |
| 156 }, 'classList.add should not add a token if it already exists'); |
| 157 test(function () { |
| 158 elem.classList.remove('bar'); |
| 159 assert_equals( elem.classList.length, 2 ); |
| 160 assert_equals( elem.classList + '', 'foo FOO', 'implicit' ); |
| 161 assert_equals( elem.classList.toString(), 'foo FOO', 'explicit' ); |
| 162 }, 'classList.remove removes arguments passed, if they are present.'); |
| 163 test(function () { |
| 164 elem.classList.remove('foo'); |
| 165 assert_equals( elem.classList.length, 1 ); |
| 166 assert_equals( elem.classList + '', 'FOO', 'implicit' ); |
| 167 assert_equals( elem.classList.toString(), 'FOO', 'explicit' ); |
| 168 assert_false( elem.classList.contains('foo') ); |
| 169 assert_true( elem.classList.contains('FOO') ); |
| 170 }, 'classList.remove must remove existing tokens'); |
| 171 test(function () { |
| 172 assert_not_equals( getComputedStyle(elem,null).fontStyle, 'italic' ); |
| 173 }, 'classList.remove must not break case-sensitive CSS selector matching'); |
| 174 test(function () { |
| 175 secondelem.classList.remove('test'); |
| 176 assert_equals( secondelem.classList.length, 0 ); |
| 177 assert_false( secondelem.classList.contains('test') ); |
| 178 }, 'classList.remove must remove duplicated tokens'); |
| 179 test(function () { |
| 180 secondelem.className = 'token1 token2 token3'; |
| 181 secondelem.classList.remove('token2'); |
| 182 assert_equals( secondelem.classList + '', 'token1 token3', 'implicit' ); |
| 183 assert_equals( secondelem.classList.toString(), 'token1 token3', 'explicit' ); |
| 184 }, 'classList.remove must collapse whitespace around removed tokens'); |
| 185 test(function () { |
| 186 secondelem.className = ' token1 token2 '; |
| 187 secondelem.classList.remove('token2'); |
| 188 assert_equals( secondelem.classList + '', 'token1', 'implicit' ); |
| 189 assert_equals( secondelem.classList.toString(), 'token1', 'explicit' ); |
| 190 }, 'classList.remove must collapse whitespaces around each token'); |
| 191 test(function () { |
| 192 secondelem.className = ' token1 token2 token1 '; |
| 193 secondelem.classList.remove('token2'); |
| 194 assert_equals( secondelem.classList + '', 'token1', 'implicit' ); |
| 195 assert_equals( secondelem.classList.toString(), 'token1', 'explicit' ); |
| 196 }, 'classList.remove must collapse whitespaces around each token and remove dupl
icates'); |
| 197 test(function () { |
| 198 secondelem.className = ' token1 token2 token1 '; |
| 199 secondelem.classList.remove('token1'); |
| 200 assert_equals( secondelem.classList + '', 'token2', 'implicit' ); |
| 201 assert_equals( secondelem.classList.toString(), 'token2', 'explicit' ); |
| 202 }, 'classList.remove must collapse whitespace when removing duplicate tokens'); |
| 203 test(function () { |
| 204 secondelem.className = ' token1 token1 '; |
| 205 secondelem.classList.add('token1'); |
| 206 assert_equals( secondelem.classList + '', 'token1', 'implicit' ); |
| 207 assert_equals( secondelem.classList.toString(), 'token1', 'explicit' ); |
| 208 }, 'classList.add must collapse whitespaces and remove duplicates when adding a
token that already exists'); |
| 209 test(function () { |
| 210 assert_true(elem.classList.toggle('foo')); |
| 211 assert_equals( elem.classList.length, 2 ); |
| 212 assert_true( elem.classList.contains('foo') ); |
| 213 assert_true( elem.classList.contains('FOO') ); |
| 214 }, 'classList.toggle must toggle tokens case-sensitively when adding'); |
| 215 test(function () { |
| 216 assert_equals( getComputedStyle(elem,null).fontStyle, 'italic' ); |
| 217 }, 'classList.toggle must not break case-sensitive CSS selector matching'); |
| 218 test(function () { |
| 219 assert_false(elem.classList.toggle('foo')); |
| 220 }, 'classList.toggle must be able to remove tokens'); |
| 221 test(function () { |
| 222 //will return true if the last test incorrectly removed both |
| 223 assert_false(elem.classList.toggle('FOO')); |
| 224 assert_false( elem.classList.contains('foo') ); |
| 225 assert_false( elem.classList.contains('FOO') ); |
| 226 }, 'classList.toggle must be case-sensitive when removing tokens'); |
| 227 test(function () { |
| 228 assert_not_equals( getComputedStyle(elem,null).fontStyle, 'italic' ); |
| 229 }, 'CSS class selectors must stop matching when all classes have been removed'); |
| 230 test(function () { |
| 231 assert_equals( elem.className, '' ); |
| 232 }, 'className must be empty when all classes have been removed'); |
| 233 test(function () { |
| 234 assert_equals( elem.classList + '', '', 'implicit' ); |
| 235 assert_equals( elem.classList.toString(), '', 'explicit' ); |
| 236 }, 'classList must stringify to an empty string when all classes have been remov
ed'); |
| 237 test(function () { |
| 238 assert_equals( elem.classList.item(0), null ); |
| 239 }, 'classList.item(0) must return null when all classes have been removed'); |
| 240 test(function () { |
| 241 /* the normative part of the spec states that: |
| 242 "unless the length is zero, in which case there are no supported property indi
ces" |
| 243 ... |
| 244 "The term[...] supported property indices [is] used as defined in the WebIDL s
pecification." |
| 245 WebIDL creates actual OwnProperties and then [] just acts as a normal property
lookup */ |
| 246 assert_equals( elem.classList[0], undefined ); |
| 247 }, 'classList[0] must be undefined when all classes have been removed'); |
| 248 // The ordered set parser must skip ASCII whitespace (U+0009, U+000A, U+000C, U+
000D, and U+0020.) |
| 249 test(function () { |
| 250 var foo = document.createElement('div'); |
| 251 foo.className = 'a '; |
| 252 foo.classList.add('b'); |
| 253 assert_equals(foo.className,'a b'); |
| 254 }, 'classList.add should treat " " as a space'); |
| 255 test(function () { |
| 256 var foo = document.createElement('div'); |
| 257 foo.className = 'a\t'; |
| 258 foo.classList.add('b'); |
| 259 assert_equals(foo.className,'a b'); |
| 260 }, 'classList.add should treat \\t as a space'); |
| 261 test(function () { |
| 262 var foo = document.createElement('div'); |
| 263 foo.className = 'a\r'; |
| 264 foo.classList.add('b'); |
| 265 assert_equals(foo.className,'a b'); |
| 266 }, 'classList.add should treat \\r as a space'); |
| 267 test(function () { |
| 268 var foo = document.createElement('div'); |
| 269 foo.className = 'a\n'; |
| 270 foo.classList.add('b'); |
| 271 assert_equals(foo.className,'a b'); |
| 272 }, 'classList.add should treat \\n as a space'); |
| 273 test(function () { |
| 274 var foo = document.createElement('div'); |
| 275 foo.className = 'a\f'; |
| 276 foo.classList.add('b'); |
| 277 assert_equals(foo.className,'a b'); |
| 278 }, 'classList.add should treat \\f as a space'); |
| 279 test(function () { |
| 280 //WebIDL and ECMAScript 5 - a readonly property has a getter but not a setter |
| 281 //ES5 makes [[Put]] fail but not throw |
| 282 var failed = false; |
| 283 secondelem.className = 'token1'; |
| 284 try { |
| 285 secondelem.classList.length = 0; |
| 286 } catch(e) { |
| 287 failed = e; |
| 288 } |
| 289 assert_equals(secondelem.classList.length,1); |
| 290 assert_false(failed,'an error was thrown'); |
| 291 }, 'classList.length must be read-only'); |
| 292 test(function () { |
| 293 var failed = false, realList = secondelem.classList; |
| 294 try { |
| 295 secondelem.classList = ''; |
| 296 } catch(e) { |
| 297 failed = e; |
| 298 } |
| 299 assert_equals(secondelem.classList,realList); |
| 300 assert_false(failed,'an error was thrown'); |
| 301 }, 'classList must be read-only'); |
| 302 </script> |
| 303 </head> |
| 304 <body> |
| 305 |
| 306 <div id="log"></div> |
| 307 |
| 308 </body> |
| 309 </html> |
OLD | NEW |