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.html.parser;
16  
17  import org.htmlunit.WebDriverTestCase;
18  import org.htmlunit.html.HtmlPageTest;
19  import org.htmlunit.junit.annotation.Alerts;
20  import org.htmlunit.junit.annotation.HtmlUnitNYI;
21  import org.junit.jupiter.api.Test;
22  
23  /**
24   * Test class for {@link HTMLParser}.
25   *
26   * @author Ahmed Ashour
27   * @author Ronald Brill
28   * @author Marc Guillemot
29   * @author Frank Danek
30   */
31  public class HTMLParser2Test extends WebDriverTestCase {
32  
33      /**
34       * @throws Exception failure
35       */
36      @Test
37      public void qualified_body() throws Exception {
38          final String html = "<html><body>\n"
39              + "<wicket:body>whatever</wicket:body>\n"
40              + "</body></html>";
41          loadPage2(html);
42      }
43  
44      /**
45       * Malformed HTML:
46       * &lt;/td&gt;some text&lt;/tr&gt; =&gt; text comes before the table.
47       *
48       * @throws Exception on test failure
49       */
50      @Test
51      @Alerts({"\\nbeforeafter", "undefined", "undefined"})
52      public void htmlTableTextAroundTD() throws Exception {
53          final String html = "<html><head>\n"
54              + "<script>\n"
55              + LOG_TITLE_FUNCTION_NORMALIZE
56              + "function test() {\n"
57              + "  var tmp = document.getElementById('testDiv');\n"
58              + "  tmp = tmp.firstChild;\n"
59              + "  log(tmp.data);\n"
60              + "  tmp = tmp.nextSibling;\n"
61              + "  log(tmp.data);\n"
62              + "  tmp = tmp.nextSibling;\n"
63              + "  log(tmp.tagName);\n"
64              + "}\n"
65              + "</script>\n"
66              + "</head>\n"
67              + "<body onload='test()'><div id='testDiv'>\n"
68              + "<table><tr>before<td></td>after</tr></table>\n"
69              + "</div></body></html>";
70  
71          loadPageVerifyTitle2(html);
72      }
73  
74      /**
75       * Malformed HTML:
76       * &lt;/td&gt;some text&lt;/tr&gt; =&gt; text comes before the table.
77       *
78       * @throws Exception on test failure
79       */
80      @Test
81      @Alerts({"\\nabcbeforeafter", "undefined", "undefined"})
82      public void htmlTableTextAroundTD2() throws Exception {
83          final String html = "<html><head>\n"
84              + "<script>\n"
85              + LOG_TITLE_FUNCTION_NORMALIZE
86              + "function test() {\n"
87              + "  var tmp = document.getElementById('testDiv');\n"
88              + "  tmp = tmp.firstChild;\n"
89              + "  log(tmp.data);\n"
90              + "  tmp = tmp.nextSibling;\n"
91              + "  log(tmp.data);\n"
92              + "  tmp = tmp.nextSibling;\n"
93              + "  log(tmp.tagName);\n"
94              + "}\n"
95              + "</script>\n"
96              + "</head>\n"
97              + "<body onload='test()'><div id='testDiv'>\n"
98              + "abc<table><tr>before<td></td>after</tr></table>\n"
99              + "</div></body></html>";
100 
101         loadPageVerifyTitle2(html);
102     }
103 
104     /**
105      * Malformed HTML:
106      * &lt;/td&gt;some text&lt;/tr&gt; =&gt; text comes before the table.
107      *
108      * @throws Exception on test failure
109      */
110     @Test
111     @Alerts({"\\nbe", "B-for", "e", "STRONG-aft", "er", "[object\\sHTMLTableElement]"})
112     public void htmlTableTagsAroundTD() throws Exception {
113         final String html = "<html><head>\n"
114             + "<script>\n"
115             + LOG_TITLE_FUNCTION_NORMALIZE
116             + "function test() {\n"
117             + "  var tmp = document.getElementById('testDiv');\n"
118             + "  tmp = tmp.firstChild;\n"
119             + "  log(tmp.data);\n"
120 
121             + "  tmp = tmp.nextSibling;\n"
122             + "  log(tmp.nodeName + '-' + tmp.firstChild.data);\n"
123 
124             + "  tmp = tmp.nextSibling;\n"
125             + "  log(tmp.data);\n"
126 
127             + "  tmp = tmp.nextSibling;\n"
128             + "  log(tmp.nodeName + '-' + tmp.firstChild.data);\n"
129 
130             + "  tmp = tmp.nextSibling;\n"
131             + "  log(tmp.data);\n"
132 
133             + "  log(tmp.nextSibling);\n"
134             + "}\n"
135             + "</script>\n"
136             + "</head>\n"
137             + "<body onload='test()'><div id='testDiv'>\n"
138             + "<table><tr>be<b>for</b>e<td></td><strong>aft</strong>er</tr></table>\n"
139             + "</div></body></html>";
140 
141         loadPageVerifyTitle2(html);
142     }
143 
144     /**
145      * @throws Exception on test failure
146      */
147     @Test
148     @Alerts("TABLE")
149     public void htmlTableWhitespaceAroundTD() throws Exception {
150         final String html = "<html><head>\n"
151             + "<script>\n"
152             + LOG_TITLE_FUNCTION
153             + "function test() {\n"
154             + "  var tmp = document.getElementById('testDiv');\n"
155             + "  tmp = tmp.firstChild;\n"
156             + "  log(tmp.tagName);\n"
157             + "}\n"
158             + "</script>\n"
159             + "</head>\n"
160             + "<body onload='test()'><div id='testDiv'><table><tr> <td></td> </tr></table>\n"
161             + "</div></body></html>";
162 
163         loadPageVerifyTitle2(html);
164     }
165 
166     /**
167      * @throws Exception on test failure
168      */
169     @Test
170     @Alerts({"H2", "TABLE"})
171     public void htmlTableMisplacedElementInside() throws Exception {
172         final String html = "<html><head>\n"
173             + "<script>\n"
174             + LOG_TITLE_FUNCTION
175             + "function test() {\n"
176             + "  var tmp = document.body.firstChild;\n"
177             + "  log(tmp.tagName);\n"
178             + "  tmp = document.body.firstChild.nextSibling;\n"
179             + "  log(tmp.tagName);\n"
180             + "}\n"
181             + "</script>\n"
182             + "</head>\n"
183             + "<body onload='test()'><table><tr><td></td><h2>Wrong Place</h2></tr></table>\n"
184             + "</body></html>";
185 
186         loadPageVerifyTitle2(html);
187     }
188 
189     /**
190      * @throws Exception on test failure
191      */
192     @Test
193     @Alerts({"H2", "TABLE"})
194     public void htmlTableMisplacedElementInside2() throws Exception {
195         final String html = "<html><head>\n"
196             + "<script>\n"
197             + LOG_TITLE_FUNCTION
198             + "function test() {\n"
199             + "  var tmp = document.body.firstChild;\n"
200             + "  log(tmp.tagName);\n"
201             + "  tmp = document.body.firstChild.nextSibling;\n"
202             + "  log(tmp.tagName);\n"
203             + "}\n"
204             + "</script>\n"
205             + "</head>\n"
206             + "<body onload='test()'><table><tr><td></td><h2>Wrong Place</h2><td></td></tr></table>\n"
207             + "</body></html>";
208 
209         loadPageVerifyTitle2(html);
210     }
211 
212     /**
213      * @throws Exception on test failure
214      */
215     @Test
216     @Alerts({"H2", "TABLE"})
217     public void htmlTableMisplacedElementInside3() throws Exception {
218         final String html = "<html><head>\n"
219             + "<script>\n"
220             + LOG_TITLE_FUNCTION
221             + "function test() {\n"
222             + "  var tmp = document.body.firstChild;\n"
223             + "  log(tmp.tagName);\n"
224             + "  tmp = document.body.firstChild.nextSibling;\n"
225             + "  log(tmp.tagName);\n"
226             + "}\n"
227             + "</script>\n"
228             + "</head>\n"
229             + "<body onload='test()'><table><tr><td></td></tr><h2>Wrong Place</h2></table>\n"
230             + "</body></html>";
231 
232         loadPageVerifyTitle2(html);
233     }
234 
235     /**
236      * @throws Exception on test failure
237      */
238     @Test
239     @Alerts({"H2", "TABLE"})
240     public void htmlTableMisplacedElementInside4() throws Exception {
241         final String html = "<html><head>\n"
242             + "<script>\n"
243             + LOG_TITLE_FUNCTION
244             + "function test() {\n"
245             + "  var tmp = document.body.firstChild;\n"
246             + "  log(tmp.tagName);\n"
247             + "  tmp = document.body.firstChild.nextSibling;\n"
248             + "  log(tmp.tagName);\n"
249             + "}\n"
250             + "</script>\n"
251             + "</head>\n"
252             + "<body onload='test()'><table><tr><td></td></tr><h2>Wrong Place</h2><tr><td></td></tr></table>\n"
253             + "</body></html>";
254 
255         loadPageVerifyTitle2(html);
256     }
257 
258     /**
259      * @throws Exception if the test fails
260      */
261     @Test
262     @Alerts({"H2", "TABLE", "H2", "TABLE", "SCRIPT"})
263     public void htmlTableMisplacedElementInside5() throws Exception {
264         final String html = "<html><head>\n"
265                 + "</head>\n"
266                 + "<body>"
267                 +   "<table>"
268                 +     "<tr>"
269                 +       "<h2>X</h2>"
270                 +       "<td>1st</td>"
271                 +     "</tr>\n"
272 
273                 +       "<table>"
274                 +         "<tr>"
275                 +           "<h2>Y</h2>"
276                 +           "<td>1st</td>"
277                 +         "</tr>"
278                 +       "</table>\n"
279                 +   "</table>\n"
280 
281                 + "<script>\n"
282                 + LOG_TITLE_FUNCTION
283                 + "   var tmp = document.body.firstChild;\n"
284                 + "   while (tmp != null) {if (tmp.tagName) log(tmp.tagName); tmp = tmp.nextSibling;}\n"
285                 + "</script>\n"
286                 + "</body></html>";
287         loadPageVerifyTitle2(html);
288     }
289 
290     /**
291      * @throws Exception if the test fails
292      */
293     @Test
294     @Alerts({"H2#x", "TABLE", "H2#y", "TABLE", "H2#z", "TABLE", "H2#a", "TABLE", "SCRIPT"})
295     public void htmlTableMisplacedElementInside6() throws Exception {
296         final String html = "<html><head>\n"
297                 + "</head>\n"
298                 + "<body>"
299                 +   "<table>"
300                 +     "<tr>"
301                 +       "<h2 id='x'>X</h2>"
302                 +       "<td>x</td>"
303                 +     "</tr>\n"
304 
305                 +       "<table>"
306                 +         "<tr>"
307                 +           "<h2 id='y'>Y</h2>"
308                 +           "<td>y</td>"
309                 +         "</tr>"
310                 +       "</table>\n"
311 
312                 +     "<h2 id='z'>Z</h2>"
313                 +     "<table><tr><td>z</td></table>\n"
314                 +   "</table>\n"
315 
316                 +   "<h2 id='a'>A</h2>"
317                 +   "<table><tr><td>a</td></table>\n"
318                 +   "</table>\n"
319 
320                 + "<script>\n"
321                 + LOG_TITLE_FUNCTION
322                 + "   var tmp = document.body.firstChild;\n"
323                 + "   while (tmp != null) {\n"
324                 + "     if (tmp.tagName) {\n"
325                 + "       log(tmp.tagName + (tmp.id ? '#' + tmp.id : ''));\n"
326                 + "     }\n"
327                 + "     tmp = tmp.nextSibling;\n"
328                 + "   }\n"
329                 + "</script>\n"
330                 + "</body></html>";
331         loadPageVerifyTitle2(html);
332     }
333 
334     /**
335      * @throws Exception if the test fails
336      */
337     @Test
338     @Alerts({"4", "TABLE", "TABLE", "SPAN", "SCRIPT"})
339     public void tableInsideTable() throws Exception {
340         final String html = "<html><head>\n"
341                 + "</head>\n"
342                 + "<body>"
343                 +   "<table>"
344                 +     "<tr>"
345                 +       "<td>x</td>"
346                 +     "</tr>\n"
347 
348                 +       "<table>"
349                 +         "<tr>"
350                 +           "<td>y</td>"
351                 +         "</tr>"
352                 +       "</table>\n"
353 
354                       // the second table has closed the first one
355                 +     "<tr>"
356                 +       "<td><span>z</span></td>"
357                 +     "</tr>\n"
358                 +   "</table>\n"
359 
360                 + "<script>\n"
361                 + LOG_TITLE_FUNCTION
362                 + "  log(document.body.children.length);\n"
363                 + "  log(document.body.children[0].tagName);\n"
364                 + "  log(document.body.children[1].tagName);\n"
365                 + "  log(document.body.children[2].tagName);\n"
366                 + "  log(document.body.children[3].tagName);\n"
367                 + "</script>\n"
368                 + "</body></html>";
369         loadPageVerifyTitle2(html);
370     }
371 
372     /**
373      * @throws Exception if the test fails
374      */
375     @Test
376     @Alerts({"4", "TABLE", "TABLE", "SPAN", "SCRIPT"})
377     public void tableInsideTableTr() throws Exception {
378         final String html = "<html><head>\n"
379                 + "</head>\n"
380                 + "<body>"
381                 +   "<table>"
382                 +     "<tr>"
383                 +       "<td>x</td>"
384                 +     "</tr>\n"
385 
386                 +     "<tr>"
387                 +       "<table>"
388                 +         "<tr>"
389                 +           "<td>y</td>"
390                 +         "</tr>"
391                 +       "</table>\n"
392                 +     "</tr>\n"
393 
394                       // the second table has closed the first one
395                 +     "<tr>"
396                 +       "<td><span>z</span></td>"
397                 +     "</tr>\n"
398                 +   "</table>\n"
399 
400                 + "<script>\n"
401                 + LOG_TITLE_FUNCTION
402                 + "  log(document.body.children.length);\n"
403                 + "  log(document.body.children[0].tagName);\n"
404                 + "  log(document.body.children[1].tagName);\n"
405                 + "  log(document.body.children[2].tagName);\n"
406                 + "  log(document.body.children[3].tagName);\n"
407                 + "</script>\n"
408                 + "</body></html>";
409         loadPageVerifyTitle2(html);
410     }
411 
412     /**
413      * @throws Exception if the test fails
414      */
415     @Test
416     @Alerts({"2", "TABLE", "SCRIPT"})
417     public void tableInsideTableTd() throws Exception {
418         final String html = "<html><head>\n"
419                 + "</head>\n"
420                 + "<body>"
421                 +   "<table>"
422                 +     "<tr>"
423                 +       "<td>x</td>"
424                 +     "</tr>\n"
425 
426                 +     "<tr><td>"
427                 +       "<table>"
428                 +         "<tr>"
429                 +           "<td>y</td>"
430                 +         "</tr>"
431                 +       "</table>\n"
432                 +     "</td></tr>\n"
433 
434                       // the second table has closed the first one
435                 +     "<tr>"
436                 +       "<td><span>z</span></td>"
437                 +     "</tr>\n"
438                 +   "</table>\n"
439 
440                 + "<script>\n"
441                 + LOG_TITLE_FUNCTION
442                 + "  log(document.body.children.length);\n"
443                 + "  log(document.body.children[0].tagName);\n"
444                 + "  log(document.body.children[1].tagName);\n"
445                 + "</script>\n"
446                 + "</body></html>";
447         loadPageVerifyTitle2(html);
448     }
449 
450     /**
451      * @throws Exception if the test fails
452      */
453     @Test
454     @Alerts({"1", "TABLE"})
455     public void scriptInsideTable() throws Exception {
456         final String html = "<html><head>\n"
457                 + "</head>\n"
458                 + "<body>"
459                 +   "<table>"
460                 +     "<tr>"
461                 +       "<td>1st</td>"
462                 +     "</tr>\n"
463 
464                 + "<script>\n"
465                 + LOG_TITLE_FUNCTION
466                 + "  log(document.body.childNodes.length);\n"
467                 + "  var tmp = document.body.firstChild;\n"
468                 + "  while (tmp != null) {if (tmp.tagName) log(tmp.tagName); tmp = tmp.nextSibling;}\n"
469                 + "</script>\n"
470                 + "</body></html>";
471         loadPageVerifyTitle2(html);
472     }
473 
474     /**
475      * @throws Exception if the test fails
476      */
477     @Test
478     @Alerts({"1", "TABLE"})
479     public void scriptInsideTableRows() throws Exception {
480         final String html = "<html><head>\n"
481                 + "</head>\n"
482                 + "<body>"
483                 +   "<table>"
484                 +     "<tr>"
485                 +       "<td>1st</td>"
486                 +     "</tr>\n"
487                 +     "<tr>"
488 
489                 + "<script>\n"
490                 + LOG_TITLE_FUNCTION
491                 + "  log(document.body.childNodes.length);\n"
492                 + "  var tmp = document.body.firstChild;\n"
493                 + "  while (tmp != null) {if (tmp.tagName) log(tmp.tagName); tmp = tmp.nextSibling;}\n"
494                 + "</script>\n"
495 
496                 +     "</tr>\n"
497                 + "</body></html>";
498         loadPageVerifyTitle2(html);
499     }
500 
501     /**
502      * @throws Exception if the test fails
503      */
504     @Test
505     @Alerts({"1", "TABLE"})
506     public void scriptInsideTableData() throws Exception {
507         final String html = "<html><head>\n"
508                 + "</head>\n"
509                 + "<body>"
510                 +   "<table>"
511                 +     "<tr>"
512                 +       "<td>1st</td>"
513                 +     "</tr>\n"
514                 +     "<tr>"
515                 +       "<td>"
516 
517                 + "<script>\n"
518                 + LOG_TITLE_FUNCTION
519                 + "  log(document.body.childNodes.length);\n"
520                 + "  var tmp = document.body.firstChild;\n"
521                 + "  while (tmp != null) {if (tmp.tagName) log(tmp.tagName); tmp = tmp.nextSibling;}\n"
522                 + "</script>\n"
523 
524                 +       "</td>"
525                 +     "</tr>\n"
526                 + "</body></html>";
527         loadPageVerifyTitle2(html);
528     }
529 
530     /**
531      * @throws Exception on test failure
532      */
533     @Test
534     @Alerts({"TABLE", "TABLE"})
535     public void htmlTableClosesAnother() throws Exception {
536         final String html = "<html><head>\n"
537             + "<script>\n"
538             + "function test() {\n"
539             + LOG_TITLE_FUNCTION
540             + "  var tmp = document.body.firstChild;\n"
541             + "  log(tmp.tagName);\n"
542             + "  tmp = document.body.firstChild.nextSibling;\n"
543             + "  log(tmp.tagName);\n"
544             + "}\n"
545             + "</script>\n"
546             + "</head>\n"
547 
548             + "<body onload='test()'>"
549             + "<table>"
550             +   "<tr>"
551             +     "<td>a</td>"
552             +   "</tr>"
553 
554             +   "<table>"
555             +     "<tr>"
556             +       "<td>o</td>"
557             +     "</tr>"
558             +   "</table>\n"
559 
560             + "</table>\n"
561             + "</body></html>";
562 
563         loadPageVerifyTitle2(html);
564     }
565 
566     /**
567      * @throws Exception on test failure
568      */
569     @Test
570     @Alerts({"TABLE", "TABLE"})
571     public void htmlTableClosesAnotherInsideTr() throws Exception {
572         final String html = "<html><head>\n"
573             + "<script>\n"
574             + LOG_TITLE_FUNCTION
575             + "function test() {\n"
576             + "  var tmp = document.body.firstChild;\n"
577             + "  log(tmp.tagName);\n"
578             + "  tmp = document.body.firstChild.nextSibling;\n"
579             + "  log(tmp.tagName);\n"
580             + "}\n"
581             + "</script>\n"
582             + "</head>\n"
583 
584             + "<body onload='test()'>"
585             + "<table>"
586             +   "<tr>"
587 
588             +   "<table>"
589             +     "<tr>"
590             +       "<td>o</td>"
591             +     "</tr>"
592             +   "</table>\n"
593 
594             +   "</tr>"
595             + "</table>\n"
596             + "</body></html>";
597 
598         loadPageVerifyTitle2(html);
599     }
600 
601 
602     /**
603      * @throws Exception on test failure
604      */
605     @Test
606     @Alerts({"TABLE", "null"})
607     public void htmlTableNotClosesOnotherInsideTd() throws Exception {
608         final String html = "<html><head>\n"
609             + "<script>\n"
610             + LOG_TITLE_FUNCTION
611             + "function test() {\n"
612             + "  var tmp = document.body.firstChild;\n"
613             + "  log(tmp.tagName);\n"
614             + "  tmp = document.body.firstChild.nextSibling;\n"
615             + "  log(tmp);\n"
616             + "}\n"
617             + "</script>\n"
618             + "</head>\n"
619 
620             + "<body onload='test()'>"
621             + "<table>"
622             +   "<tr>"
623             +     "<td><span>"
624 
625             +   "<table>"
626             +     "<tr>"
627             +       "<td>o</td>"
628             +     "</tr>"
629             +   "</table>\n"
630 
631             +     "</span></td>"
632             +   "</tr>"
633             + "</table>"
634             + "</body></html>";
635 
636         loadPageVerifyTitle2(html);
637     }
638 
639     /**
640      * @throws Exception on test failure
641      */
642     @Test
643     @Alerts("Hi!")
644     public void unclosedCommentsInScript() throws Exception {
645         final String html = "<html><body>\n"
646             + "<script><!--\n"
647             + "window.document.title = 'Hi!§';\n"
648             + "</script>\n"
649             + "<h1>Ho!§</h1>\n"
650             + "<!-- some comment -->\n"
651             + "<h1>Hu!</h1>\n"
652             + "</body></html>";
653 
654         loadPageVerifyTitle2(html);
655     }
656 
657     /**
658      * This tests for a bug in NekoHTML.
659      * @throws Exception on test failure
660      */
661     @Test
662     @Alerts({"P", "BUTTON", "DIV"})
663     public void divInsideButton() throws Exception {
664         final String html = "<html><head>\n"
665             + "<script>\n"
666             + LOG_TITLE_FUNCTION
667             + "function test() {\n"
668             + "try {\n"
669             + "  var tmp = document.getElementById('myP');\n"
670             + "  log(tmp.tagName);\n"
671             + "  tmp = tmp.firstChild;\n"
672             + "  log(tmp.tagName);\n"
673             + "  tmp = tmp.firstChild.tagName;\n"
674             + "  log(tmp);\n"
675             + "} catch(e) { logEx(e); }\n"
676             + "}\n"
677             + "</script>\n"
678             + "</head>\n"
679             + "<body onload='test()'>\n"
680             + "<p id='myP'><button><div>Test</div></button></p>\n"
681             + "</body></html>";
682 
683         loadPageVerifyTitle2(html);
684     }
685 
686     /**
687      * This tests for a bug in NekoHTML.
688      * @throws Exception on test failure
689      */
690     @Test
691     @Alerts({"P", "LABEL", "OBJECT"})
692     public void objectInsideLabel() throws Exception {
693         final String html = "<html><head>\n"
694             + "<script>\n"
695             + LOG_TITLE_FUNCTION
696             + "function test() {\n"
697             + "try {\n"
698             + "  var tmp = document.getElementById('myP');\n"
699             + "  log(tmp.tagName);\n"
700             + "  tmp = tmp.firstChild;\n"
701             + "  log(tmp.tagName);\n"
702             + "  tmp = tmp.firstChild.tagName;\n"
703             + "  log(tmp);\n"
704             + "} catch(e) { logEx(e); }\n"
705             + "}\n"
706             + "</script>\n"
707             + "</head>\n"
708             + "<body onload='test()'>\n"
709             + "<p id='myP'><label><object></object></label></p>\n"
710             + "</body></html>";
711 
712         loadPageVerifyTitle2(html);
713     }
714 
715     /**
716      * This tests for a bug in NekoHTML.
717      * Without setting a property NekoHTML closes all inline tags
718      * when a table start tag is detected. This is ok from the spec
719      * but different with real browsers.
720      *
721      * @throws Exception on test failure
722      */
723     @Test
724     public void tableClosesInlineTags() throws Exception {
725         final String html = "<html><head>\n"
726                 + "<script>\n"
727                 + "  function test() {\n"
728                 + "    var myP = document.getElementById('myP');\n"
729                 + "    for(var i = 0; i < myP.childNodes.length; i++) {\n"
730                 + "      var myNode = myP.childNodes[i];\n"
731                 + "      if (myNode.nodeType == 1 && myNode.nodeName != 'TABLE') {\n"
732                 + "        var hasTable = false;\n"
733                 + "        for(var j = 0; j<myNode.childNodes.length; j++) {\n"
734                 + "          if (myNode.childNodes[j].nodeName == 'TABLE') {\n"
735                 + "            hasTable = true;\n"
736                 + "          }\n"
737                 + "        }\n"
738                 + "        if (!hasTable) {\n"
739                 + "          log('<' + myNode.nodeName + '>');\n"
740                 + "        }\n"
741                 + "      }\n"
742                 + "    }\n"
743                 + "  }\n"
744                 + "</script>\n"
745                 + "</head>\n"
746                 + "\n"
747                 + "<body onload='test()'>\n"
748                 + "\n"
749                 + "<p id='myP'>\n"
750                 + "  <a><table></table></a>\n"
751                 + "  <abbr><table></table></abbr>\n"
752                 + "  <acronym><table></table></acronym>\n"
753                 + "  <b><table></table></b>\n"
754                 + "  <bdo><table></table></bdo>\n"
755                 + "  <big><table></table></big>\n"
756                 + "  <button><table></table></button>\n"
757                 + "  <cite><table></table></cite>\n"
758                 + "  <code><table></table></code>\n"
759                 + "  <del><table></table></del>\n"
760                 + "  <dfn><table></table></dfn>\n"
761                 + "  <em><table></table></em>\n"
762                 + "  <font><table></table></font>\n"
763                 + "  <i><table></table></i>\n"
764                 + "  <ins><table></table></ins>\n"
765                 + "  <kbd><table></table></kbd>\n"
766                 + "  <label><table></table></label>\n"
767                 + "  <map><table></table></map>\n"
768                 + "  <q><table></table></q>\n"
769                 + "  <samp><table></table></samp>\n"
770                 + "  <small><table></table></small>\n"
771                 + "  <span><table></table></span>\n"
772                 + "  <strong><table></table></strong>\n"
773                 + "  <sub><table></table></sub>\n"
774                 + "  <sup><table></table></sup>\n"
775                 + "  <tt><table></table></tt>\n"
776                 + "  <var><table></table></var>\n"
777                 + "</p>\n"
778                 + "\n"
779                 + "</body>\n"
780                 + "</html>";
781 
782         loadPageVerifyTitle2(html);
783     }
784 
785     /**
786      * @throws Exception on test failure
787      */
788     @Test
789     @Alerts({"2", "2", "3", "3", "2", "2", "3", "2", "2", "3", "2", "2"})
790     public void childNodes_p_parent() throws Exception {
791         final String html = "<html><head>\n"
792             + "<script>\n"
793             + LOG_TITLE_FUNCTION
794             + "function test() {\n"
795             + "  for (var i = 1; i <= 12; i++) {\n"
796             + "    log(document.getElementById('p' + i).childNodes.length);\n"
797             + "  }\n"
798             + "}\n"
799             + "</script>\n"
800             + "</head><body onload='test()'>\n"
801             + "<p id='p1'><input> </p>\n"
802             + "<p id='p2'> <input></p>\n"
803             + "<p id='p3'> <input> </p>\n"
804             + "<p id='p4'> <a></a> </p>\n"
805             + "<p id='p5'><a></a> </p>\n"
806             + "<p id='p6'> <a></a></p>\n"
807             + "<p id='p7'> <a href='hi'>there</a> </p>\n"
808             + "<p id='p8'><a href='hi'>there</a> </p>\n"
809             + "<p id='p9'> <a href='hi'>there</a></p>\n"
810             + "<p id='p10'> <a href='hi'></a> </p>\n"
811             + "<p id='p11'><a href='hi'></a> </p>\n"
812             + "<p id='p12'> <a href='hi'></a></p>\n"
813             + "</body></html>";
814 
815         loadPageVerifyTitle2(html);
816     }
817 
818     /**
819      * @throws Exception on test failure
820      */
821     @Test
822     @Alerts({"2", "2", "3", "3", "2", "2", "3", "2", "2", "3", "2", "2", "3"})
823     public void childNodes_f() throws Exception {
824         final String html = "<html><head>\n"
825             + "<script>\n"
826             + LOG_TITLE_FUNCTION
827             + "function test() {\n"
828             + "  for (var i = 1; i <= 13; i++) {\n"
829             + "    log(document.getElementById('f' + i).childNodes.length);\n"
830             + "  }\n"
831             + "}\n"
832             + "</script>\n"
833             + "</head><body onload='test()'>\n"
834             + "<form id='f1'><input> </form>\n"
835             + "<form id='f2'> <input></form>\n"
836             + "<form id='f3'> <input> </form>\n"
837             + "<form id='f4'> <a></a> </form>\n"
838             + "<form id='f5'><a></a> </form>\n"
839             + "<form id='f6'> <a></a></form>\n"
840             + "<form id='f7'> <a href='hi'>there</a> </form>\n"
841             + "<form id='f8'><a href='hi'>there</a> </form>\n"
842             + "<form id='f9'> <a href='hi'>there</a></form>\n"
843             + "<form id='f10'> <a href='hi'></a> </form>\n"
844             + "<form id='f11'><a href='hi'></a> </form>\n"
845             + "<form id='f12'> <a href='hi'></a></form>\n"
846             + "<form id='f13'> <div> </div> </form>\n"
847             + "</body></html>";
848         loadPageVerifyTitle2(html);
849     }
850 
851     /**
852      * Conditional comments are removed from the dom.
853      * @throws Exception on test failure
854      */
855     @Test
856     @Alerts({"<!--[if gt IE 11]><br><![endif]-->", "<!--[if lt IE 11]><br><![endif]-->"})
857     public void ieConditionalCommentsNotInDom() throws Exception {
858         final String html = "<html><head>\n"
859             + "<script>\n"
860             + LOG_TITLE_FUNCTION
861             + "function test() {\n"
862             + "try {\n"
863             + "  var tmp = document.getElementById('my1');\n"
864             + "  log(tmp.innerHTML);\n"
865             + "  tmp = document.getElementById('my2');\n"
866             + "  log(tmp.innerHTML);\n"
867             + "} catch(e) { logEx(e); }\n"
868             + "}\n"
869             + "</script>\n"
870             + "</head>\n"
871             + "<body onload='test()'>\n"
872             + "  <div id='my1'><!--[if gt IE 11]><br><![endif]--></div>\n"
873             + "  <div id='my2'><!--[if lt IE 11]><br><![endif]--></div>\n"
874             + "</body></html>";
875 
876         loadPageVerifyTitle2(html);
877     }
878 
879     /**
880      * Test incorrect parsing of LABEL within A tag. Fixed in NekoHTML 1.9.19.
881      * @see <a href="http://sf.net/p/htmlunit/bugs/1547/">Bug #1547</a>
882      * @throws Exception on test failure
883      */
884     @Test
885     @Alerts("1")
886     public void acceptLabelWithinAnchor() throws Exception {
887         final String html = "<html><body>\n"
888             + "<a href='foo'>\n"
889             + "<label>XL</label>\n"
890             + "</a>\n"
891             + "<script>\n"
892             + LOG_TITLE_FUNCTION
893             + "log(document.links.length)\n"
894             + "</script>\n"
895             + "</body></html>";
896 
897         loadPageVerifyTitle2(html);
898     }
899 
900     /**
901      * @see <a href="http://sf.net/p/htmlunit/bugs/1423/">Bug #1423</a>
902      * @throws Exception on test failure
903      */
904     @Test
905     @Alerts({"<var data=\"f\"> <a href=\"#\">a</a> <div>d</div> <li>l</li> </var> ", "3"})
906     public void varInsideUl() throws Exception {
907         final String html =
908             HtmlPageTest.STANDARDS_MODE_PREFIX_
909             + "<html>\n"
910             + "<head></head>\n"
911             + "<body>\n"
912             + "<ul id='myUl'>\n"
913             +   "<var data='f'>\n"
914             +     "<a href='#'>a</a>\n"
915             +     "<div>d</div>\n"
916             +     "<li>l</li>\n"
917             +   "</var>\n"
918             + "</ul>\n"
919             + "<script>\n"
920             + LOG_TITLE_FUNCTION
921             + "  var tmp = document.getElementById('myUl');\n"
922             + "  log(tmp.innerHTML);\n"
923             + "  log(tmp.childNodes.length);\n"
924             + "</script>\n"
925             + "</body></html>";
926 
927         loadPageVerifyTitle2(html);
928     }
929 
930     /**
931      * @see <a href="http://sf.net/p/htmlunit/bugs/1046/">Bug #1046</a>
932      * @throws Exception on test failure
933      */
934     @Test
935     @Alerts({"<table> <tbody><tr> <td>data</td> </tr> </tbody></table> ", "3"})
936     public void tableInsideAnchor() throws Exception {
937         final String html =
938             HtmlPageTest.STANDARDS_MODE_PREFIX_
939             + "<html>\n"
940             + "<head></head>\n"
941             + "<body>\n"
942             +  "<a id='myA' href='#'>\n"
943             +   "<table>\n"
944             +     "<tr>\n"
945             +       "<td>data</td>\n"
946             +     "</tr>\n"
947             +   "</table>\n"
948             +  "</a>\n"
949             + "<script>\n"
950             + LOG_TITLE_FUNCTION
951             + "  var tmp = document.getElementById('myA');\n"
952             + "  log(tmp.innerHTML);\n"
953             + "  log(tmp.childNodes.length);\n"
954             + "</script>\n"
955             + "</body></html>";
956 
957         loadPageVerifyTitle2(html);
958     }
959 
960     /**
961      * Issue #1825.
962      * @throws Exception on test failure
963      */
964     @Test
965     @Alerts({"<iframe></div></body></html></iframe>", "1",
966              "1", "IFRAME", "null", "1",
967              "3", "#text", "</div></body></html>"})
968     @HtmlUnitNYI(CHROME = {"<iframe>&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</iframe>", "1",
969                            "1", "IFRAME", "null", "1",
970                            "3", "#text", "</div></body></html>"},
971             EDGE = {"<iframe>&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</iframe>", "1",
972                     "1", "IFRAME", "null", "1",
973                     "3", "#text", "</div></body></html>"},
974             FF = {"<iframe>&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</iframe>", "1",
975                   "1", "IFRAME", "null", "1",
976                   "3", "#text", "</div></body></html>"},
977             FF_ESR = {"<iframe>&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;</iframe>", "1",
978                       "1", "IFRAME", "null", "1",
979                       "3", "#text", "</div></body></html>"})
980     public void selfClosingIframe() throws Exception {
981         final String html = "<html><head>\n"
982             + "<script>\n"
983             + LOG_TITLE_FUNCTION
984             + "function test() {\n"
985             + "try {\n"
986             + "  var tmp = document.getElementById('myDiv');\n"
987             + "  log(tmp.innerHTML);\n"
988             + "  log(tmp.childNodes.length);\n"
989 
990             + "  var child = tmp.childNodes[0];\n"
991             + "  log(child.nodeType);\n"
992             + "  log(child.nodeName);\n"
993             + "  log(child.nodeValue);\n"
994 
995             + "  log(child.childNodes.length);\n"
996             + "  var child2 = child.childNodes[0];\n"
997             + "  log(child2.nodeType);\n"
998             + "  log(child2.nodeName);\n"
999             + "  log(child2.nodeValue);\n"
1000 
1001             + "} catch(e) { logEx(e); }\n"
1002             + "}\n"
1003             + "</script>\n"
1004             + "</head>\n"
1005             + "<body onload='test()'>\n"
1006             + "  <div id='myDiv'><iframe/></div>"
1007             + "</body></html>";
1008 
1009         loadPageVerifyTitle2(html);
1010     }
1011 
1012     /**
1013      * Issue #1842.
1014      * @throws Exception on test failure
1015      */
1016     @Test
1017     @Alerts({"2", "1-1#DL", "0-1#DT", "1-1#DL", "0-1#DT"})
1018     public void dlShouldCloseDt() throws Exception {
1019         final String html = "<html><head>\n"
1020             + "<script>\n"
1021             + LOG_TITLE_FUNCTION
1022             + "function test() {\n"
1023             + "try {\n"
1024             + "  var tmp = document.getElementById('myBody');\n"
1025             + "  log(tmp.childNodes.length);\n"
1026 
1027             + "  var child = tmp.childNodes[0];\n"
1028             + "  log(child.childNodes.length + '-' + child.nodeType + '#' +child.nodeName);\n"
1029 
1030             + "  var child2 = child.childNodes[0];\n"
1031             + "  log(child2.childNodes.length + '-' + child2.nodeType + '#' +child2.nodeName);\n"
1032 
1033             + "  var child = tmp.childNodes[1];\n"
1034             + "  log(child.childNodes.length + '-' + child.nodeType + '#' +child.nodeName);\n"
1035 
1036             + "  var child2 = child.childNodes[0];\n"
1037             + "  log(child2.childNodes.length + '-' + child2.nodeType + '#' +child2.nodeName);\n"
1038 
1039             + "} catch(e) { logEx(e); }\n"
1040             + "}\n"
1041             + "</script>\n"
1042             + "</head>\n"
1043             + "<body id='myBody' onload='test()'>"
1044             + "<DL><DT></DL>"
1045             + "<DL><DT></DL>"
1046             + "</body></html>";
1047 
1048         loadPageVerifyTitle2(html);
1049     }
1050 
1051     /**
1052      * As of version 2.43.0 this fails with a stack overflow.
1053      *
1054      * @throws Exception on test failure
1055      */
1056     @Test
1057     @Alerts({"1", "1-1#P"})
1058     public void innerHtmlParagraph() throws Exception {
1059         final String html = "<html><head>\n"
1060             + "<script>\n"
1061             + LOG_TITLE_FUNCTION
1062             + "function test() {\n"
1063             + "try {\n"
1064             + "  var tmp = document.getElementById('myP');\n"
1065             + "  tmp.innerHTML = '<p>HtmlUnit</p>';\n"
1066             + "  log(tmp.childNodes.length);\n"
1067 
1068             + "  var child = tmp.childNodes[0];\n"
1069             + "  log(child.childNodes.length + '-' + child.nodeType + '#' + child.nodeName);\n"
1070 
1071             + "} catch(e) { logEx(e); }\n"
1072             + "}\n"
1073             + "</script>\n"
1074             + "</head>\n"
1075             + "<body onload='test()'>"
1076             + "  <p id='myP'>Test</p>"
1077             + "</body></html>";
1078 
1079         loadPageVerifyTitle2(html);
1080     }
1081 
1082     /**
1083      * @throws Exception on test failure
1084      */
1085     @Test
1086     @Alerts({"P", "A para", "STYLE", "graph."})
1087     public void styleInsideP() throws Exception {
1088         final String html = "<html><head>\n"
1089             + "<script>\n"
1090             + LOG_TITLE_FUNCTION
1091             + "function test() {\n"
1092             + "try {\n"
1093             + "  var tmp = document.getElementById('myP');\n"
1094             + "  log(tmp.tagName);\n"
1095 
1096             + "  tmp = tmp.firstChild;\n"
1097             + "  log(tmp.textContent);\n"
1098 
1099             + "  tmp = tmp.nextSibling;\n"
1100             + "  log(tmp.tagName);\n"
1101 
1102             + "  tmp = tmp.nextSibling;\n"
1103             + "  log(tmp.textContent);\n"
1104             + "} catch(e) { logEx(e); }\n"
1105             + "}\n"
1106             + "</script>\n"
1107             + "</head>\n"
1108             + "<body onload='test()'>\n"
1109             + "  <p id='myP'>A para<style>h1 {color:red;} p {color:blue;}</style>graph.</p>\n"
1110             + "</body></html>";
1111 
1112         loadPageVerifyTitle2(html);
1113     }
1114 
1115     /**
1116      * @throws Exception on test failure
1117      */
1118     @Test
1119     @Alerts({"TABLE", "STYLE"})
1120     public void styleInsideTable() throws Exception {
1121         final String html = "<html><head>\n"
1122             + "<script>\n"
1123             + LOG_TITLE_FUNCTION
1124             + "function test() {\n"
1125             + "try {\n"
1126             + "  var tmp = document.getElementById('myP');\n"
1127             + "  log(tmp.tagName);\n"
1128 
1129             + "  tmp = tmp.firstChild;\n"
1130             + "  log(tmp.tagName);\n"
1131             + "} catch(e) { logEx(e); }\n"
1132             + "}\n"
1133             + "</script>\n"
1134             + "</head>\n"
1135             + "<body onload='test()'>\n"
1136             + "  <table id='myP'><style>h1 {color:red;} p {color:blue;}</style></table>\n"
1137             + "</body></html>";
1138 
1139         loadPageVerifyTitle2(html);
1140     }
1141 
1142     /**
1143      * @throws Exception if the test fails
1144      */
1145     @Test
1146     @Alerts({"2", "8"})
1147     public void childNodesDynamicUpdateDuringParsing() throws Exception {
1148         final String html =
1149                 "<html><head>\n"
1150                 + "<script>\n"
1151                 + LOG_TITLE_FUNCTION
1152                 + "</script>\n"
1153                 + "</head>\n"
1154                 + "<body id='id1'>\n"
1155                 + "<script>\n"
1156                 + "  var childNodes = document.getElementById('id1').childNodes;\n"
1157                 + "  log(childNodes.length);\n"
1158                 + "</script>\n"
1159                 + "<h1>My First Heading</h1>\n"
1160                 + "<p>My first paragraph.</p>\n"
1161                 + "<script>\n"
1162                 + "  log(childNodes.length);\n"
1163                 + "</script>\n"
1164                 + "</body></html>";
1165 
1166         loadPageVerifyTitle2(html);
1167     }
1168 }