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