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.html;
16  
17  import org.htmlunit.WebDriverTestCase;
18  import org.htmlunit.junit.BrowserRunner;
19  import org.htmlunit.junit.annotation.Alerts;
20  import org.junit.Test;
21  import org.junit.runner.RunWith;
22  
23  /**
24   * Tests for {@link HTMLCollection}.
25   *
26   * @author Marc Guillemot
27   * @author Ahmed Ashour
28   * @author Frank Danek
29   * @author Ronald Brill
30   */
31  @RunWith(BrowserRunner.class)
32  public class HTMLCollectionTest extends WebDriverTestCase {
33  
34      /**
35       * @throws Exception if the test fails
36       */
37      @Test
38      @Alerts("true")
39      public void implicitToStringConversion() throws Exception {
40          final String html = DOCTYPE_HTML
41              + "<html><head>\n"
42              + "<script>\n"
43              + LOG_TITLE_FUNCTION
44              + "function test() {\n"
45              + "  log(document.links != 'foo')\n"
46              + "}\n"
47              + "</script></head>\n"
48              + "<body onload='test()'>\n"
49              + "  <a href='bla.html'>link</a>\n"
50              + "</body></html>";
51  
52          loadPageVerifyTitle2(html);
53      }
54  
55      /**
56       * Test that <tt>toString</tt> is accessible.
57       * @throws Exception if the test fails
58       */
59      @Test
60      @Alerts("function")
61      public void toStringFunction() throws Exception {
62          final String html = DOCTYPE_HTML
63              + "<html><head>\n"
64              + "<script>\n"
65              + LOG_TITLE_FUNCTION
66              + "function test() {\n"
67              + "  log(typeof document.links.toString);\n"
68              + "}\n"
69              + "</script></head>\n"
70              + "<body onload='test()'>\n"
71              + "<a href='bla.html'>link</a>\n"
72              + "</body></html>";
73  
74          loadPageVerifyTitle2(html);
75      }
76  
77      /**
78       * @throws Exception if the test fails
79       */
80      @Test
81      @Alerts({"4", "HierarchyRequestError/DOMException"})
82      public void getElements() throws Exception {
83          final String html = DOCTYPE_HTML
84              + "<html><head>\n"
85              + "<script>\n"
86              + LOG_TITLE_FUNCTION
87              + "function doTest() {\n"
88              + "  log(document.all.length);\n"
89              + "  try {\n"
90              + "    document.appendChild(document.createElement('div'));\n"
91              + "    log(document.all.length);\n"
92              + "  } catch(e) { logEx(e) }\n"
93              + "}\n"
94              + "</script></head>\n"
95              + "<body onload='doTest()'>\n"
96              + "</body></html>";
97  
98          loadPageVerifyTitle2(html);
99      }
100 
101     /**
102      * @throws Exception if the test fails
103      */
104     @Test
105     @Alerts({"string 0", "string item", "string length", "string namedItem"})
106     public void for_in() throws Exception {
107         final String html = DOCTYPE_HTML
108             + "<html><head>\n"
109             + "<script>\n"
110             + LOG_TITLE_FUNCTION
111             + "  function test() {\n"
112             + "    var arr = new Array();\n"
113             + "    \n"
114             + "    for (i in document.forms) {\n"
115             + "      arr[arr.length] = (typeof i) + ' ' + i;\n"
116             + "    }\n"
117             + "    arr.sort();\n"
118             + "    for (i = 0; i < arr.length; i++) {\n"
119             + "      log(arr[i]);\n"
120             + "    }\n"
121             + "  }\n"
122             + "</script></head><body onload='test()'>\n"
123             + "<form name='myForm'></form>\n"
124             + "</body></html>";
125 
126         loadPageVerifyTitle2(html);
127     }
128 
129     /**
130      * @throws Exception if the test fails
131      */
132     @Test
133     @Alerts({"string 0", "string 1", "string 2", "string 3", "string 4", "string 5",
134              "string item", "string length", "string namedItem"})
135     public void for_in2() throws Exception {
136         final String html = DOCTYPE_HTML
137             + "<html><head>\n"
138             + "<script>\n"
139             + LOG_TITLE_FUNCTION
140             + "  function test() {\n"
141             + "    var form = document.getElementById('myForm');\n"
142             + "    var x = form.getElementsByTagName('*');\n"
143             + "    var arr = new Array();\n"
144             + "    for (i in x){\n"
145             + "      arr[arr.length] = (typeof i) + ' ' + i;\n"
146             + "    }\n"
147             + "    arr.sort();\n"
148             + "    for (i = 0; i < arr.length; i++) {\n"
149             + "      log(arr[i]);\n"
150             + "    }\n"
151             + "  }\n"
152             + "</script></head><body onload='test()'>\n"
153             + "<form id='myForm'>\n"
154             + "  <input type='text' id='id1' name='val1' id='input_enabled' value='4'>\n"
155             + "  <div>This is not a form element</div>\n"
156             + "  <input type='text' name='val2' id='input_disabled' disabled='disabled' value='5'>\n"
157             + "  <input type='submit' name='first_submit' value='Commit it!'>\n"
158             + "  <input type='submit' id='second_submit' value='Delete it!'>\n"
159             + "  <input type='text' name='action' value='blah'>\n"
160             + "</form>\n"
161             + "</body></html>";
162 
163         loadPageVerifyTitle2(html);
164     }
165 
166     /**
167      * <code>document.all.tags</code> is different from <code>document.forms.tags</code>!
168      * @throws Exception if the test fails
169      */
170     @Test
171     @Alerts({"false", "false"})
172     public void tags() throws Exception {
173         final String html = DOCTYPE_HTML
174             + "<html><head>\n"
175             + "<script>\n"
176             + LOG_TITLE_FUNCTION
177             + "  function test() {\n"
178             + "    log(document.all.tags != undefined);\n"
179             + "    log(document.forms.tags != undefined);\n"
180             + "  }\n"
181             + "</script></head><body onload='test()'>\n"
182             + "<form name='myForm'></form>\n"
183             + "</body></html>";
184 
185         loadPageVerifyTitle2(html);
186     }
187 
188     /**
189      * Depending on the method used, out of bound access give different responses.
190      * @throws Exception if the test fails
191      */
192     @Test
193     @Alerts({"null", "null", "undefined", "TypeError"})
194     public void outOfBoundAccess() throws Exception {
195         final String html = DOCTYPE_HTML
196             + "<html><head>\n"
197             + "<script>\n"
198             + LOG_TITLE_FUNCTION
199             + "  function test() {\n"
200             + "    var col = document.getElementsByTagName('a');\n"
201             + "    log(col.item(1));\n"
202             + "    log(col.namedItem('foo'));\n"
203             + "    log(col[1]);\n"
204             + "    try {\n"
205             + "      log(col(1));\n"
206             + "    } catch(e) { logEx(e) }\n"
207             + "  }\n"
208             + "</script></head><body onload='test()'>\n"
209             + "</body></html>";
210 
211         loadPageVerifyTitle2(html);
212     }
213 
214     /**
215      * @throws Exception if an error occurs
216      */
217     @Test
218     @Alerts({"undefined", "undefined", "undefined"})
219     public void inexistentProperties() throws Exception {
220         final String html = DOCTYPE_HTML
221             + "<html><head>\n"
222             + "<script>\n"
223             + LOG_TITLE_FUNCTION
224             + "  function test() {\n"
225             + "    var x = document.documentElement.childNodes;\n"
226             + "    log(x.split);\n"
227             + "    log(x.setInterval);\n"
228             + "    log(x.bogusNonExistentProperty);\n"
229             + "  }\n"
230             + "</script></head><body onload='test()'>\n"
231             + "</body></html>";
232         loadPageVerifyTitle2(html);
233     }
234 
235     /**
236      * @throws Exception if the test fails
237      */
238     @Test
239     @Alerts({"3", "#text", "5"})
240     public void childNodes() throws Exception {
241         final String html = DOCTYPE_HTML
242             + "<html><head>\n"
243             + "<script>\n"
244             + LOG_TITLE_FUNCTION
245             + "  function test() {\n"
246             + "    log(document.body.childNodes.length);\n"
247             + "    log(document.body.firstChild.nodeName);\n"
248             + "    log(document.getElementById('myDiv').childNodes.length);\n"
249             + "  }\n"
250             + "</script></head>\n"
251             + "<body onload='test()'> <div id='myDiv'> <div> </div> <div> </div> </div> </body>\n"
252             + "</html>";
253 
254         loadPageVerifyTitle2(html);
255     }
256 
257     /**
258      * @throws Exception if the test fails
259      */
260     @Test
261     @Alerts("object")
262     public void typeof() throws Exception {
263         final String html = DOCTYPE_HTML
264             + "<html><head>\n"
265             + "<script>\n"
266             + LOG_TITLE_FUNCTION
267             + "  function test() {\n"
268             + "    log(typeof document.getElementsByTagName('a'));\n"
269             + "  }\n"
270             + "</script></head>\n"
271             + "<body onload='test()'></body>\n"
272             + "</html>";
273 
274         loadPageVerifyTitle2(html);
275     }
276 
277     /**
278      * Verifies that dollar signs don't cause exceptions in {@link HTMLCollection} (which uses Java
279      * regex internally). Found via the MooTools unit tests.
280      *
281      * @throws Exception if the test fails
282      */
283     @Test
284     @Alerts({"[object HTMLHeadingElement]", "undefined"})
285     public void getElementWithDollarSign() throws Exception {
286         final String html
287             = "<h3 id='$h'>h</h3><script>\n"
288             + LOG_TITLE_FUNCTION
289             + "var hs = document.getElementsByTagName('h3');\n"
290             + "log(hs['$h']);\n"
291             + "log(hs['$n']);\n"
292             + "</script>";
293         loadPageVerifyTitle2(html);
294     }
295 
296     /**
297      * @throws Exception if the test fails
298      */
299     @Test
300     @Alerts({"function", "function", "function", "function"})
301     public void array_prototype() throws Exception {
302         final String html = DOCTYPE_HTML
303             + "<html><head>\n"
304             + "<script>\n"
305             + LOG_TITLE_FUNCTION
306             + "  function test() {\n"
307             + "    log(typeof Object.prototype.__defineGetter__);\n"
308             + "    log(typeof Object.prototype.__lookupGetter__);\n"
309             + "    log(typeof Array.prototype.indexOf);\n"
310             + "    log(typeof Array.prototype.map);\n"
311             + "  }\n"
312             + "</script></head>\n"
313             + "<body onload='test()'></body>\n"
314             + "</html>";
315 
316         loadPageVerifyTitle2(html);
317     }
318 
319     /**
320      * @throws Exception if the test fails
321      */
322     @Test
323     @Alerts({"function", "function", "function", "function"})
324     public void array_prototype_standards() throws Exception {
325         final String html = DOCTYPE_HTML
326             + "<html><head>\n"
327             + "<script>\n"
328             + LOG_TITLE_FUNCTION
329             + "  function test() {\n"
330             + "    log(typeof Object.prototype.__defineGetter__);\n"
331             + "    log(typeof Object.prototype.__lookupGetter__);\n"
332             + "    log(typeof Array.prototype.indexOf);\n"
333             + "    log(typeof Array.prototype.map);\n"
334             + "  }\n"
335             + "</script></head>\n"
336             + "<body onload='test()'></body>\n"
337             + "</html>";
338 
339         loadPageVerifyTitle2(html);
340     }
341 
342     /**
343      * @throws Exception if the test fails
344      */
345     @Test
346     @Alerts("true")
347     public void has() throws Exception {
348         final String html = DOCTYPE_HTML
349             + "<html><head>\n"
350             + "<script>\n"
351             + LOG_TITLE_FUNCTION
352             + "  function test() {\n"
353             + "    log(0 in document.forms);\n"
354             + "  }\n"
355             + "</script></head><body onload='test()'>\n"
356             + "<form name='myForm'></form>\n"
357             + "</body></html>";
358 
359         loadPageVerifyTitle2(html);
360     }
361 
362     /**
363      * @throws Exception if the test fails
364      */
365     @Test
366     @Alerts({"myForm", "mySecondForm"})
367     public void forOf() throws Exception {
368         final String html = DOCTYPE_HTML
369             + "<html><head>\n"
370             + "<script>\n"
371             + LOG_TITLE_FUNCTION
372             + "  function test() {\n"
373             + "    try {"
374             + "      for (f of document.forms) {\n"
375             + "        log(f.name);\n"
376             + "      }\n"
377             + "    } catch(e) { logEx(e) }\n"
378             + "  }\n"
379             + "</script>\n"
380             + "</head>\n"
381             + "<body onload='test()'>\n"
382             + "<form name='myForm'></form>\n"
383             + "<form name='mySecondForm'></form>\n"
384             + "</body></html>";
385 
386         loadPageVerifyTitle2(html);
387     }
388 
389     /**
390      * @throws Exception if the test fails
391      */
392     @Test
393     @Alerts({"myForm", "mySecondForm", "dynamicForm", "-", "myForm", "mySecondForm", "dynamicForm"})
394     public void forOfDynamicAtEnd() throws Exception {
395         final String html = DOCTYPE_HTML
396             + "<html><head>\n"
397             + "<script>\n"
398             + LOG_TITLE_FUNCTION
399             + "  function test() {\n"
400             + "    try {"
401             + "      var i = 0;\n"
402             + "      for (f of document.forms) {\n"
403             + "        i++;\n"
404             + "        if (i == 1) {\n"
405             + "          var frm = document.createElement('FORM');\n"
406             + "          frm.name = 'dynamicForm';\n"
407             + "          document.body.appendChild(frm);\n"
408             + "        }\n"
409             + "        log(f.name);\n"
410             + "      }\n"
411 
412             + "      log('-');\n"
413             + "      for (f of document.forms) {\n"
414             + "        log(f.name);\n"
415             + "      }\n"
416             + "    } catch(e) { logEx(e) }\n"
417             + "  }\n"
418             + "</script>\n"
419             + "</head>\n"
420             + "<body onload='test()'>\n"
421             + "<form name='myForm'></form>\n"
422             + "<form name='mySecondForm'></form>\n"
423             + "</body></html>";
424 
425         loadPageVerifyTitle2(html);
426     }
427 
428     /**
429      * @throws Exception if the test fails
430      */
431     @Test
432     @Alerts({"myForm", "myForm", "mySecondForm", "-", "dynamicForm", "myForm", "mySecondForm"})
433     public void forOfDynamicAtStart() throws Exception {
434         final String html = DOCTYPE_HTML
435             + "<html><head>\n"
436             + "<script>\n"
437             + LOG_TITLE_FUNCTION
438             + "  function test() {\n"
439             + "    try{\n"
440             + "      var i = 0;\n"
441             + "      for (f of document.forms) {\n"
442             + "        i++;\n"
443             + "        if (i == 1) {\n"
444             + "          var frm = document.createElement('FORM');\n"
445             + "          frm.name = 'dynamicForm';\n"
446             + "          document.body.insertBefore(frm, document.getElementsByName('myForm')[0]);\n"
447             + "        }\n"
448             + "        log(f.name);\n"
449             + "      }\n"
450 
451             + "      log('-');\n"
452             + "      for (f of document.forms) {\n"
453             + "        log(f.name);\n"
454             + "      }\n"
455             + "    } catch(e) { logEx(e) }\n"
456             + "  }\n"
457             + "</script>\n"
458             + "</head>\n"
459             + "<body onload='test()'>\n"
460             + "<form name='myForm'></form>\n"
461             + "<form name='mySecondForm'></form>\n"
462             + "</body></html>";
463 
464         loadPageVerifyTitle2(html);
465     }
466 
467     /**
468      * @throws Exception if the test fails
469      */
470     @Test
471     @Alerts("b1-button1")
472     public void item_Unknown() throws Exception {
473         item("'foo'");
474     }
475 
476     /**
477      * @throws Exception if the test fails
478      */
479     @Test
480     @Alerts("b1-button1")
481     public void item_ById() throws Exception {
482         item("'b2'");
483     }
484 
485     /**
486      * @throws Exception if the test fails
487      */
488     @Test
489     @Alerts("b1-button1")
490     public void item_ByName() throws Exception {
491         item("'button2'");
492     }
493 
494     /**
495      * @throws Exception if the test fails
496      */
497     @Test
498     @Alerts("null")
499     public void item_NegativIndex() throws Exception {
500         item("-1");
501     }
502 
503     /**
504      * @throws Exception if the test fails
505      */
506     @Test
507     @Alerts("b1-button1")
508     public void item_ZeroIndex() throws Exception {
509         item("0");
510     }
511 
512     /**
513      * @throws Exception if the test fails
514      */
515     @Test
516     @Alerts("b2-button2")
517     public void item_ValidIndex() throws Exception {
518         item("1");
519     }
520 
521     /**
522      * @throws Exception if the test fails
523      */
524     @Test
525     @Alerts("b2-button2")
526     public void item_DoubleIndex() throws Exception {
527         item("1.1");
528     }
529 
530     /**
531      * @throws Exception if the test fails
532      */
533     @Test
534     @Alerts("null")
535     public void item_InvalidIndex() throws Exception {
536         item("2");
537     }
538 
539     /**
540      * @throws Exception if the test fails
541      */
542     @Test
543     @Alerts("b2-button2")
544     public void item_IndexAsString() throws Exception {
545         item("'1'");
546     }
547 
548     /**
549      * @throws Exception if the test fails
550      */
551     @Test
552     @Alerts("b2-button2")
553     public void item_IndexDoubleAsString() throws Exception {
554         item("'1.1'");
555     }
556 
557     private void item(final String name) throws Exception {
558         final String html = DOCTYPE_HTML
559             + "<html><head>\n"
560             + "<script>\n"
561             + LOG_TITLE_FUNCTION
562             + "  function report(result) {\n"
563             + "    if (result == null || result == undefined) {\n"
564             + "      log(result);\n"
565             + "    } else if (('length' in result) && ('item' in result)) {\n"
566             + "      log('coll ' + result.length);\n"
567             + "      for(var i = 0; i < result.length; i++) {\n"
568             + "        log(result.item(i).id + '-' + result.item(i).name);\n"
569             + "      }\n"
570             + "    } else if (result.id || result.name) {\n"
571             + "      log(result.id + '-' + result.name);\n"
572             + "    } else {\n"
573             + "      log(result);\n"
574             + "    }\n"
575             + "  }\n"
576 
577             + "  function doTest() {\n"
578             + "    try {\n"
579             + "      var col = document.getElementsByTagName('button');\n"
580             + "      report(col.item(" + name + "));\n"
581             + "    } catch(e) { logEx(e); }\n"
582             + "  }\n"
583             + "</script></head>\n"
584             + "<body onload='doTest()'>\n"
585             + "  <button id='b1' name='button1'></button>\n"
586             + "  <button id='b2' name='button2'></button>\n"
587             + "</body></html>";
588 
589         loadPageVerifyTitle2(html);
590     }
591 
592     /**
593      * @throws Exception if the test fails
594      */
595     @Test
596     @Alerts("undefined")
597     public void arrayIndex_Unknown() throws Exception {
598         arrayIndex("'foo'");
599     }
600 
601     /**
602      * @throws Exception if the test fails
603      */
604     @Test
605     @Alerts("b2-button2")
606     public void arrayIndex_ById() throws Exception {
607         arrayIndex("'b2'");
608     }
609 
610     /**
611      * @throws Exception if the test fails
612      */
613     @Test
614     @Alerts("b2-button2")
615     public void arrayIndex_ByName() throws Exception {
616         arrayIndex("'button2'");
617     }
618 
619     /**
620      * @throws Exception if the test fails
621      */
622     @Test
623     @Alerts("undefined")
624     public void arrayIndex_NegativIndex() throws Exception {
625         arrayIndex("-1");
626     }
627 
628     /**
629      * @throws Exception if the test fails
630      */
631     @Test
632     @Alerts("b1-button1")
633     public void arrayIndex_ZeroIndex() throws Exception {
634         arrayIndex("0");
635     }
636 
637     /**
638      * @throws Exception if the test fails
639      */
640     @Test
641     @Alerts("b2-button2")
642     public void arrayIndex_ValidIndex() throws Exception {
643         arrayIndex("1");
644     }
645 
646     /**
647      * @throws Exception if the test fails
648      */
649     @Test
650     @Alerts("undefined")
651     public void arrayIndex_DoubleIndex() throws Exception {
652         arrayIndex("1.1");
653     }
654 
655     /**
656      * @throws Exception if the test fails
657      */
658     @Test
659     @Alerts("undefined")
660     public void arrayIndex_InvalidIndex() throws Exception {
661         arrayIndex("2");
662     }
663 
664     /**
665      * @throws Exception if the test fails
666      */
667     @Test
668     @Alerts("undefined")
669     public void arrayIndex_IndexAsString() throws Exception {
670         arrayIndex("'2'");
671     }
672 
673     private void arrayIndex(final String name) throws Exception {
674         final String html = DOCTYPE_HTML
675             + "<html><head>\n"
676             + "<script>\n"
677             + LOG_TITLE_FUNCTION
678             + "  function report(result) {\n"
679             + "    if (result == null || result == undefined) {\n"
680             + "      log(result);\n"
681             + "    } else if (('length' in result) && ('item' in result)) {\n"
682             + "      log('coll ' + result.length);\n"
683             + "      for(var i = 0; i < result.length; i++) {\n"
684             + "        log(result.item(i).id + '-' + result.item(i).name);\n"
685             + "      }\n"
686             + "    } else if (result.id || result.name) {\n"
687             + "      log(result.id + '-' + result.name);\n"
688             + "    } else {\n"
689             + "      log(result);\n"
690             + "    }\n"
691             + "  }\n"
692 
693             + "  function doTest() {\n"
694             + "    try {\n"
695             + "      var col = document.getElementsByTagName('button');\n"
696             + "      report(col[" + name + "]);\n"
697             + "    } catch(e) { logEx(e); }\n"
698             + "  }\n"
699             + "</script></head>\n"
700             + "<body onload='doTest()'>\n"
701             + "  <button id='b1' name='button1'></button>\n"
702             + "  <button id='b2' name='button2'></button>\n"
703             + "</body></html>";
704 
705         loadPageVerifyTitle2(html);
706     }
707 
708     /**
709      * @throws Exception if the test fails
710      */
711     @Test
712     @Alerts("TypeError")
713     public void functionIndex_Unknown() throws Exception {
714         functionIndex("'foo'");
715     }
716 
717     /**
718      * @throws Exception if the test fails
719      */
720     @Test
721     @Alerts("TypeError")
722     public void functionIndex_ById() throws Exception {
723         functionIndex("'b2'");
724     }
725 
726     /**
727      * @throws Exception if the test fails
728      */
729     @Test
730     @Alerts("TypeError")
731     public void functionIndex_ByName() throws Exception {
732         functionIndex("'button2'");
733     }
734 
735     /**
736      * @throws Exception if the test fails
737      */
738     @Test
739     @Alerts("TypeError")
740     public void functionIndex_NegativIndex() throws Exception {
741         functionIndex("-1");
742     }
743 
744     /**
745      * @throws Exception if the test fails
746      */
747     @Test
748     @Alerts("TypeError")
749     public void functionIndex_ZeroIndex() throws Exception {
750         functionIndex("0");
751     }
752 
753     /**
754      * @throws Exception if the test fails
755      */
756     @Test
757     @Alerts("TypeError")
758     public void functionIndex_ValidIndex() throws Exception {
759         functionIndex("1");
760     }
761 
762     /**
763      * @throws Exception if the test fails
764      */
765     @Test
766     @Alerts("TypeError")
767     public void functionIndex_DoubleIndex() throws Exception {
768         functionIndex("1.1");
769     }
770 
771     /**
772      * @throws Exception if the test fails
773      */
774     @Test
775     @Alerts("TypeError")
776     public void functionIndex_InvalidIndex() throws Exception {
777         functionIndex("2");
778     }
779 
780     /**
781      * @throws Exception if the test fails
782      */
783     @Test
784     @Alerts("TypeError")
785     public void functionIndex_IndexAsString() throws Exception {
786         functionIndex("'2'");
787     }
788 
789     private void functionIndex(final String name) throws Exception {
790         final String html = DOCTYPE_HTML
791             + "<html><head>\n"
792             + "<script>\n"
793             + LOG_TITLE_FUNCTION
794             + "  function report(result) {\n"
795             + "    if (result == null || result == undefined) {\n"
796             + "      log(result);\n"
797             + "    } else if (('length' in result) && ('item' in result)) {\n"
798             + "      log('coll ' + result.length);\n"
799             + "      for(var i = 0; i < result.length; i++) {\n"
800             + "        log(result.item(i).id + '-' + result.item(i).name);\n"
801             + "      }\n"
802             + "    } else if (result.id || result.name) {\n"
803             + "      log(result.id + '-' + result.name);\n"
804             + "    } else {\n"
805             + "      log(result);\n"
806             + "    }\n"
807             + "  }\n"
808 
809             + "  function doTest() {\n"
810             + "    try {\n"
811             + "      var col = document.getElementsByTagName('button');\n"
812             + "      report(col(" + name + "));\n"
813             + "    } catch(e) { logEx(e); }\n"
814             + "  }\n"
815             + "</script></head>\n"
816             + "<body onload='doTest()'>\n"
817             + "  <button id='b1' name='button1'></button>\n"
818             + "  <button id='b2' name='button2'></button>\n"
819             + "</body></html>";
820 
821         loadPageVerifyTitle2(html);
822     }
823 
824     /**
825      * @throws Exception if the test fails
826      */
827     @Test
828     @Alerts("null")
829     public void namedItem_Unknown() throws Exception {
830         namedItem("foo");
831     }
832 
833     /**
834      * @throws Exception if the test fails
835      */
836     @Test
837     @Alerts("button1-")
838     public void namedItem_ById() throws Exception {
839         namedItem("button1");
840     }
841 
842     /**
843      * @throws Exception if the test fails
844      */
845     @Test
846     @Alerts("-button2")
847     public void namedItem_ByName_formWithoutId() throws Exception {
848         namedItem("button2");
849     }
850 
851     /**
852      * @throws Exception if the test fails
853      */
854     @Test
855     @Alerts("b3-button3")
856     public void namedItem_ByName() throws Exception {
857         namedItem("button3");
858     }
859 
860     /**
861      * @throws Exception if the test fails
862      */
863     @Test
864     @Alerts("b4-button4_1")
865     public void namedItem_DuplicateId() throws Exception {
866         namedItem("b4");
867     }
868 
869     /**
870      * @throws Exception if the test fails
871      */
872     @Test
873     @Alerts("b5_1-button5")
874     public void namedItem_DuplicateName() throws Exception {
875         namedItem("button5");
876     }
877 
878     /**
879      * @throws Exception if the test fails
880      */
881     @Test
882     @Alerts(DEFAULT = "b6-button6",
883             CHROME = "button6-button6_2",
884             EDGE = "button6-button6_2")
885     public void namedItem_DuplicateIdName() throws Exception {
886         namedItem("button6");
887     }
888 
889     /**
890      * @throws Exception if the test fails
891      */
892     @Test
893     @Alerts("b1-button1")
894     public void namedItem_ZeroIndex() throws Exception {
895         item("0");
896     }
897 
898     /**
899      * @throws Exception if the test fails
900      */
901     @Test
902     @Alerts("b2-button2")
903     public void namedItem_ValidIndex() throws Exception {
904         item("1");
905     }
906 
907     /**
908      * @throws Exception if the test fails
909      */
910     @Test
911     @Alerts("b2-button2")
912     public void namedItem_DoubleIndex() throws Exception {
913         item("1.1");
914     }
915 
916     /**
917      * @throws Exception if the test fails
918      */
919     @Test
920     @Alerts("null")
921     public void namedItem_InvalidIndex() throws Exception {
922         item("200");
923     }
924 
925     /**
926      * @throws Exception if the test fails
927      */
928     @Test
929     @Alerts("b2-button2")
930     public void namedItem_IndexAsString() throws Exception {
931         item("'1'");
932     }
933 
934     /**
935      * @throws Exception if the test fails
936      */
937     @Test
938     @Alerts("b2-button2")
939     public void namedItem_IndexDoubleAsString() throws Exception {
940         item("'1.1'");
941     }
942 
943     private void namedItem(final String name) throws Exception {
944         final String html = DOCTYPE_HTML
945             + "<html><head>\n"
946             + "<script>\n"
947             + LOG_TITLE_FUNCTION
948             + "  function report(result) {\n"
949             + "    if (result == null || result == undefined) {\n"
950             + "      log(result);\n"
951             + "    } else if (result.id || result.name) {\n"
952             + "      log(result.id + '-' + result.name);\n"
953             + "    } else {\n"
954             + "      log('coll ' + result.length);\n"
955             + "      for(var i = 0; i < result.length; i++) {\n"
956             + "        log(result.item(i).id + '-' + result.item(i).name);\n"
957             + "      }\n"
958             + "    }\n"
959             + "   }\n"
960 
961             + "  function doTest() {\n"
962             + "    var col = document.getElementsByTagName('button');\n"
963             + "    report(col.namedItem('" + name + "'));\n"
964             + "  }\n"
965             + "</script></head>\n"
966             + "<body onload='doTest()'>\n"
967             + "  <button id='button1'></button>\n"
968             + "  <button name='button2'></button>\n"
969             + "  <button id='b3' name='button3'></button>\n"
970             + "  <button id='b4' name='button4_1'></button>\n"
971             + "  <button id='b4' name='button4_2'></button>\n"
972             + "  <button id='b5_1' name='button5'></button>\n"
973             + "  <button id='b5_2' name='button5'></button>\n"
974             + "  <button id='b6' name='button6'></button>\n"
975             + "  <button id='button6' name='button6_2'></button>\n"
976             + "</body></html>";
977 
978         loadPageVerifyTitle2(html);
979     }
980 
981     /**
982      * @throws Exception if the test fails
983      */
984     @Test
985     @Alerts({"1", "1"})
986     public void setLength() throws Exception {
987         final String html = DOCTYPE_HTML
988             + "<html>\n"
989             + "<head>\n"
990             + "<script>\n"
991             + LOG_TITLE_FUNCTION
992             + "function test() {\n"
993             + "  var x = document.children;\n"
994             + "  try {\n"
995             + "    log(x.length);\n"
996             + "    x.length = 100;\n"
997             + "    log(x.length);\n"
998             + "  } catch(e) { log('Type error'); }\n"
999             + "}\n"
1000             + "</script></head>\n"
1001             + "<body onload='test()'>\n"
1002             + "</body></html>";
1003 
1004         loadPageVerifyTitle2(html);
1005     }
1006 
1007     /**
1008      * @throws Exception if the test fails
1009      */
1010     @Test
1011     @Alerts({"1", "Type error"})
1012     public void setLengthStrictMode() throws Exception {
1013         final String html = DOCTYPE_HTML
1014             + "<html>\n"
1015             + "<head>\n"
1016             + "<script>\n"
1017             + LOG_TITLE_FUNCTION
1018             + "function test() {\n"
1019             + "  'use strict';\n"
1020             + "  var x = document.children;\n"
1021             + "  try {\n"
1022             + "    log(x.length);\n"
1023             + "    x.length = 100;\n"
1024             + "    log(x.length);\n"
1025             + "  } catch(e) { log('Type error'); }\n"
1026             + "}\n"
1027             + "</script></head>\n"
1028             + "<body onload='test()'>\n"
1029             + "</body></html>";
1030 
1031         loadPageVerifyTitle2(html);
1032     }
1033 
1034     /**
1035      * See {@link HTMLAllCollectionTest#looselyEqualToUndefined}.
1036      *
1037      * @throws Exception if the test fails
1038      */
1039     @Test
1040     @Alerts({"false", "false", "false", "false"})
1041     public void looselyEqualToUndefined() throws Exception {
1042         final String html = DOCTYPE_HTML
1043             + "<html>\n"
1044             + "<body>\n"
1045             + "<script>\n"
1046             + LOG_TITLE_FUNCTION
1047             + "  log(undefined === document.children);\n"
1048             + "  log(undefined == document.children);\n"
1049             + "  log(document.children === undefined);\n"
1050             + "  log(document.children == undefined);\n"
1051             + "</script>\n"
1052             + "</body></html>";
1053 
1054         loadPageVerifyTitle2(html);
1055     }
1056 
1057     /**
1058      * See {@link HTMLAllCollectionTest#looselyEqualToNull()}.
1059      *
1060      * @throws Exception if the test fails
1061      */
1062     @Test
1063     @Alerts({"false", "false", "false", "false"})
1064     public void looselyEqualToNull() throws Exception {
1065         final String html = DOCTYPE_HTML
1066             + "<html>\n"
1067             + "<body>\n"
1068             + "<script>\n"
1069             + LOG_TITLE_FUNCTION
1070             + "  log(null === document.children);\n"
1071             + "  log(null == document.children);\n"
1072             + "  log(document.children === null);\n"
1073             + "  log(document.children == null);\n"
1074             + "</script>\n"
1075             + "</body></html>";
1076 
1077         loadPageVerifyTitle2(html);
1078     }
1079 
1080     /**
1081      * See {@link HTMLAllCollectionTest#falsyInBooleanContexts()}.
1082      *
1083      * @throws Exception if the test fails
1084      */
1085     @Test
1086     @Alerts({"1", "7", "4", "[object HTMLCollection]", "1"})
1087     public void falsyInBooleanContexts() throws Exception {
1088         final String html = DOCTYPE_HTML
1089             + "<html>\n"
1090             + "<body>\n"
1091             + "<script>\n"
1092             + LOG_TITLE_FUNCTION
1093             + "  x = 11;\n"
1094             + "  if(document.children) { x = 1 } else { x = 7 }"
1095             + "  log(x);\n"
1096 
1097             + "  if(!document.children) { x = 1 } else { x = 7 }"
1098             + "  log(x);\n"
1099 
1100             + "  log(document.children ? 4 : 3);\n"
1101 
1102             + "  log(document.children ?? 'htmlunit');\n"
1103             + "  log(document.children?.length);\n"
1104             + "</script>\n"
1105             + "</body></html>";
1106 
1107         loadPageVerifyTitle2(html);
1108     }
1109 }