View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host.dom;
16  
17  import org.htmlunit.WebDriverTestCase;
18  import org.htmlunit.junit.annotation.Alerts;
19  import org.htmlunit.junit.annotation.HtmlUnitNYI;
20  import org.junit.jupiter.api.Test;
21  
22  /**
23   * Tests for {@link DOMTokenList}.
24   *
25   * @author Ahmed Ashour
26   * @author Ronald Brill
27   * @author Frank Danek
28   * @author Marek Gawlicki
29   * @author Markus Winter
30   */
31  public class DOMTokenListTest extends WebDriverTestCase {
32  
33      /**
34       * @throws Exception if the test fails
35       */
36      @Test
37      @Alerts({"3", "b", "b", "true", "false", "c d", "<body onload=\"test()\" class=\"c d\"> </body>"})
38      public void various() throws Exception {
39          final String html = DOCTYPE_HTML
40              + "<html><head><script>\n"
41              + LOG_TITLE_FUNCTION
42              + "function test() {\n"
43              + "  var list = document.body.classList;\n"
44              + "  log(list.length);\n"
45              + "  log(list.item(1));\n"
46              + "  log(list[1]);\n"
47              + "  log(list.contains('c'));\n"
48  
49              + "  list.add('d');\n"
50              + "  list.remove('a');\n"
51              + "  log(list.toggle('b'));\n"
52  
53              + "  log(list);\n"
54              + "  log(document.body.outerHTML);\n"
55              + "}\n"
56              + "</script></head>\n"
57              + "<body onload='test()' class='a b c'>\n"
58              + "</body></html>";
59  
60          loadPageVerifyTitle2(html);
61      }
62  
63      /**
64       * @throws Exception if the test fails
65       */
66      @Test
67      @Alerts({"0", "null", "false", "# removed", "", "<body onload=\"test()\"> </body>"})
68      public void noAttribute() throws Exception {
69          final String html = DOCTYPE_HTML
70              + "<html><head><script>\n"
71              + LOG_TITLE_FUNCTION
72              + "function test() {\n"
73              + "  var list = document.body.classList;\n"
74              + "  log(list.length);\n"
75              + "  log(list.item(0));\n"
76              + "  log(list.contains('#'));\n"
77              + "  list.remove('#');"
78              + "  log('# removed');\n"
79              + "  log(document.body.className);\n"
80              + "  log(document.body.outerHTML);\n"
81              + "}\n"
82              + "</script></head>\n"
83              + "<body onload='test()'>\n"
84              + "</body></html>";
85  
86          loadPageVerifyTitle2(html);
87      }
88  
89      /**
90       * @throws Exception if the test fails
91       */
92      @Test
93      @Alerts({"0", "undefined", "1", "#", "<body onload=\"test()\" class=\"#\"> </body>"})
94      public void noAttributeAdd() throws Exception {
95          final String html = DOCTYPE_HTML
96              + "<html><head><script>\n"
97              + LOG_TITLE_FUNCTION
98              + "function test() {\n"
99              + "  var list = document.body.classList;\n"
100             + "  log(list.length);\n"
101             + "  log(list.add('#'));\n"
102             + "  log(list.length);\n"
103             + "  log(document.body.className);\n"
104             + "  log(document.body.outerHTML);\n"
105             + "}\n"
106             + "</script></head><body onload='test()'>\n"
107             + "</body></html>";
108 
109         loadPageVerifyTitle2(html);
110     }
111 
112     /**
113      * @throws Exception if the test fails
114      */
115     @Test
116     @Alerts({"0", "true", "1", "#"})
117     public void noAttributeToggle() throws Exception {
118         final String html = DOCTYPE_HTML
119             + "<html><head><script>\n"
120             + LOG_TITLE_FUNCTION
121             + "function test() {\n"
122             + "  var list = document.body.classList;\n"
123             + "  log(list.length);\n"
124             + "  log(list.toggle('#'));\n"
125             + "  log(list.length);\n"
126             + "  log(document.body.className);\n"
127             + "}\n"
128             + "</script></head><body onload='test()'>\n"
129             + "</body></html>";
130 
131         loadPageVerifyTitle2(html);
132     }
133 
134     /**
135      * @throws Exception if the test fails
136      */
137     @Test
138     @Alerts({"3", "0", "2", "8"})
139     public void length() throws Exception {
140         final String html = DOCTYPE_HTML
141             + "<html><head><script>\n"
142             + LOG_TITLE_FUNCTION
143             + "function test() {\n"
144             + "  var list = document.getElementById('d1').classList;\n"
145             + "  log(list.length);\n"
146             + "  list = document.getElementById('d2').classList;\n"
147             + "  log(list.length);\n"
148             + "  list = document.getElementById('d3').classList;\n"
149             + "  log(list.length);\n"
150             + "  list = document.getElementById('d4').classList;\n"
151             + "  log(list.length);\n"
152             + "}\n"
153             + "</script></head><body onload='test()'>\n"
154             + "  <div id='d1' class=' a b c '></div>\n"
155             + "  <div id='d2' class=''></div>\n"
156             + "  <div id='d3' class=' a b a'></div>\n"
157             + "  <div id='d4' class=' a b \t c \n d \u000B e \u000C f \r g'></div>\n"
158             + "</body></html>";
159 
160         loadPageVerifyTitle2(html);
161     }
162 
163     /**
164      * @throws Exception if the test fails
165      */
166     @Test
167     @Alerts({"a", "b", "c", "d", "\u000B", "e", "f", "g", "null", "null", "null"})
168     public void item() throws Exception {
169         final String html = DOCTYPE_HTML
170             + "<html><head><script>\n"
171             + LOG_TITLE_FUNCTION
172             + "function test() {\n"
173             + "  var list = document.getElementById('d1').classList;\n"
174             + "  for (var i = 0; i < list.length; i++) {\n"
175             + "    log(list.item(i));\n"
176             + "  }\n"
177             + "  log(list.item(-1));\n"
178             + "  log(list.item(list.length));\n"
179             + "  log(list.item(100));\n"
180             + "}\n"
181             + "</script></head><body onload='test()'>\n"
182             + "  <div id='d1' class=' a b \t c \n d \u000B e \u000C f \r g'></div>\n"
183             + "</body></html>";
184 
185         loadPageVerifyTitle2(html);
186     }
187 
188     /**
189      * @throws Exception if the test fails
190      */
191     @Test
192     @Alerts({"a", "b", "c", "d", "\u000B", "e", "f", "g"})
193     public void forEach() throws Exception {
194         final String html = DOCTYPE_HTML
195                 + "<html><head><script>\n"
196                 + LOG_TITLE_FUNCTION
197                 + "function test() {\n"
198                 + "  var list = document.getElementById('d1').classList;\n"
199                 + "  list.forEach((i) => {\n"
200                 + "    log(i);\n"
201                 + "  });\n"
202                 + "}\n"
203                 + "</script></head><body onload='test()'>\n"
204                 + "  <div id='d1' class=' a b \t c \n d \u000B e \u000C f \r g'></div>\n"
205                 + "</body></html>";
206 
207         loadPageVerifyTitle2(html);
208     }
209 
210     /**
211      * @throws Exception if the test fails
212      */
213     @Test
214     @Alerts({"4", "a", "b", "c", "d",
215              "7", "a", "b", "c", "d", "new-a", "new-b", "new-c"})
216     public void forEachAdd() throws Exception {
217         final String html = DOCTYPE_HTML
218                 + "<html><head><script>\n"
219                 + LOG_TITLE_FUNCTION
220                 + "function test() {\n"
221                 + "  var list = document.getElementById('d1').classList;\n"
222                 + "  log(list.length);\n"
223 
224                 + "  list.forEach((i) => {\n"
225                 + "    log(i);\n"
226                 + "    if (list.length < 7) { list.add('new-' + i); }\n"
227                 + "  });\n"
228 
229                 + "  log(list.length);\n"
230                 + "  list.forEach((i) => {\n"
231                 + "    log(i);\n"
232                 + "  });\n"
233                 + "}\n"
234                 + "</script></head><body onload='test()'>\n"
235                 + "  <div id='d1' class='a b c d'></div>\n"
236                 + "</body></html>";
237 
238         loadPageVerifyTitle2(html);
239     }
240 
241     /**
242      * @throws Exception if the test fails
243      */
244     @Test
245     @Alerts({"4", "a", "c", "d", "3"})
246     public void forEachRemove() throws Exception {
247         final String html = DOCTYPE_HTML
248                 + "<html><head><script>\n"
249                 + LOG_TITLE_FUNCTION
250                 + "function test() {\n"
251                 + "  var list = document.getElementById('d1').classList;\n"
252                 + "  log(list.length);\n"
253 
254                 + "  list.forEach((i) => {\n"
255                 + "    log(i);\n"
256                 + "    list.remove('a');\n"
257                 + "  });\n"
258 
259                 + "  log(list.length);\n"
260                 + "}\n"
261                 + "</script></head><body onload='test()'>\n"
262                 + "  <div id='d1' class='a b c d'></div>\n"
263                 + "</body></html>";
264 
265         loadPageVerifyTitle2(html);
266     }
267 
268 
269     /**
270      * @throws Exception if the test fails
271      */
272     @Test
273     @Alerts({"4", "a", "1"})
274     public void forEachRemove2() throws Exception {
275         final String html = DOCTYPE_HTML
276                 + "<html><head><script>\n"
277                 + LOG_TITLE_FUNCTION
278                 + "function test() {\n"
279                 + "  var list = document.getElementById('d1').classList;\n"
280                 + "  log(list.length);\n"
281 
282                 + "  list.forEach((i) => {\n"
283                 + "    log(i);\n"
284                 + "    list.remove('a');\n"
285                 + "    list.remove('c');\n"
286                 + "    list.remove('d');\n"
287                 + "  });\n"
288 
289                 + "  log(list.length);\n"
290                 + "}\n"
291                 + "</script></head><body onload='test()'>\n"
292                 + "  <div id='d1' class='a b c d'></div>\n"
293                 + "</body></html>";
294 
295         loadPageVerifyTitle2(html);
296     }
297 
298     /**
299      * @throws Exception if the test fails
300      */
301     @Test
302     @Alerts({"a", "b", "c"})
303     public void forEachDuplicates() throws Exception {
304         final String html = DOCTYPE_HTML
305                 + "<html><head><script>\n"
306                 + LOG_TITLE_FUNCTION
307                 + "function test() {\n"
308                 + "  var list = document.getElementById('d1').classList;\n"
309                 + "  list.forEach((i) => {\n"
310                 + "    log(i);\n"
311                 + "  });\n"
312                 + "}\n"
313                 + "</script></head><body onload='test()'>\n"
314                 + "  <div id='d1' class=' a b a c'></div>\n"
315                 + "</body></html>";
316 
317         loadPageVerifyTitle2(html);
318     }
319 
320     /**
321      * @throws Exception if the test fails
322      */
323     @Test
324     @Alerts({"a#0#true", "b#1#true"})
325     public void forEachAllParams() throws Exception {
326         final String html = DOCTYPE_HTML
327                 + "<html><head><script>\n"
328                 + LOG_TITLE_FUNCTION
329                 + "function test() {\n"
330                 + "  var list = document.getElementById('d1').classList;\n"
331                 + "  list.forEach((val, idx, listObj) => {\n"
332                 + "    log(val + '#' + idx + '#' + (listObj === list));\n"
333                 + "  });\n"
334                 + "}\n"
335                 + "</script></head><body onload='test()'>\n"
336                 + "  <div id='d1' class=' a b  '></div>\n"
337                 + "</body></html>";
338 
339         loadPageVerifyTitle2(html);
340     }
341 
342     /**
343      * @throws Exception if the test fails
344      */
345     @Test
346     @Alerts({"TypeError", "TypeError"})
347     public void forEachWrongParam() throws Exception {
348         final String html = DOCTYPE_HTML
349                 + "<html><head><script>\n"
350                 + LOG_TITLE_FUNCTION
351                 + "function test() {\n"
352                 + "  var list = document.getElementById('d1').classList;\n"
353                 + "  try {\n"
354                 + "    list.forEach();\n"
355                 + "  } catch(e) { logEx(e); }\n"
356                 + "  try {\n"
357                 + "    list.forEach('wrong');\n"
358                 + "  } catch(e) { logEx(e); }\n"
359                 + "}\n"
360                 + "</script></head><body onload='test()'>\n"
361                 + "  <div id='d1' class=' a b \t c \n d \u000B e \u000C f \r g'></div>\n"
362                 + "</body></html>";
363 
364         loadPageVerifyTitle2(html);
365     }
366 
367     /**
368      * @throws Exception if an error occurs
369      */
370     @Test
371     @Alerts({"value", "done", "object", "0", "a"})
372     public void entries() throws Exception {
373         final String html = DOCTYPE_HTML
374             + "<html><head>\n"
375             + "<script>\n"
376             + LOG_TITLE_FUNCTION
377             + "  function test() {\n"
378             + "    var list = document.getElementById('d1').classList;\n"
379             + "    if (!list.entries) {\n"
380             + "      log('not defined');\n"
381             + "      return;\n"
382             + "    }\n"
383             + "    var i = list.entries().next();\n"
384             + "    for (var x in i) {\n"
385             + "      log(x);\n"
386             + "    }\n"
387             + "    var v = i.value;\n"
388             + "    log(typeof v);\n"
389             + "    log(v[0]);\n"
390             + "    log(v[1]);\n"
391             + "  }\n"
392             + "</script>\n"
393             + "</head><body onload='test()'>\n"
394             + "  <div id='d1' class=' a x'></div>\n"
395             + "</body></html>\n";
396 
397         loadPageVerifyTitle2(html);
398     }
399 
400     /**
401      * @throws Exception if an error occurs
402      */
403     @Test
404     @Alerts({"true", "undefined", "function", "undefined", "undefined", "true", "true", "true"})
405     public void entriesPropertyDescriptor() throws Exception {
406         final String html = DOCTYPE_HTML
407             + "<html><head>\n"
408             + "<script>\n"
409             + LOG_TITLE_FUNCTION
410             + "  function test() {\n"
411             + "    var list = document.getElementById('d1').classList;\n"
412 
413             + "    log('entries' in list);\n"
414             + "    log(Object.getOwnPropertyDescriptor(list, 'entries'));\n"
415 
416             + "    var desc = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(list), 'entries');\n"
417             + "    if (desc === undefined) { log('no entries'); return; }\n"
418             + "    log(typeof desc.value);\n"
419             + "    log(desc.get);\n"
420             + "    log(desc.set);\n"
421             + "    log(desc.writable);\n"
422             + "    log(desc.enumerable);\n"
423             + "    log(desc.configurable);\n"
424             + "  }\n"
425             + "</script>\n"
426             + "</head><body onload='test()'>\n"
427             + "  <div id='d1' class=' a x'></div>\n"
428             + "</body></html>\n";
429 
430         loadPageVerifyTitle2(html);
431     }
432 
433     /**
434      * @throws Exception if an error occurs
435      */
436     @Test
437     @Alerts({"0,a", "1,x"})
438     public void entriesForOf() throws Exception {
439         final String html = DOCTYPE_HTML
440             + "<html><head>\n"
441             + "<script>\n"
442             + LOG_TITLE_FUNCTION
443             + "  function test() {\n"
444             + "    var list = document.getElementById('d1').classList;\n"
445             + "    if (!list.entries) {\n"
446             + "      log('not defined');\n"
447             + "      return;\n"
448             + "    }\n"
449             + "    for (var i of list.entries()) {\n"
450             + "      log(i);\n"
451             + "    }\n"
452             + "  }\n"
453             + "</script>\n"
454             + "</head><body onload='test()'>\n"
455             + "  <div id='d1' class=' a x'></div>\n"
456             + "</body></html>\n";
457 
458         loadPageVerifyTitle2(html);
459     }
460 
461     /**
462      * @throws Exception on test failure
463      */
464     @Test
465     @Alerts("0,1,2,add,contains,entries,forEach,item,keys,length,remove,replace,supports,toggle,toString,value,values")
466     @HtmlUnitNYI(CHROME = "0,1,2,add,contains,entries,forEach,item,keys,length,remove,replace,toggle,value,values",
467             EDGE = "0,1,2,add,contains,entries,forEach,item,keys,length,remove,replace,toggle,value,values",
468             FF = "0,1,2,add,contains,entries,forEach,item,keys,length,remove,replace,toggle,value,values",
469             FF_ESR = "0,1,2,add,contains,entries,forEach,item,keys,length,remove,replace,toggle,value,values")
470     public void forIn() throws Exception {
471         final String html = DOCTYPE_HTML
472                 + "<html><head>\n"
473                 + "<script>\n"
474                 + LOG_TITLE_FUNCTION
475                 + "  function test() {\n"
476                 + "    var all = [];\n"
477                 + "    for (var i in document.getElementById('d1').classList) {\n"
478                 + "      all.push(i);\n"
479                 + "    }\n"
480                 + "    all.sort(sortFunction);\n"
481                 + "    log(all);\n"
482                 + "  }\n"
483                 + "  function sortFunction(s1, s2) {\n"
484                 + "    return s1.toLowerCase() > s2.toLowerCase() ? 1 : -1;\n"
485                 + "  }\n"
486                 + "</script>\n"
487                 + "</head><body onload='test()'>\n"
488                 + "  <div id='d1' class=' a b g'></div>\n"
489                 + "</body></html>";
490 
491         loadPageVerifyTitle2(html);
492     }
493 
494     /**
495      * @throws Exception on test failure
496      */
497     @Test
498     @Alerts("add,contains,entries,forEach,item,keys,length,remove,replace,supports,toggle,toString,value,values")
499     @HtmlUnitNYI(CHROME = "add,contains,entries,forEach,item,keys,length,remove,replace,toggle,value,values",
500             EDGE = "add,contains,entries,forEach,item,keys,length,remove,replace,toggle,value,values",
501             FF = "add,contains,entries,forEach,item,keys,length,remove,replace,toggle,value,values",
502             FF_ESR = "add,contains,entries,forEach,item,keys,length,remove,replace,toggle,value,values")
503     public void forInEmptyList() throws Exception {
504         final String html = DOCTYPE_HTML
505                 + "<html><head>\n"
506                 + "<script>\n"
507                 + LOG_TITLE_FUNCTION
508                 + "  function test() {\n"
509                 + "    var all = [];\n"
510                 + "    for (var i in document.getElementById('d1').classList) {\n"
511                 + "      all.push(i);\n"
512                 + "    }\n"
513                 + "    all.sort(sortFunction);\n"
514                 + "    log(all);\n"
515                 + "  }\n"
516                 + "  function sortFunction(s1, s2) {\n"
517                 + "    return s1.toLowerCase() > s2.toLowerCase() ? 1 : -1;\n"
518                 + "  }\n"
519                 + "</script>\n"
520                 + "</head><body onload='test()'>\n"
521                 + "  <div id='d1'></div>\n"
522                 + "</body></html>";
523 
524         loadPageVerifyTitle2(html);
525     }
526 
527     /**
528      * @throws Exception on test failure
529      */
530     @Test
531     @Alerts({"true", "a", "b", "g"})
532     public void iterator() throws Exception {
533         final String html = DOCTYPE_HTML
534                 + "<html><head>\n"
535                 + "<script>\n"
536                 + LOG_TITLE_FUNCTION
537                 + "  function test() {\n"
538                 + "    var list = document.getElementById('d1').classList;\n"
539 
540                 + "    if (typeof Symbol != 'undefined') {\n"
541                 + "      log(list[Symbol.iterator] === list.values);\n"
542                 + "    }\n"
543 
544                 + "    if (!list.forEach) {\n"
545                 + "      log('no for..of');\n"
546                 + "      return;\n"
547                 + "    }\n"
548 
549                 + "    for (var i of list) {\n"
550                 + "      log(i);\n"
551                 + "    }\n"
552                 + "  }\n"
553                 + "</script>\n"
554                 + "</head><body onload='test()'>\n"
555                 + "  <div id='d1' class=' a b g'></div>\n"
556                 + "</body></html>";
557 
558         loadPageVerifyTitle2(html);
559     }
560 
561     /**
562      * @throws Exception if the test fails
563      */
564     @Test
565     @Alerts({"a b", "2", "null", "undefined"})
566     public void itemNegative() throws Exception {
567         item("a b", -1);
568     }
569 
570     /**
571      * @throws Exception if the test fails
572      */
573     @Test
574     @Alerts({"a b", "2", "null", "undefined"})
575     public void itemNegative2() throws Exception {
576         item("a b", -123);
577     }
578 
579     /**
580      * @throws Exception if the test fails
581      */
582     @Test
583     @Alerts({"a b", "2", "a", "a"})
584     public void itemFirst() throws Exception {
585         item("a b", 0);
586     }
587 
588     /**
589      * @throws Exception if the test fails
590      */
591     @Test
592     @Alerts({"a b", "2", "b", "b"})
593     public void itemLast() throws Exception {
594         item("a b", 1);
595     }
596 
597     /**
598      * @throws Exception if the test fails
599      */
600     @Test
601     @Alerts({"a b", "2", "null", "undefined"})
602     public void itemOutside() throws Exception {
603         item("a b", 13);
604     }
605 
606     private void item(final String in, final int pos) throws Exception {
607         final String html = DOCTYPE_HTML
608             + "<html><head>\n"
609             + "<script>\n"
610             + LOG_TITLE_FUNCTION
611             + "  function test() {\n"
612             + "    var elem = document.getElementById('d1');\n"
613 
614             + "    var config = { attributes: true, attributeOldValue: true };\n"
615             + "    var observer = new MutationObserver(function(mutations) {\n"
616             + "      mutations.forEach(function(mutation) {\n"
617             + "        log(mutation.attributeName + ' changed old: ' + mutation.oldValue);\n"
618             + "      });\n"
619             + "    });\n"
620             + "    observer.observe(elem, config);"
621 
622             + "    var list = elem.classList;\n"
623             + "    if (!list) { log('no list'); return; }\n"
624 
625             + "    log(elem.className);\n"
626             + "    log(list.length);\n"
627             + "    try {\n"
628             + "      log(list.item(" + pos + "));\n"
629             + "      log(list[" + pos + "]);\n"
630             + "    } catch(e) { logEx(e);}\n"
631             + "  }\n"
632             + "</script></head><body onload='test()'>\n"
633             + "  <div id='d1' class='" + in + "'></div>\n"
634             + "</body></html>";
635 
636         loadPageVerifyTitle2(html);
637     }
638 
639     /**
640      * @throws Exception if the test fails
641      */
642     @Test
643     @Alerts({"a\\sb", "2", "false"})
644     public void containsEmpty() throws Exception {
645         contains("a b", "");
646     }
647 
648     /**
649      * @throws Exception if the test fails
650      */
651     @Test
652     @Alerts({"a\\sb", "2", "false"})
653     public void containsBlank() throws Exception {
654         contains("a b", " ");
655     }
656 
657     /**
658      * @throws Exception if the test fails
659      */
660     @Test
661     @Alerts({"a\\sb", "2", "false"})
662     public void containsTab() throws Exception {
663         contains("a b", "\t");
664     }
665 
666     /**
667      * @throws Exception if the test fails
668      */
669     @Test
670     @Alerts({"a\\sb", "2", "false"})
671     public void containsCr() throws Exception {
672         contains("a b", "\\r");
673     }
674 
675     /**
676      * @throws Exception if the test fails
677      */
678     @Test
679     @Alerts({"a\\sb", "2", "false"})
680     public void containsNl() throws Exception {
681         contains("a b", "\\n");
682     }
683 
684     /**
685      * @throws Exception if the test fails
686      */
687     @Test
688     @Alerts({"a\\sb", "2", "false"})
689     public void containsVt() throws Exception {
690         contains("a b", "\u000B");
691     }
692 
693     /**
694      * @throws Exception if the test fails
695      */
696     @Test
697     @Alerts({"", "0", "false"})
698     public void containsInsideEmpty() throws Exception {
699         contains("", "a");
700     }
701 
702     /**
703      * @throws Exception if the test fails
704      */
705     @Test
706     @Alerts({"\\s\\t\\s\\n\\s\\s", "0", "false"})
707     public void containsInsideWhitespace() throws Exception {
708         contains(" \t \r  ", "a");
709     }
710 
711     /**
712      * @throws Exception if the test fails
713      */
714     @Test
715     @Alerts({"a\\sb", "2", "true"})
716     public void containsInsideAtStart() throws Exception {
717         contains("a b", "a");
718     }
719 
720     /**
721      * @throws Exception if the test fails
722      */
723     @Test
724     @Alerts({"a\\sb", "2", "true"})
725     public void containsInsideAtEnd() throws Exception {
726         contains("a b", "b");
727     }
728 
729     /**
730      * @throws Exception if the test fails
731      */
732     @Test
733     @Alerts({"abc\\sdef", "2", "false"})
734     public void containsInsideSubstringAtStart() throws Exception {
735         contains("abc def", "ab");
736     }
737 
738     /**
739      * @throws Exception if the test fails
740      */
741     @Test
742     @Alerts({"abc\\sdef", "2", "false"})
743     public void containsInsideSubstringAtEnd() throws Exception {
744         contains("abc def", "bc");
745     }
746 
747     /**
748      * @throws Exception if the test fails
749      */
750     @Test
751     @Alerts({"abcd\\sef", "2", "false"})
752     public void containsInsideSubstringInside() throws Exception {
753         contains("abcd ef", "bc");
754     }
755 
756     /**
757      * @throws Exception if the test fails
758      */
759     @Test
760     @Alerts({"a\\s\\s", "1", "true"})
761     public void containsInsideWhitespaceAtEnd() throws Exception {
762         contains("a  ", "a");
763     }
764 
765     /**
766      * @throws Exception if the test fails
767      */
768     @Test
769     @Alerts({"\\s\\sa", "1", "true"})
770     public void containsInsideWhitespaceInFront() throws Exception {
771         contains("  a", "a");
772     }
773 
774     /**
775      * @throws Exception if the test fails
776      */
777     @Test
778     @Alerts({"a\\s\\t\\sc\\s\\n\\sd\\s\\se", "4", "true"})
779     public void containsWhitespaceExisting() throws Exception {
780         contains("a \t c \n d  e", "c");
781     }
782 
783     private void contains(final String in, final String toAdd) throws Exception {
784         final String html = DOCTYPE_HTML
785             + "<html><head>\n"
786             + "<script>\n"
787             + LOG_TITLE_FUNCTION_NORMALIZE
788             + "  function test() {\n"
789             + "    var elem = document.getElementById('d1');\n"
790 
791             + "    var config = { attributes: true, attributeOldValue: true };\n"
792             + "    var observer = new MutationObserver(function(mutations) {\n"
793             + "      mutations.forEach(function(mutation) {\n"
794             + "        log(mutation.attributeName + ' changed old: ' + mutation.oldValue);\n"
795             + "      });\n"
796             + "    });\n"
797             + "    observer.observe(elem, config);"
798 
799             + "    var list = elem.classList;\n"
800             + "    if (!list) { log('no list'); return; }\n"
801 
802             + "    log(elem.className);\n"
803             + "    log(list.length);\n"
804             + "    try {\n"
805             + "      log(list.contains('" + toAdd + "'));\n"
806             + "    } catch(e) { logEx(e);}\n"
807             + "  }\n"
808             + "</script></head><body onload='test()'>\n"
809             + "  <div id='d1' class='" + in + "'></div>\n"
810             + "</body></html>";
811 
812         loadPageVerifyTitle2(html);
813     }
814 
815     /**
816      * @throws Exception if the test fails
817      */
818     @Test
819     @Alerts({"a\\sb", "2", "SyntaxError/DOMException", "2", "a\\sb"})
820     public void addEmpty() throws Exception {
821         add("a b", "''");
822     }
823 
824     /**
825      * @throws Exception if the test fails
826      */
827     @Test
828     @Alerts({"a\\sb", "2", "InvalidCharacterError/DOMException", "2", "a\\sb"})
829     public void addBlank() throws Exception {
830         add("a b", "' '");
831     }
832 
833     /**
834      * @throws Exception if the test fails
835      */
836     @Test
837     @Alerts({"a\\sb", "2", "InvalidCharacterError/DOMException", "2", "a\\sb"})
838     public void addTab() throws Exception {
839         add("a b", "'\t'");
840     }
841 
842     /**
843      * @throws Exception if the test fails
844      */
845     @Test
846     @Alerts({"a\\sb", "2", "InvalidCharacterError/DOMException", "2", "a\\sb"})
847     public void addCr() throws Exception {
848         add("a b", "'\\r'");
849     }
850 
851     /**
852      * @throws Exception if the test fails
853      */
854     @Test
855     @Alerts({"a\\sb", "2", "InvalidCharacterError/DOMException", "2", "a\\sb"})
856     public void addNl() throws Exception {
857         add("a b", "'\\n'");
858     }
859 
860     /**
861      * @throws Exception if the test fails
862      */
863     @Test
864     @Alerts({"a\\sb", "2", "3", "a\\sb\\s\u000B", "class\\schanged\\sold:\\sa\\sb"})
865     public void addVt() throws Exception {
866         add("a b", "'\u000B'");
867     }
868 
869     /**
870      * @throws Exception if the test fails
871      */
872     @Test
873     @Alerts({"", "0", "1", "a", "class\\schanged\\sold:\\s"})
874     public void addToEmpty() throws Exception {
875         add("", "'a'");
876     }
877 
878     /**
879      * @throws Exception if the test fails
880      */
881     @Test
882     @Alerts({"\\s\\t\\s\\n\\s\\s", "0", "1", "a", "class\\schanged\\sold:\\s\\s\\t\\s\\n\\s\\s"})
883     public void addToWhitespace() throws Exception {
884         add(" \t \r  ", "'a'");
885     }
886 
887     /**
888      * @throws Exception if the test fails
889      */
890     @Test
891     @Alerts({"a\\s\\s", "1", "2", "a\\sb", "class\\schanged\\sold:\\sa\\s\\s"})
892     public void addToWhitespaceAtEnd() throws Exception {
893         add("a  ", "'b'");
894     }
895 
896     /**
897      * @throws Exception if the test fails
898      */
899     @Test
900     @Alerts({"a\\sb", "2", "3", "a\\sb\\sc", "class\\schanged\\sold:\\sa\\sb"})
901     public void addNotExisting() throws Exception {
902         add("a b", "'c'");
903     }
904 
905     /**
906      * @throws Exception if the test fails
907      */
908     @Test
909     @Alerts({"a\\sb", "2", "2", "a\\sb", "class\\schanged\\sold:\\sa\\sb"})
910     public void addExisting() throws Exception {
911         add("a b", "'a'");
912     }
913 
914     /**
915      * @throws Exception if the test fails
916      */
917     @Test
918     @Alerts({"b\\sa", "2", "2", "b\\sa", "class\\schanged\\sold:\\sb\\sa"})
919     public void addExisting2() throws Exception {
920         add("b a", "'a'");
921     }
922 
923     /**
924      * @throws Exception if the test fails
925      */
926     @Test
927     @Alerts({"b\\sa\\sb", "2", "3", "b\\sa\\sc", "class\\schanged\\sold:\\sb\\sa\\sb"})
928     public void addNormalizes() throws Exception {
929         add("b a b", "'c'");
930     }
931 
932     /**
933      * @throws Exception if the test fails
934      */
935     @Test
936     @Alerts({"a\\sb\\sa", "2", "InvalidCharacterError/DOMException", "2", "a\\sb\\sa"})
937     public void addElementWithBlank() throws Exception {
938         add("a b a", "'a b'");
939     }
940 
941     /**
942      * @throws Exception if the test fails
943      */
944     @Test
945     @Alerts({"a\\sb\\sa\\tb", "2", "InvalidCharacterError/DOMException", "2", "a\\sb\\sa\\tb"})
946     public void addElementWithTab() throws Exception {
947         add("a b a\tb", "'a\tb'");
948     }
949 
950     /**
951      * @throws Exception if the test fails
952      */
953     @Test
954     @Alerts({"a\\s\\t\\sc\\s\\n\\sd\\s\\se", "4", "4", "a\\sc\\sd\\se",
955              "class\\schanged\\sold:\\sa\\s\\t\\sc\\s\\n\\sd\\s\\se"})
956     public void addToWhitespaceExisting() throws Exception {
957         add("a \t c \n d  e", "'c'");
958     }
959 
960     /**
961      * @throws Exception if the test fails
962      */
963     @Test
964     @Alerts({"a\\se", "2", "4", "a\\se\\sc\\sb", "class\\schanged\\sold:\\sa\\se"})
965     public void addTwoValues() throws Exception {
966         add("a e", "'c', 'b'");
967     }
968 
969     /**
970      * @throws Exception if the test fails
971      */
972     @Test
973     @Alerts({"a\\se", "2", "3", "a\\se\\sc", "class\\schanged\\sold:\\sa\\se"})
974     public void addTwoValuesExisting() throws Exception {
975         add("a e", "'c', 'e'");
976     }
977 
978     /**
979      * @throws Exception if the test fails
980      */
981     @Test
982     @Alerts({"a\\se", "2", "4", "a\\se\\sc\\s7", "class\\schanged\\sold:\\sa\\se"})
983     public void addTwoValuesNumber() throws Exception {
984         add("a e", "'c', 7");
985     }
986 
987     /**
988      * @throws Exception if the test fails
989      */
990     @Test
991     @Alerts({"a\\se", "2", "4", "a\\se\\strue\\sfalse", "class\\schanged\\sold:\\sa\\se"})
992     public void addTwoValuesBoolean() throws Exception {
993         add("a e", "true, false");
994     }
995 
996     /**
997      * @throws Exception if the test fails
998      */
999     @Test
1000     @Alerts({"a\\se", "2", "InvalidCharacterError/DOMException", "2", "a\\se"})
1001     public void addTwoValuesObject() throws Exception {
1002         add("a e", "'c', { color: 'blue' }");
1003     }
1004 
1005     /**
1006      * @throws Exception if the test fails
1007      */
1008     @Test
1009     @Alerts({"a\\se", "2", "4", "a\\se\\sc\\sundefined", "class\\schanged\\sold:\\sa\\se"})
1010     public void addTwoValuesUndefined() throws Exception {
1011         add("a e", "'c', undefined");
1012     }
1013 
1014     /**
1015      * @throws Exception if the test fails
1016      */
1017     @Test
1018     @Alerts({"a\\se", "2", "4", "a\\se\\sc\\snull", "class\\schanged\\sold:\\sa\\se"})
1019     public void addTwoValuesNull() throws Exception {
1020         add("a e", "'c', null");
1021     }
1022 
1023     private void add(final String in, final String toAdd) throws Exception {
1024         final String html = DOCTYPE_HTML
1025             + "<html><head>\n"
1026             + "<script>\n"
1027             + LOG_TITLE_FUNCTION_NORMALIZE
1028             + "  function test() {\n"
1029             + "    var elem = document.getElementById('d1');\n"
1030 
1031             + "    var config = { attributes: true, attributeOldValue: true };\n"
1032             + "    var observer = new MutationObserver(function(mutations) {\n"
1033             + "      mutations.forEach(function(mutation) {\n"
1034             + "        log(mutation.attributeName + ' changed old: ' + mutation.oldValue);\n"
1035             + "      });\n"
1036             + "    });\n"
1037             + "    observer.observe(elem, config);"
1038 
1039             + "    var list = elem.classList;\n"
1040             + "    if (!list) { log('no list'); return; }\n"
1041 
1042             + "    log(elem.className);\n"
1043             + "    log(list.length);\n"
1044             + "    try {\n"
1045             + "      list.add(" + toAdd + ");\n"
1046             + "    } catch(e) { logEx(e);}\n"
1047             + "    log(list.length);\n"
1048             + "    log(elem.className);\n"
1049             + "  }\n"
1050             + "</script></head>\n"
1051             + "<body onload='test()'>\n"
1052             + "  <div id='d1' class='" + in + "'></div>\n"
1053             + "</body></html>";
1054 
1055         loadPageVerifyTitle2(html);
1056     }
1057 
1058     /**
1059      * @throws Exception if the test fails
1060      */
1061     @Test
1062     @Alerts({"2", "3"})
1063     public void addSvg() throws Exception {
1064         final String html = DOCTYPE_HTML
1065             + "<html><head>\n"
1066             + "<script>\n"
1067             + LOG_TITLE_FUNCTION
1068             + "  function test() {\n"
1069             + "    var elem = document.getElementById('myId');\n"
1070             + "    var list = elem.classList;\n"
1071             + "    if (!list) { log('no list'); return; }\n"
1072 
1073             + "    log(list.length);\n"
1074             + "    try {\n"
1075             + "      list.add('new');\n"
1076             + "    } catch(e) { logEx(e);}\n"
1077             + "    log(list.length);\n"
1078             + "  }\n"
1079             + "</script></head><body onload='test()'>\n"
1080             + "  <svg xmlns='http://www.w3.org/2000/svg' version='1.1'>\n"
1081             + "    <text id='myId' class='cls1, cls2'/>\n"
1082             + "  </svg>\n"
1083             + "</body></html>";
1084 
1085         loadPageVerifyTitle2(html);
1086     }
1087 
1088     /**
1089      * @throws Exception if the test fails
1090      */
1091     @Test
1092     @Alerts({"block", "none"})
1093     public void addStyleCheck() throws Exception {
1094         final String html = DOCTYPE_HTML
1095             + "<html><head>\n"
1096             + "<style>\n"
1097             + "  #d1.hidden { display: none; }\n"
1098             + "</style>\n"
1099             + "<script>\n"
1100             + LOG_TITLE_FUNCTION
1101             + "function test() {\n"
1102             + "  var div1 = document.getElementById('d1');\n"
1103             + "  var list = div1.classList;\n"
1104 
1105             + "  log(getComputedStyle(div1, null).display);\n"
1106             + "  list.add('hidden');\n"
1107             + "  log(getComputedStyle(div1, null).display);\n"
1108             + "}\n"
1109             + "</script>"
1110             + "</head>\n"
1111             + "<body onload='test()'>\n"
1112             + "  <div id='d1' class='nice'></div>\n"
1113             + "</body></html>";
1114 
1115         loadPageVerifyTitle2(html);
1116     }
1117 
1118     /**
1119      * @throws Exception if the test fails
1120      */
1121     @Test
1122     @Alerts({"a\\sb", "2", "SyntaxError/DOMException", "2", "a\\sb", "<div\\sid=\"d1\"\\sclass=\"a\\sb\"></div>"})
1123     public void removeEmpty() throws Exception {
1124         remove("a b", "''");
1125     }
1126 
1127     /**
1128      * @throws Exception if the test fails
1129      */
1130     @Test
1131     @Alerts({"a\\sb", "2", "InvalidCharacterError/DOMException",
1132              "2", "a\\sb", "<div\\sid=\"d1\"\\sclass=\"a\\sb\"></div>"})
1133     public void removeBlank() throws Exception {
1134         remove("a b", "' '");
1135     }
1136 
1137     /**
1138      * @throws Exception if the test fails
1139      */
1140     @Test
1141     @Alerts({"a\\sb", "2", "InvalidCharacterError/DOMException",
1142              "2", "a\\sb", "<div\\sid=\"d1\"\\sclass=\"a\\sb\"></div>"})
1143     public void removeTab() throws Exception {
1144         remove("a b", "'\t'");
1145     }
1146 
1147     /**
1148      * @throws Exception if the test fails
1149      */
1150     @Test
1151     @Alerts({"a\\sb", "2", "InvalidCharacterError/DOMException",
1152              "2", "a\\sb", "<div\\sid=\"d1\"\\sclass=\"a\\sb\"></div>"})
1153     public void removeCr() throws Exception {
1154         remove("a b", "'\\r'");
1155     }
1156 
1157     /**
1158      * @throws Exception if the test fails
1159      */
1160     @Test
1161     @Alerts({"a\\sb", "2", "InvalidCharacterError/DOMException",
1162              "2", "a\\sb", "<div\\sid=\"d1\"\\sclass=\"a\\sb\"></div>"})
1163     public void removeNl() throws Exception {
1164         remove("a b", "'\\n'");
1165     }
1166 
1167     /**
1168      * @throws Exception if the test fails
1169      */
1170     @Test
1171     @Alerts({"a\\sb", "2", "2", "a\\sb", "<div\\sid=\"d1\"\\sclass=\"a\\sb\"></div>", "class\\schanged\\sold:\\sa\\sb"})
1172     public void removeVt() throws Exception {
1173         remove("a b", "'\u000B'");
1174     }
1175 
1176     /**
1177      * @throws Exception if the test fails
1178      */
1179     @Test
1180     @Alerts({"", "0", "0", "", "<div\\sid=\"d1\"\\sclass=\"\"></div>", "class\\schanged\\sold:\\s"})
1181     public void removeFromEmpty() throws Exception {
1182         remove("", "'a'");
1183     }
1184 
1185     /**
1186      * @throws Exception if the test fails
1187      */
1188     @Test
1189     @Alerts({"\\s\\t\\s\\n\\s\\s", "0", "0", "",
1190              "<div\\sid=\"d1\"\\sclass=\"\"></div>",
1191              "class\\schanged\\sold:\\s\\s\\t\\s\\n\\s\\s"})
1192     public void removeFromWhitespace() throws Exception {
1193         remove(" \t \r  ", "'a'");
1194     }
1195 
1196     /**
1197      * @throws Exception if the test fails
1198      */
1199     @Test
1200     @Alerts({"a\\sb", "2", "2", "a\\sb", "<div\\sid=\"d1\"\\sclass=\"a\\sb\"></div>", "class\\schanged\\sold:\\sa\\sb"})
1201     public void removeNotExisting() throws Exception {
1202         remove("a b", "'c'");
1203     }
1204 
1205     /**
1206      * @throws Exception if the test fails
1207      */
1208     @Test
1209     @Alerts({"a\\sb\\sa", "2", "1", "b", "<div\\sid=\"d1\"\\sclass=\"b\"></div>", "class\\schanged\\sold:\\sa\\sb\\sa"})
1210     public void removeDuplicated() throws Exception {
1211         remove("a b a", "'a'");
1212     }
1213 
1214     /**
1215      * @throws Exception if the test fails
1216      */
1217     @Test
1218     @Alerts({"a\\sb\\sa", "2", "InvalidCharacterError/DOMException", "2", "a\\sb\\sa",
1219              "<div\\sid=\"d1\"\\sclass=\"a\\sb\\sa\"></div>"})
1220     public void removeElementWithBlank() throws Exception {
1221         remove("a b a", "'a b'");
1222     }
1223 
1224     /**
1225      * @throws Exception if the test fails
1226      */
1227     @Test
1228     @Alerts({"a\\sb\\sa\\tb", "2", "InvalidCharacterError/DOMException", "2", "a\\sb\\sa\\tb",
1229              "<div\\sid=\"d1\"\\sclass=\"a\\sb\\sa\\tb\"></div>"})
1230     public void removeElementWithTab() throws Exception {
1231         remove("a b a\tb", "'a\tb'");
1232     }
1233 
1234     /**
1235      * @throws Exception if the test fails
1236      */
1237     @Test
1238     @Alerts({"a", "1", "0", "", "<div\\sid=\"d1\"\\sclass=\"\"></div>", "class\\schanged\\sold:\\sa"})
1239     public void removeLast() throws Exception {
1240         remove("a", "'a'");
1241     }
1242 
1243     /**
1244      * @throws Exception if the test fails
1245      */
1246     @Test
1247     @Alerts({"a\\s\\t\\sc\\s\\n\\sd\\s\\se", "4", "3", "a\\sd\\se",
1248              "<div\\sid=\"d1\"\\sclass=\"a\\sd\\se\"></div>",
1249              "class\\schanged\\sold:\\sa\\s\\t\\sc\\s\\n\\sd\\s\\se"})
1250     public void removeWhitespace() throws Exception {
1251         remove("a \t c \n d  e", "'c'");
1252     }
1253 
1254     /**
1255      * @throws Exception if the test fails
1256      */
1257     @Test
1258     @Alerts({"a\\sc\\sa\\sc", "2", "1", "a",
1259              "<div\\sid=\"d1\"\\sclass=\"a\"></div>",
1260              "class\\schanged\\sold:\\sa\\sc\\sa\\sc"})
1261     public void removeNormalizes() throws Exception {
1262         remove("a c a c", "'c'");
1263     }
1264 
1265     /**
1266      * @throws Exception if the test fails
1267      */
1268     @Test
1269     @Alerts({"c", "1", "0", "",
1270              "<div\\sid=\"d1\"\\sclass=\"\"></div>",
1271              "class\\schanged\\sold:\\sc"})
1272     public void removeAll() throws Exception {
1273         remove("c", "'c'");
1274     }
1275 
1276     /**
1277      * @throws Exception if the test fails
1278      */
1279     @Test
1280     @Alerts({"", "0", "0", "",
1281              "<div\\sid=\"d1\"\\sclass=\"\"></div>",
1282              "class\\schanged\\sold:\\s"})
1283     public void removeAllFromEmpty() throws Exception {
1284         remove("", "'c'");
1285     }
1286 
1287     /**
1288      * @throws Exception if the test fails
1289      */
1290     @Test
1291     @Alerts({"", "0", "0", "",
1292              "<div\\sid=\"d1\"></div>"})
1293     public void removeAllNotDefined() throws Exception {
1294         remove(null, "'c'");
1295     }
1296 
1297     /**
1298      * @throws Exception if the test fails
1299      */
1300     @Test
1301     @Alerts({"a\\sb", "2", "1", "a",
1302              "<div\\sid=\"d1\"\\sclass=\"a\"></div>",
1303              "class\\schanged\\sold:\\sa\\sb"})
1304     public void removeTwo() throws Exception {
1305         remove("a b", "'b', 'd'");
1306     }
1307 
1308     /**
1309      * @throws Exception if the test fails
1310      */
1311     @Test
1312     @Alerts({"a\\sb\\s7", "3", "1", "a",
1313              "<div\\sid=\"d1\"\\sclass=\"a\"></div>",
1314              "class\\schanged\\sold:\\sa\\sb\\s7"})
1315     public void removeTwoNumber() throws Exception {
1316         remove("a b 7", "'b', 7");
1317     }
1318 
1319     /**
1320      * @throws Exception if the test fails
1321      */
1322     @Test
1323     @Alerts({"a\\sb\\strue", "3", "2", "a\\sb",
1324              "<div\\sid=\"d1\"\\sclass=\"a\\sb\"></div>",
1325              "class\\schanged\\sold:\\sa\\sb\\strue"})
1326     public void removeTwoBoolean() throws Exception {
1327         remove("a b true", "true, false");
1328     }
1329 
1330     /**
1331      * @throws Exception if the test fails
1332      */
1333     @Test
1334     @Alerts({"a\\sb\\sundefined", "3", "1", "a",
1335              "<div\\sid=\"d1\"\\sclass=\"a\"></div>",
1336              "class\\schanged\\sold:\\sa\\sb\\sundefined"})
1337     public void removeTwoUndefined() throws Exception {
1338         remove("a b undefined", "'b', undefined");
1339     }
1340 
1341     /**
1342      * @throws Exception if the test fails
1343      */
1344     @Test
1345     @Alerts({"a\\snull\\s7", "3", "2", "a\\s7",
1346              "<div\\sid=\"d1\"\\sclass=\"a\\s7\"></div>",
1347              "class\\schanged\\sold:\\sa\\snull\\s7"})
1348     public void removeTwoNull() throws Exception {
1349         remove("a null 7", "'b', null");
1350     }
1351 
1352     /**
1353      * @throws Exception if the test fails
1354      */
1355     @Test
1356     @Alerts({"a\\sb\\s7", "3", "InvalidCharacterError/DOMException", "3", "a\\sb\\s7",
1357              "<div\\sid=\"d1\"\\sclass=\"a\\sb\\s7\"></div>"})
1358     public void removeTwoObject() throws Exception {
1359         remove("a b 7", "'b', { color: 'red' }");
1360     }
1361 
1362     private void remove(final String in, final String toRemove) throws Exception {
1363         String html = DOCTYPE_HTML
1364             + "<html><head>\n"
1365             + "<script>\n"
1366             + LOG_TITLE_FUNCTION_NORMALIZE
1367             + "  function test() {\n"
1368             + "    var elem = document.getElementById('d1');\n"
1369 
1370             + "    var config = { attributes: true, attributeOldValue: true };\n"
1371             + "    var observer = new MutationObserver(function(mutations) {\n"
1372             + "      mutations.forEach(function(mutation) {\n"
1373             + "        log(mutation.attributeName + ' changed old: ' + mutation.oldValue);\n"
1374             + "      });\n"
1375             + "    });\n"
1376             + "    observer.observe(elem, config);"
1377 
1378             + "    var list = elem.classList;\n"
1379             + "    if (!list) { log('no list'); return; }\n"
1380 
1381             + "    log(elem.className);\n"
1382             + "    log(list.length);\n"
1383             + "    try {\n"
1384             + "      list.remove(" + toRemove + ");\n"
1385             + "    } catch(e) { logEx(e);}\n"
1386             + "    log(list.length);\n"
1387             + "    log(elem.className);\n"
1388             + "    log(elem.outerHTML);\n"
1389             + "  }\n"
1390             + "</script></head>\n"
1391             + "<body onload='test()'>\n";
1392         if (in == null) {
1393             html += "  <div id='d1'></div>\n";
1394         }
1395         else {
1396             html += "  <div id='d1' class='" + in + "'></div>\n";
1397         }
1398 
1399         html += "</body></html>";
1400 
1401         loadPageVerifyTitle2(html);
1402     }
1403 
1404     /**
1405      * @throws Exception if the test fails
1406      */
1407     @Test
1408     @Alerts({"a", "1", "SyntaxError/DOMException", "1", "a", "<div\\sid=\"d1\"\\sclass=\"a\"></div>"})
1409     public void replaceEmptyOldToken() throws Exception {
1410         replace("a", "", "abc");
1411     }
1412 
1413     /**
1414      * @throws Exception if the test fails
1415      */
1416     @Test
1417     @Alerts({"a\\sb", "2", "InvalidCharacterError/DOMException",
1418              "2", "a\\sb", "<div\\sid=\"d1\"\\sclass=\"a\\sb\"></div>"})
1419     public void replaceOldTokenContainingWhiteSpace() throws Exception {
1420         replace("a b", " a x", "abc");
1421     }
1422 
1423     /**
1424      * @throws Exception if the test fails
1425      */
1426     @Test
1427     @Alerts({"a", "1", "SyntaxError/DOMException", "1", "a", "<div\\sid=\"d1\"\\sclass=\"a\"></div>"})
1428     public void replaceEmptyNewToken() throws Exception {
1429         replace("a", "abc", "");
1430     }
1431 
1432     /**
1433      * @throws Exception if the test fails
1434      */
1435     @Test
1436     @Alerts({"a\\sb", "2", "InvalidCharacterError/DOMException",
1437              "2", "a\\sb", "<div\\sid=\"d1\"\\sclass=\"a\\sb\"></div>"})
1438     public void replaceNewTokenContainingWhiteSpace() throws Exception {
1439         replace("a b", "abc", " a x");
1440     }
1441 
1442     /**
1443      * @throws Exception if the test fails
1444      */
1445     @Test
1446     @Alerts({"a\\sb", "2", "true", "2", "a\\sax",
1447              "<div\\sid=\"d1\"\\sclass=\"a\\sax\"></div>",
1448              "class\\schanged\\sold:\\sa\\sb"})
1449     public void replace() throws Exception {
1450         replace("a b", "b", "ax");
1451     }
1452 
1453     /**
1454      * @throws Exception if the test fails
1455      */
1456     @Test
1457     @Alerts({"a\\sb\\sc\\sb\\su", "4", "true", "4", "a\\sax\\sc\\su",
1458              "<div\\sid=\"d1\"\\sclass=\"a\\sax\\sc\\su\"></div>",
1459              "class\\schanged\\sold:\\sa\\sb\\sc\\sb\\su"})
1460     public void replaceOnce() throws Exception {
1461         replace("a b c b u", "b", "ax");
1462     }
1463 
1464     /**
1465      * @throws Exception if the test fails
1466      */
1467     @Test
1468     @Alerts({"a\\sb", "2", "false", "2", "a\\sb", "<div\\sid=\"d1\"\\sclass=\"a\\sb\"></div>"})
1469     public void replaceNotFound() throws Exception {
1470         replace("a b", "ab", "ax");
1471     }
1472 
1473     /**
1474      * @throws Exception if the test fails
1475      */
1476     @Test
1477     @Alerts({"", "0", "false", "0", "", "<div\\sid=\"d1\"\\sclass=\"\"></div>"})
1478     public void replaceInEmpty() throws Exception {
1479         replace("", "ab", "ax");
1480     }
1481 
1482     /**
1483      * @throws Exception if the test fails
1484      */
1485     @Test
1486     @Alerts({"", "0", "false", "0", "",
1487              "<div\\sid=\"d1\"\\sclass=\"\"></div>"})
1488     public void replaceFromEmpty() throws Exception {
1489         replace("", "a", "c");
1490     }
1491 
1492     /**
1493      * @throws Exception if the test fails
1494      */
1495     @Test
1496     @Alerts({"", "0", "false", "0", "",
1497              "<div\\sid=\"d1\"></div>"})
1498     public void replaceNotDefined() throws Exception {
1499         replace(null, "a", "c");
1500     }
1501 
1502     private void replace(final String in, final String oldToken, final String newToken) throws Exception {
1503         String html = DOCTYPE_HTML
1504             + "<html><head>\n"
1505             + "<script>\n"
1506             + LOG_TITLE_FUNCTION_NORMALIZE
1507             + "  function test() {\n"
1508             + "    var elem = document.getElementById('d1');\n"
1509 
1510             + "    var config = { attributes: true, attributeOldValue: true };\n"
1511             + "    var observer = new MutationObserver(function(mutations) {\n"
1512             + "      mutations.forEach(function(mutation) {\n"
1513             + "        log(mutation.attributeName + ' changed old: ' + mutation.oldValue);\n"
1514             + "      });\n"
1515             + "    });\n"
1516             + "    observer.observe(elem, config);"
1517 
1518             + "    var list = elem.classList;\n"
1519             + "    if (!list) { log('no list'); return; }\n"
1520 
1521             + "    log(elem.className);\n"
1522             + "    log(list.length);\n"
1523             + "    try {\n"
1524             + "      var res = list.replace('" + oldToken + "', '" + newToken + "');\n"
1525             + "      log(res);\n"
1526             + "    } catch(e) { logEx(e);}\n"
1527             + "    log(list.length);\n"
1528             + "    log(elem.className);\n"
1529             + "    log(elem.outerHTML);\n"
1530             + "  }\n"
1531             + "</script></head>\n"
1532             + "<body onload='test()'>\n";
1533         if (in == null) {
1534             html += "  <div id='d1'></div>\n";
1535         }
1536         else {
1537             html += "  <div id='d1' class='" + in + "'></div>\n";
1538         }
1539 
1540         html += "</body></html>";
1541 
1542         loadPageVerifyTitle2(html);
1543     }
1544 
1545     /**
1546      * @throws Exception if the test fails
1547      */
1548     @Test
1549     @Alerts({ "none", "block"})
1550     public void removeStyleCheck() throws Exception {
1551         final String html = DOCTYPE_HTML
1552             + "<html><head>\n"
1553             + "<style>\n"
1554             + "  #d1.hidden { display: none; }\n"
1555             + "</style>\n"
1556             + "<script>\n"
1557             + LOG_TITLE_FUNCTION
1558             + "function test() {\n"
1559             + "  var div1 = document.getElementById('d1');\n"
1560             + "  var list = div1.classList;\n"
1561 
1562             + "  log(getComputedStyle(div1, null).display);\n"
1563             + "  list.remove('hidden');\n"
1564             + "  log(getComputedStyle(div1, null).display);\n"
1565             + "}\n"
1566             + "</script>"
1567             + "</head>\n"
1568             + "<body onload='test()'>\n"
1569             + "  <div id='d1' class='hidden'></div>\n"
1570             + "</body></html>";
1571 
1572         loadPageVerifyTitle2(html);
1573     }
1574 
1575     /**
1576      * @throws Exception if the test fails
1577      */
1578     @Test
1579     @Alerts({"2", "false", "true", "false", "false"})
1580     public void in() throws Exception {
1581         final String html = DOCTYPE_HTML
1582             + "<html><head><script>\n"
1583             + LOG_TITLE_FUNCTION
1584             + "function test() {\n"
1585             + "  var list = document.getElementById('d1').classList;\n"
1586             + "  log(list.length);\n"
1587             + "  log(-1 in list);\n"
1588             + "  log(0 in list);\n"
1589             + "  log(2 in list);\n"
1590             + "  log(42 in list);\n"
1591             + "}\n"
1592             + "</script></head><body onload='test()'>\n"
1593             + "  <div id='d1' class='a e'></div>\n"
1594             + "</body></html>";
1595 
1596         loadPageVerifyTitle2(html);
1597     }
1598 
1599     /**
1600      * @throws Exception if the test fails
1601      */
1602     @Test
1603     @Alerts({"InvalidCharacterError/DOMException", "SyntaxError/DOMException",
1604              "2", "true", "false", "1", "false", "true", "2", "true",
1605              "class changed old: a e", "class changed old: a"})
1606     public void toggle() throws Exception {
1607         final String html = DOCTYPE_HTML
1608             + "<html><head><script>\n"
1609             + LOG_TITLE_FUNCTION
1610             + "function test() {\n"
1611             + "  var elem = document.getElementById('d1');\n"
1612 
1613             + "    var config = { attributes: true, attributeOldValue: true };\n"
1614             + "    var observer = new MutationObserver(function(mutations) {\n"
1615             + "      mutations.forEach(function(mutation) {\n"
1616             + "        log(mutation.attributeName + ' changed old: ' + mutation.oldValue);\n"
1617             + "      });\n"
1618             + "    });\n"
1619             + "    observer.observe(elem, config);"
1620 
1621             + "  var list = elem.classList;\n"
1622             + "  try {\n"
1623             + "    list.toggle('ab e');\n"
1624             + "  } catch(e) { logEx(e);}\n"
1625             + "  try {\n"
1626             + "    list.toggle('');\n"
1627             + "  } catch(e) { logEx(e);}\n"
1628             + "  log(list.length);\n"
1629             + "  log(list.contains('e'));\n"
1630             + "  log(list.toggle('e'));\n"
1631             + "  log(list.length);\n"
1632             + "  log(list.contains('e'));\n"
1633             + "  log(list.toggle('e'));\n"
1634             + "  log(list.length);\n"
1635             + "  log(list.contains('e'));\n"
1636             + "}\n"
1637             + "</script></head><body onload='test()'>\n"
1638             + "  <div id='d1' class='a e'></div>\n"
1639             + "</body></html>";
1640 
1641         loadPageVerifyTitle2(html);
1642     }
1643 
1644     /**
1645      * @throws Exception if the test fails
1646      */
1647     @Test
1648     @Alerts({"none", "block", "none"})
1649     public void toggleStyleCheck() throws Exception {
1650         final String html = DOCTYPE_HTML
1651             + "<html><head>\n"
1652             + "<style>\n"
1653             + "  #d1.hidden { display: none; }\n"
1654             + "</style>\n"
1655             + "<script>\n"
1656             + LOG_TITLE_FUNCTION
1657             + "function test() {\n"
1658             + "  var div1 = document.getElementById('d1');\n"
1659             + "  var list = div1.classList;\n"
1660             + "  log(getComputedStyle(div1, null).display);\n"
1661 
1662             + "  list.toggle('hidden');\n"
1663             + "  log(getComputedStyle(div1, null).display);\n"
1664 
1665             + "  list.toggle('hidden');\n"
1666             + "  log(getComputedStyle(div1, null).display);\n"
1667             + "}\n"
1668             + "</script>"
1669             + "</head>\n"
1670             + "<body onload='test()'>\n"
1671             + "  <div id='d1' class='hidden'></div>\n"
1672             + "</body></html>";
1673 
1674         loadPageVerifyTitle2(html);
1675     }
1676 
1677     /**
1678      * @throws Exception if the test fails
1679      */
1680     @Test
1681     @Alerts({"a", "1", "SyntaxError/DOMException", "1", "a", "<div\\sid=\"d1\"\\sclass=\"a\"></div>"})
1682     public void toggleEmptyToken() throws Exception {
1683         toggle("a", "");
1684     }
1685 
1686     /**
1687      * @throws Exception if the test fails
1688      */
1689     @Test
1690     @Alerts({"a\\sb", "2", "false", "1", "a",
1691              "<div\\sid=\"d1\"\\sclass=\"a\"></div>",
1692              "class\\schanged\\sold:\\sa\\sb"})
1693     public void toggleStd() throws Exception {
1694         toggle("a b", "b");
1695     }
1696 
1697     /**
1698      * @throws Exception if the test fails
1699      */
1700     @Test
1701     @Alerts({"a\\sb\\sc\\sb\\su", "4", "false", "3", "a\\sc\\su",
1702              "<div\\sid=\"d1\"\\sclass=\"a\\sc\\su\"></div>",
1703              "class\\schanged\\sold:\\sa\\sb\\sc\\sb\\su"})
1704     public void toggleOnce() throws Exception {
1705         toggle("a b c b u", "b");
1706     }
1707 
1708     /**
1709      * @throws Exception if the test fails
1710      */
1711     @Test
1712     @Alerts({"a\\sb", "2", "true", "3", "a\\sb\\sab",
1713              "<div\\sid=\"d1\"\\sclass=\"a\\sb\\sab\"></div>",
1714              "class\\schanged\\sold:\\sa\\sb"})
1715     public void toggleNotFound() throws Exception {
1716         toggle("a b", "ab");
1717     }
1718 
1719     /**
1720      * @throws Exception if the test fails
1721      */
1722     @Test
1723     @Alerts({"a", "1", "false", "0", "",
1724              "<div\\sid=\"d1\"\\sclass=\"\"></div>",
1725              "class\\schanged\\sold:\\sa"})
1726     public void toggleTheOnly() throws Exception {
1727         toggle("a", "a");
1728     }
1729 
1730     /**
1731      * @throws Exception if the test fails
1732      */
1733     @Test
1734     @Alerts({"", "0", "true", "1", "a",
1735              "<div\\sid=\"d1\"\\sclass=\"a\"></div>",
1736              "class\\schanged\\sold:\\s"})
1737     public void toggleInEmpty() throws Exception {
1738         toggle("", "a");
1739     }
1740 
1741     /**
1742      * @throws Exception if the test fails
1743      */
1744     @Test
1745     @Alerts({"", "0", "true", "1", "a",
1746              "<div\\sid=\"d1\"\\sclass=\"a\"></div>",
1747              "class\\schanged\\sold:\\s"})
1748     public void toggleFromEmpty() throws Exception {
1749         toggle("", "a");
1750     }
1751 
1752     /**
1753      * @throws Exception if the test fails
1754      */
1755     @Test
1756     @Alerts({"", "0", "true", "1", "a",
1757              "<div\\sid=\"d1\"\\sclass=\"a\"></div>",
1758              "class\\schanged\\sold:\\snull"})
1759     public void toggleNotDefined() throws Exception {
1760         toggle(null, "a");
1761     }
1762 
1763     private void toggle(final String in, final String token) throws Exception {
1764         String html = DOCTYPE_HTML
1765             + "<html><head>\n"
1766             + "<script>\n"
1767             + LOG_TITLE_FUNCTION_NORMALIZE
1768             + "  function test() {\n"
1769             + "    var elem = document.getElementById('d1');\n"
1770 
1771             + "    var config = { attributes: true, attributeOldValue: true };\n"
1772             + "    var observer = new MutationObserver(function(mutations) {\n"
1773             + "      mutations.forEach(function(mutation) {\n"
1774             + "        log(mutation.attributeName + ' changed old: ' + mutation.oldValue);\n"
1775             + "      });\n"
1776             + "    });\n"
1777             + "    observer.observe(elem, config);"
1778 
1779             + "    var list = elem.classList;\n"
1780             + "    if (!list) { log('no list'); return; }\n"
1781 
1782             + "    log(elem.className);\n"
1783             + "    log(list.length);\n"
1784             + "    try {\n"
1785             + "      var res = list.toggle('" + token + "');\n"
1786             + "      log(res);\n"
1787             + "    } catch(e) { logEx(e);}\n"
1788             + "    log(list.length);\n"
1789             + "    log(elem.className);\n"
1790             + "    log(elem.outerHTML);\n"
1791             + "  }\n"
1792             + "</script></head>\n"
1793             + "<body onload='test()'>\n";
1794         if (in == null) {
1795             html += "  <div id='d1'></div>\n";
1796         }
1797         else {
1798             html += "  <div id='d1' class='" + in + "'></div>\n";
1799         }
1800 
1801         html += "</body></html>";
1802 
1803         loadPageVerifyTitle2(html);
1804     }
1805 
1806     /**
1807      * @throws Exception if an error occurs
1808      */
1809     @Test
1810     @Alerts({"value", "done", "number", "0"})
1811     public void keys() throws Exception {
1812         final String html = DOCTYPE_HTML
1813             + "<html><head>\n"
1814             + "<script>\n"
1815             + LOG_TITLE_FUNCTION
1816             + "  function test() {\n"
1817             + "    var list = document.getElementById('d1').classList;\n"
1818             + "    if (!list.keys) {\n"
1819             + "      log('not defined');\n"
1820             + "      return;\n"
1821             + "    }\n"
1822             + "    var i = list.keys().next();\n"
1823             + "    for (var x in i) {\n"
1824             + "      log(x);\n"
1825             + "    }\n"
1826             + "    var v = i.value;\n"
1827             + "    log(typeof v);\n"
1828             + "    log(v);\n"
1829             + "  }\n"
1830             + "</script>\n"
1831             + "</head><body onload='test()'>\n"
1832             + "  <div id='d1' class=' a b g'></div>\n"
1833             + "</body></html>\n";
1834 
1835         loadPageVerifyTitle2(html);
1836     }
1837 
1838     /**
1839      * @throws Exception if an error occurs
1840      */
1841     @Test
1842     @Alerts({"true", "undefined", "function", "undefined", "undefined", "true", "true", "true"})
1843     public void keysPropertyDescriptor() throws Exception {
1844         final String html = DOCTYPE_HTML
1845             + "<html><head>\n"
1846             + "<script>\n"
1847             + LOG_TITLE_FUNCTION
1848             + "  function test() {\n"
1849             + "    var list = document.getElementById('d1').classList;\n"
1850 
1851             + "    log('keys' in list);\n"
1852             + "    log(Object.getOwnPropertyDescriptor(list, 'keys'));\n"
1853 
1854             + "    var desc = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(list), 'keys');\n"
1855             + "    if (desc === undefined) { log('no keys'); return; }\n"
1856             + "    log(typeof desc.value);\n"
1857             + "    log(desc.get);\n"
1858             + "    log(desc.set);\n"
1859             + "    log(desc.writable);\n"
1860             + "    log(desc.enumerable);\n"
1861             + "    log(desc.configurable);\n"
1862             + "  }\n"
1863             + "</script>\n"
1864             + "</head><body onload='test()'>\n"
1865             + "  <div id='d1' class=' a b g'></div>\n"
1866             + "</body></html>\n";
1867 
1868         loadPageVerifyTitle2(html);
1869     }
1870 
1871     /**
1872      * @throws Exception if an error occurs
1873      */
1874     @Test
1875     @Alerts({"0", "1", "2"})
1876     public void keysForOf() throws Exception {
1877         final String html = DOCTYPE_HTML
1878             + "<html><head>\n"
1879             + "<script>\n"
1880             + LOG_TITLE_FUNCTION
1881             + "  function test() {\n"
1882             + "    var list = document.getElementById('d1').classList;\n"
1883             + "    if (!list.keys) {\n"
1884             + "      log('not defined');\n"
1885             + "      return;\n"
1886             + "    }\n"
1887             + "    for (var i of list.keys()) {\n"
1888             + "      log(i);\n"
1889             + "    }\n"
1890             + "  }\n"
1891             + "</script>\n"
1892             + "</head><body onload='test()'>\n"
1893             + "  <div id='d1' class=' a b g'></div>\n"
1894             + "</body></html>\n";
1895 
1896         loadPageVerifyTitle2(html);
1897     }
1898 
1899     /**
1900      * @throws Exception if an error occurs
1901      */
1902     @Test
1903     @Alerts({"0,1,2", ""})
1904     public void objectKeys() throws Exception {
1905         final String html = DOCTYPE_HTML
1906             + "<html><head>\n"
1907             + "<script>\n"
1908             + LOG_TITLE_FUNCTION
1909             + "  function test() {\n"
1910             + "    var list = document.getElementById('d1').classList;\n"
1911             + "    log(Object.keys(list));\n"
1912 
1913             + "    var list = document.getElementById('b1').classList;\n"
1914             + "    log(Object.keys(list));\n"
1915             + "  }\n"
1916             + "</script>\n"
1917             + "</head><body onload='test()' id='b1'>\n"
1918             + "  <div id='d1' class=' a b g'></div>\n"
1919             + "</body></html>\n";
1920 
1921         loadPageVerifyTitle2(html);
1922     }
1923 
1924     /**
1925      * @throws Exception if an error occurs
1926      */
1927     @Test
1928     @Alerts({"value", "done", "string", "a"})
1929     public void values() throws Exception {
1930         final String html = DOCTYPE_HTML
1931             + "<html><head>\n"
1932             + "<script>\n"
1933             + LOG_TITLE_FUNCTION
1934             + "  function test() {\n"
1935             + "    var list = document.getElementById('d1').classList;\n"
1936             + "    if (!list.values) {\n"
1937             + "      log('not defined');\n"
1938             + "      return;\n"
1939             + "    }\n"
1940             + "    var i = list.values().next();\n"
1941             + "    for (var x in i) {\n"
1942             + "      log(x);\n"
1943             + "    }\n"
1944             + "    var v = i.value;\n"
1945             + "    log(typeof v);\n"
1946             + "    log(v);\n"
1947             + "  }\n"
1948             + "</script>\n"
1949             + "</head><body onload='test()'>\n"
1950             + "  <div id='d1' class=' a b g'></div>\n"
1951             + "</body></html>\n";
1952 
1953         loadPageVerifyTitle2(html);
1954     }
1955 
1956     /**
1957      * @throws Exception if an error occurs
1958      */
1959     @Test
1960     @Alerts({"true", "undefined", "function", "undefined", "undefined", "true", "true", "true"})
1961     public void valuesPropertyDescriptor() throws Exception {
1962         final String html = DOCTYPE_HTML
1963             + "<html><head>\n"
1964             + "<script>\n"
1965             + LOG_TITLE_FUNCTION
1966             + "  function test() {\n"
1967             + "    var list = document.getElementById('d1').classList;\n"
1968 
1969             + "    log('values' in list);\n"
1970             + "    log(Object.getOwnPropertyDescriptor(list, 'values'));\n"
1971 
1972             + "    var desc = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(list), 'values');\n"
1973             + "    if (desc === undefined) { log('no values'); return; }\n"
1974             + "    log(typeof desc.value);\n"
1975             + "    log(desc.get);\n"
1976             + "    log(desc.set);\n"
1977             + "    log(desc.writable);\n"
1978             + "    log(desc.enumerable);\n"
1979             + "    log(desc.configurable);\n"
1980             + "  }\n"
1981             + "</script>\n"
1982             + "</head><body onload='test()'>\n"
1983             + "  <div id='d1' class=' a b g'></div>\n"
1984             + "</body></html>\n";
1985 
1986         loadPageVerifyTitle2(html);
1987     }
1988 
1989     /**
1990      * @throws Exception if an error occurs
1991      */
1992     @Test
1993     @Alerts({"a", "b", "g"})
1994     public void valuesForOf() throws Exception {
1995         final String html = DOCTYPE_HTML
1996             + "<html><head>\n"
1997             + "<script>\n"
1998             + LOG_TITLE_FUNCTION
1999             + "  function test() {\n"
2000             + "    var list = document.getElementById('d1').classList;\n"
2001             + "    if (!list.values) {\n"
2002             + "      log('not defined');\n"
2003             + "      return;\n"
2004             + "    }\n"
2005             + "    for (var i of list.values()) {\n"
2006             + "      log(i);\n"
2007             + "    }\n"
2008             + "  }\n"
2009             + "</script>\n"
2010             + "</head><body onload='test()'>\n"
2011             + "  <div id='d1' class=' a b g'></div>\n"
2012             + "</body></html>\n";
2013 
2014         loadPageVerifyTitle2(html);
2015     }
2016 
2017     /**
2018      * @throws Exception if an error occurs
2019      */
2020     @Test
2021     @Alerts("\\sa\\sb\\sa\\s\\s\\s\\sa\\sg\\s\\s")
2022     public void getValue() throws Exception {
2023         final String html = DOCTYPE_HTML
2024             + "<html><head>\n"
2025             + "<script>\n"
2026             + LOG_TITLE_FUNCTION_NORMALIZE
2027             + "  function test() {\n"
2028             + "    var list = document.getElementById('d1').classList;\n"
2029             + "    if (!list.values) {\n"
2030             + "      log('not defined');\n"
2031             + "      return;\n"
2032             + "    }\n"
2033             + "    log(list.value);\n"
2034             + "  }\n"
2035             + "</script>\n"
2036             + "</head><body onload='test()'>\n"
2037             + "  <div id='d1' class=' a b a    a g  '></div>\n"
2038             + "</body></html>\n";
2039 
2040         loadPageVerifyTitle2(html);
2041     }
2042 
2043     /**
2044      * @throws Exception if an error occurs
2045      */
2046     @Test
2047     @Alerts({"\\sa\\sb\\sa\\s\\s\\s\\sa\\sg\\s\\s", "x\\sy", "z\\sz\\s\\s\\s\\s\\sx\\sz\\s\\s"})
2048     public void setValue() throws Exception {
2049         final String html = DOCTYPE_HTML
2050             + "<html><head>\n"
2051             + "<script>\n"
2052             + LOG_TITLE_FUNCTION_NORMALIZE
2053             + "  function test() {\n"
2054             + "    var list = document.getElementById('d1').classList;\n"
2055             + "    if (!list.values) {\n"
2056             + "      log('not defined');\n"
2057             + "      return;\n"
2058             + "    }\n"
2059             + "    log(list.value);\n"
2060 
2061             + "    list.value = 'x y';\n"
2062             + "    log(list.value);\n"
2063 
2064             + "    list.value = 'z z     x z  ';\n"
2065             + "    log(list.value);\n"
2066 
2067             + "  }\n"
2068             + "</script>\n"
2069             + "</head><body onload='test()'>\n"
2070             + "  <div id='d1' class=' a b a    a g  '></div>\n"
2071             + "</body></html>\n";
2072 
2073         loadPageVerifyTitle2(html);
2074     }
2075 
2076     /**
2077      * @throws Exception if an error occurs
2078      */
2079     @Test
2080     @Alerts({"a b", "<div id=\"d1\" class=\"a b\"></div>", "", "<div id=\"d1\" class=\"\"></div>",
2081              "undefined", "<div id=\"d1\" class=\"undefined\"></div>",
2082              "null", "<div id=\"d1\" class=\"null\"></div>",
2083              "17", "<div id=\"d1\" class=\"17\"></div>"})
2084     public void setValueEmpty() throws Exception {
2085         final String html = DOCTYPE_HTML
2086             + "<html><head>\n"
2087             + "<script>\n"
2088             + LOG_TITLE_FUNCTION
2089             + "  function test() {\n"
2090             + "    var div = document.getElementById('d1');\n"
2091             + "    var list = div.classList;\n"
2092             + "    if (!list.values) {\n"
2093             + "      log('not defined');\n"
2094             + "      return;\n"
2095             + "    }\n"
2096             + "    log(list.value);\n"
2097             + "    log(div.outerHTML);\n"
2098 
2099             + "    list.value = '';\n"
2100             + "    log(list.value);\n"
2101             + "    log(div.outerHTML);\n"
2102 
2103             + "    list.value = undefined;\n"
2104             + "    log(list.value);\n"
2105             + "    log(div.outerHTML);\n"
2106 
2107             + "    list.value = null;\n"
2108             + "    log(list.value);\n"
2109             + "    log(div.outerHTML);\n"
2110 
2111 
2112             + "    list.value = 17;\n"
2113             + "    log(list.value);\n"
2114             + "    log(div.outerHTML);\n"
2115 
2116             + "  }\n"
2117             + "</script>\n"
2118             + "</head><body onload='test()'>\n"
2119             + "  <div id='d1' class='a b'></div>\n"
2120             + "</body></html>\n";
2121 
2122         loadPageVerifyTitle2(html);
2123     }
2124 }