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