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