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.BrowserRunner;
20  import org.htmlunit.junit.annotation.Alerts;
21  import org.htmlunit.junit.annotation.HtmlUnitNYI;
22  import org.junit.Test;
23  import org.junit.runner.RunWith;
24  import org.openqa.selenium.WebDriver;
25  
26  /**
27   * Test class for {@link HTMLParser}.
28   *
29   * @author <a href="mailto:cse@dynabean.de">Christian Sell</a>
30   * @author Marc Guillemot
31   * @author Ahmed Ashour
32   * @author Sudhan Moghe
33   * @author Frank Danek
34   * @author Ronald Brill
35   */
36  @RunWith(BrowserRunner.class)
37  public class HTMLParser4Test extends WebDriverTestCase {
38  
39      /**
40       * Tests that inserted TBODY and TFOOT don't conflict.
41       * @throws Exception failure
42       */
43      @Test
44      @Alerts("TABLE")
45      public void table_tfoot() throws Exception {
46          final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
47              + "<html><body>"
48              + "<table><tr><td>hello</td></tr>\n"
49              + "<tfoot id='tf'><tr><td>foot</td></tr></tfoot>"
50              + "</table>\n"
51              + "<script>\n"
52              + LOG_TITLE_FUNCTION
53              + "log(document.getElementById('tf').parentNode.nodeName);\n"
54              + "</script>\n"
55              + "</body></html>";
56  
57          loadPageVerifyTitle2(html);
58      }
59  
60      /**
61       * Test for the condition when there is a <tt>&lt;form&gt;</tt> inside of a <tt>&lt;table&gt;</tt> and before
62       * a <tt>&lt;tr&gt;</tt>.
63       * @throws Exception failure
64       */
65      @Test
66      @Alerts("myForm")
67      public void badlyFormedHTML() throws Exception {
68          final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
69              + "<html><head>\n"
70              + "  <script>\n"
71              + LOG_TITLE_FUNCTION
72              + "    function test() {\n"
73              + "      log(document.getElementById('myInput').form.id);\n"
74              + "    }\n"
75              + "  </script>\n"
76              + "</head>\n"
77              + "<body onload='test()'>\n"
78              + "  <table>\n"
79              + "    <form name='myForm' action='foo' id='myForm'>\n"
80              + "      <tr><td>\n"
81              + "      <input type='text' name='myInput' id='myInput'/>\n"
82              + "      </td></tr>\n"
83              + "    </form>\n"
84              + "  </table>\n"
85              + "</body></html>";
86  
87          loadPageVerifyTitle2(html);
88      }
89  
90      /**
91       * @throws Exception failure
92       */
93      @Test
94      @Alerts({"4", "[object HTMLScriptElement]", "[object Text]",
95                  "[object HTMLTitleElement]", "[object Text]"})
96      public void badlyFormedHTML_scriptBeforeHead() throws Exception {
97          final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
98              + "<script>var i = 7;</script>\n"
99              + "<html>\n"
100             + "  <head>\n"
101             + "    <title></title>\n"
102             + "  </head>\n"
103             + "  <body>\n"
104             + "    <script>\n"
105             + LOG_TITLE_FUNCTION
106             + "      var headChildren = document.getElementsByTagName('head')[0].childNodes;\n"
107             + "      log(headChildren.length);\n"
108             + "      log(headChildren[0]);\n"
109             + "      log(headChildren[1]);\n"
110             + "      log(headChildren[2]);\n"
111             + "      log(headChildren[3]);\n"
112             + "    </script>\n"
113             + "  </body>\n"
114             + "</html>";
115 
116         loadPageVerifyTitle2(html);
117     }
118 
119     /**
120      * @throws Exception failure
121      */
122     @Test
123     public void badlyFormedHTML_wrongHeadConfusesStack() throws Exception {
124         final String html =
125             "<table\n"
126             + "<t:head>\n"
127             + "<t:head>\n"
128             + "<t:head>\n"
129             + "<t:head>\n"
130             + "<table>\n"
131             + "<table>";
132 
133         loadPage2(html);
134     }
135 
136     /**
137      * @throws Exception failure
138      */
139     @Test
140     @Alerts({"4", "[object HTMLScriptElement]", "[object Text]",
141                 "[object HTMLTitleElement]", "[object Text]"})
142     public void badlyFormedHTML_scriptBeforeDoctype() throws Exception {
143         final String html = "<script>var i = 7;</script>\n"
144             + HtmlPageTest.STANDARDS_MODE_PREFIX_
145             + "<html>\n"
146             + "  <head>\n"
147             + "    <title></title>\n"
148             + "  </head>\n"
149             + "  <body>\n"
150             + "    <script>\n"
151             + LOG_TITLE_FUNCTION
152             + "      var headChildren = document.getElementsByTagName('head')[0].childNodes;\n"
153             + "      log(headChildren.length);\n"
154             + "      log(headChildren[0]);\n"
155             + "      log(headChildren[1]);\n"
156             + "      log(headChildren[2]);\n"
157             + "      log(headChildren[3]);\n"
158             + "    </script>\n"
159             + "  </body>\n"
160             + "</html>";
161 
162         loadPageVerifyTitle2(html);
163     }
164 
165     /**
166      * @throws Exception failure
167      */
168     @Test
169     @Alerts({"4", "[object HTMLParagraphElement]", "[object Text]",
170                 "[object HTMLScriptElement]", "[object Text]"})
171     @HtmlUnitNYI(CHROME = {"3", "[object HTMLParagraphElement]", "[object HTMLScriptElement]",
172                            "[object Text]", "undefined"},
173             EDGE = {"3", "[object HTMLParagraphElement]", "[object HTMLScriptElement]",
174                     "[object Text]", "undefined"},
175             FF = {"3", "[object HTMLParagraphElement]", "[object HTMLScriptElement]",
176                   "[object Text]", "undefined"},
177             FF_ESR = {"3", "[object HTMLParagraphElement]", "[object HTMLScriptElement]",
178                       "[object Text]", "undefined"})
179     public void badlyFormedHTML_scriptAfterHtml() throws Exception {
180         final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
181             + "<html>\n"
182             + "  <head>\n"
183             + "    <script>\n"
184             + LOG_TITLE_FUNCTION
185             + "      function test() {\n"
186             + "        var headChildren = document.getElementsByTagName('body')[0].childNodes;\n"
187             + "        log(headChildren.length);\n"
188             + "        log(headChildren[0]);\n"
189             + "        log(headChildren[1]);\n"
190             + "        log(headChildren[2]);\n"
191             + "        log(headChildren[3]);\n"
192             + "      }\n"
193             + "    </script>\n"
194             + "  </head>\n"
195             + "  <body onload='test()'><p>HtmlUnit</p></body>\n"
196             + "</html>"
197             + "<script>var i = 7;</script>\n";
198 
199         loadPageVerifyTitle2(html);
200     }
201 
202     /**
203      * @throws Exception failure
204      */
205     @Test
206     @Alerts({"from script", "from body"})
207     public void badlyFormedHTML_duplicateHead() throws Exception {
208         final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
209             + "<html>\n"
210             + "  <head>\n"
211             + "  <head>\n"
212             + "    <script src='script.js'></script>\n"
213             + "  </head>\n"
214             + "  </head>\n"
215             + "  <body>\n"
216             + "    <p>HtmlUnit</p>\n"
217             + "    <script>window.name += 'from body' + '\\u00a7';</script>\n"
218             + "  </body>\n"
219             + "</html>";
220 
221         getMockWebConnection().setDefaultResponse("window.name += 'from script' + '\\u00a7'", 200, "OK", null);
222 
223         loadPage2(html);
224         verifyWindowName2(getWebDriver(), getExpectedAlerts());
225     }
226 
227     /**
228      * @throws Exception failure
229      */
230     @Test
231     @Alerts("<html><head><title>foo</title></head>"
232             + "<body><script>window.name += document.documentElement.outerHTML + '\\u00a7';</script></body></html>")
233     public void badlyFormedHTML_duplicateHeadStructure() throws Exception {
234         shutDownAll();
235 
236         final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
237             + "<html>"
238             + "<head>"
239             + "<head>"
240             + "<title>foo</title>"
241             + "</head>"
242             + "</head>"
243             + "<body>"
244             + "<script>window.name += document.documentElement.outerHTML + '\\u00a7';</script>"
245             + "</body>"
246             + "</html>";
247 
248         loadPage2(html);
249         verifyWindowName2(getWebDriver(), getExpectedAlerts());
250     }
251 
252     /**
253      * @throws Exception failure
254      */
255     @Test
256     @Alerts("<p title=\"Nimbus\ufffd X\">Nimbus\ufffd X</p>")
257     public void badlyFormedHTML_invalidNumericCharacterReference() throws Exception {
258         final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
259             + "<html>\n"
260             + "  <head>\n"
261             + "  </head>\n"
262             + "  <body>\n"
263             + "    <div id='tester'><p title='Nimbus&#84823000 X'>Nimbus&#84823000 X</p></div>\n"
264             + "    <script>\n"
265             + LOG_TITLE_FUNCTION
266             + "      log(document.getElementById('tester').innerHTML);\n"
267             + "    </script>\n"
268             + "  </body>\n"
269             + "</html>";
270 
271         loadPageVerifyTitle2(html);
272     }
273 
274     /**
275      * Test when an illegal tag is found in head as some websites do.
276      * @throws Exception failure
277      */
278     @Test
279     @Alerts("first")
280     public void unknownTagInHead() throws Exception {
281         // Note: the <meta> tag in this test is quite important because
282         // I could adapt the TagBalancer to make it work except with this <meta http-equiv...
283         // (it worked with <meta name=...)
284         final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
285             + "<html><head><mainA3>\n"
286             + "  <meta http-equiv='Content-Type' content='text/html; charset=ISO-8859-1'>\n"
287             + "  <title>first</title>\n"
288             + "  <script>\n"
289             + LOG_WINDOW_NAME_FUNCTION
290             + "    function test() {\n"
291             + "      log(document.title);\n"
292             + "    }\n"
293             + "  </script>\n"
294             + "</head>\n"
295             + "<body onload='test()'>\n"
296             + "</body></html>";
297 
298         loadPage2(html);
299         verifyWindowName2(getWebDriver(), getExpectedAlerts());
300     }
301 
302     /**
303      * @throws Exception failure
304      */
305     @Test
306     @Alerts({"false", "true"})
307     public void duplicatedAttribute() throws Exception {
308         final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
309             + "<html><head>\n"
310             + "</head>\n"
311             + "  <script>\n"
312             + LOG_TITLE_FUNCTION
313             + "    function test() {\n"
314             + "      log(document.getElementById('foo') == null);\n"
315             + "      log(document.getElementById('bla') == null);\n"
316             + "    }\n"
317             + "  </script>\n"
318             + "</head>\n"
319             + "<body onload='test()'>\n"
320             + "  <span id='foo' id='bla'></span>"
321             + "</body></html>";
322 
323         loadPageVerifyTitle2(html);
324     }
325 
326     /**
327      * @throws Exception failure
328      */
329     @Test
330     @Alerts({"1", "3", "[object HTMLScriptElement]",
331                 "[object HTMLUnknownElement]", "[object HTMLUnknownElement]", "[object HTMLFormElement]"})
332     public void namespace() throws Exception {
333         final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
334             + "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n"
335             + "<html xmlns='http://www.w3.org/1999/xhtml' xmlns:app='http://www.appcelerator.org'>\n"
336             + "<head>\n"
337             + "<script>\n"
338             + LOG_TITLE_FUNCTION
339             + "  function test() {\n"
340             + "    log(document.getElementById('script1'));\n"
341             + "    log(document.getElementById('script2'));\n"
342             + "    log(document.getElementById('message1'));\n"
343             + "    log(document.getElementById('form1'));\n"
344             + "  }\n"
345             + "</script>\n"
346             + "</head>\n"
347             + "<body onload='test()'>\n"
348             + "<script id='script1'>log(1)</script>\n"
349             + "<app:script id='script2'>log(2)</app:script>\n"
350             + "<script>log(3)</script>\n"
351             + "<app:message name='r:tasks.request' id='message1'>hello</app:message>\n"
352             + "<form id='form1' xmlns='http://org.pentaho'/>\n"
353             + "</body></html>";
354 
355         loadPageVerifyTitle2(html);
356     }
357 
358     /**
359      * @throws Exception failure
360      */
361     @Test
362     @Alerts({"1",
363                 "[object Element]", "app:script,app:script,http://www.appcelerator.org,app,script",
364                 "[object HTMLScriptElement]", "SCRIPT,SCRIPT,http://www.w3.org/1999/xhtml,null,script",
365                 "[object HTMLUnknownElement]", "APP:SCRIPT,APP:SCRIPT,http://www.w3.org/1999/xhtml,null,app:script"})
366     public void namespace2() throws Exception {
367         final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
368             + "<html xmlns='http://www.w3.org/1999/xhtml' xmlns:app='http://www.appcelerator.org'>\n"
369             + "<head>\n"
370             + "<script>\n"
371             + LOG_TITLE_FUNCTION
372             + "  function test() {\n"
373             + "    try {\n"
374             + "      div = document.createElementNS('http://www.appcelerator.org', 'app:script');\n"
375             + "      debug(div);\n"
376             + "    } catch(e) {log('createElementNS() is not defined')}\n"
377             + "    debug(document.getElementById('script1'));\n"
378             + "    debug(document.getElementById('script2'));\n"
379             + "  }\n"
380             + "  function debug(e) {\n"
381             + "    log(e);\n"
382             + "    log(e.nodeName + ',' + e.tagName + ',' + e.namespaceURI + ',' + e.prefix + ',' + e.localName);\n"
383             + "  }\n"
384             + "</script>\n"
385             + "</head>\n"
386             + "<body onload='test()'>\n"
387             + "<script id='script1'>log(1)</script>\n"
388             + "<app:script id='script2'>log(2)</app:script>\n"
389             + "</body></html>";
390 
391         loadPageVerifyTitle2(html);
392     }
393 
394     /**
395      * See issue #1830.
396      * @throws Exception failure
397      */
398     @Test
399     @Alerts({"[object HTMLHeadElement]",
400                 "HEAD,HEAD,http://www.w3.org/1999/xhtml,null,head",
401                 "[object HTMLBodyElement]", "BODY,BODY,http://www.w3.org/1999/xhtml,null,body"})
402     public void namespace_svg() throws Exception {
403         final String html =
404             "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" "
405                             + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"
406             + "<html xmlns=\"http://www.w3.org/2000/svg\">\n"
407             + "<head>\n"
408             + "<script>\n"
409             + LOG_TITLE_FUNCTION
410             + "  function test() {\n"
411             + "    elem = document.getElementsByTagName('head')[0];\n"
412             + "    debug(elem);\n"
413             + "    elem = document.getElementsByTagName('body')[0];\n"
414             + "    debug(elem);\n"
415             + "  }\n"
416             + "  function debug(e) {\n"
417             + "    log(e);\n"
418             + "    log(e.nodeName + ',' + e.tagName + ',' + e.namespaceURI + ',' + e.prefix + ',' + e.localName);\n"
419             + "  }\n"
420             + "</script>\n"
421             + "</head>\n"
422             + "<body onload='test()'>\n"
423             + "</body></html>";
424 
425         loadPageVerifyTitle2(html);
426     }
427 
428     /**
429      * See issue #1830.
430      * @throws Exception failure
431      */
432     @Test
433     @Alerts({"[object HTMLHeadElement]",
434                 "HEAD,HEAD,http://www.w3.org/1999/xhtml,null,head",
435                 "[object HTMLBodyElement]", "BODY,BODY,http://www.w3.org/1999/xhtml,null,body",
436                 "[object SVGGElement]", "g,g,http://www.w3.org/2000/svg,null,g"})
437     public void svg_withoutNamespace() throws Exception {
438         final String html =
439             "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" "
440                             + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"
441             + "<html>\n"
442             + "<head>\n"
443             + "<script>\n"
444             + LOG_TITLE_FUNCTION
445             + "  function test() {\n"
446             + "    elem = document.getElementsByTagName('head')[0];\n"
447             + "    debug(elem);\n"
448             + "    elem = document.getElementsByTagName('body')[0];\n"
449             + "    debug(elem);\n"
450             + "    elem = document.getElementById('rectangles');\n"
451             + "    debug(elem);\n"
452             + "  }\n"
453             + "  function debug(e) {\n"
454             + "    log(e);\n"
455             + "    log(e.nodeName + ',' + e.tagName + ',' + e.namespaceURI + ',' + e.prefix + ',' + e.localName);\n"
456             + "  }\n"
457             + "</script>\n"
458             + "</head>\n"
459             + "<body onload='test()'>\n"
460             + "  <svg>\n"
461             + "    <g id='rectangles'>\n"
462             + "      <rect x='1' y='11' width='8' height='8'/>\n"
463             + "    </g>\n"
464             + "  </svg>\n"
465             + "</body></html>";
466 
467         loadPageVerifyTitle2(html);
468     }
469 
470     /**
471      * See issue #719.
472      * @throws Exception failure
473      */
474     @Test
475     @Alerts("5")
476     public void svg_selfClosingTags() throws Exception {
477         final String html =
478             "<html>\n"
479             + "<head>\n"
480             + "<script>\n"
481             + LOG_TITLE_FUNCTION
482             + "  function test() {\n"
483             + "    elem = document.getElementById('tester');\n"
484             + "    log(elem.childNodes.length);\n"
485             + "  }\n"
486             + "</script>\n"
487             + "</head>\n"
488             + "<body onload='test()'>\n"
489             + "  <svg id='tester' xmlns=\"http://www.w3.org/2000/svg\">\n"
490             + "    <path fill=\"#4285F4\" />\n"
491             + "    <path fill=\"#34A853\" />\n"
492             + "  </svg>\n"
493             + "</body></html>";
494 
495         loadPageVerifyTitle2(html);
496     }
497 
498     /**
499      * Test for a case where complete HTML page is present inside DIV tag.
500      * Browsers ignore only HTML, HEAD and BODY tags. Contents of HEAD and BODY are added to
501      * the current node (DIV tag in test case).
502      *
503      * @throws Exception failure
504      */
505     @Test
506     @Alerts({"titles", "HEAD", "Outer Html", "DIV", "Inner Html",
507                 "bodyTitles", "DIV", "Inner Html",
508                 "innerDiv", "outerDiv"})
509     public void completeHtmlInsideDiv() throws Exception {
510         final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
511             + "<html><head>\n"
512             + "  <title>Outer Html</title>\n"
513             + "  <script>\n"
514             + LOG_TEXTAREA_FUNCTION
515             + "    function test() {\n"
516             + "      log('titles');\n"
517             + "      var titles = document.getElementsByTagName('title');\n"
518             + "      for(var i = 0; i < titles.length; i++) {\n"
519             + "        log(titles[i].parentNode.nodeName);\n"
520             + "        log(titles[i].text);\n"
521             + "      }\n"
522             + "      log('bodyTitles');\n"
523             + "      var bodyTitles = document.body.getElementsByTagName('title');\n"
524             + "      for(var i = 0; i < bodyTitles.length; i++) {\n"
525             + "        log(bodyTitles[i].parentNode.nodeName);\n"
526             + "        log(bodyTitles[i].text);\n"
527             + "      }\n"
528             + "      log('innerDiv');\n"
529             + "      var innerDiv = document.getElementById('innerDiv');\n"
530             + "      log(innerDiv.parentNode.id);\n"
531             + "    }\n"
532             + "  </script>\n"
533             + "</head>\n"
534             + "<body onload='test()'>\n"
535             + "  <DIV id=outerDiv>\n"
536             + "    Outer DIV\n"
537             + "    <html>\n"
538             + "      <head><title>Inner Html</title></head>\n"
539             + "      <body>\n"
540             + "        <DIV id=innerDiv>Inner DIV</DIV>\n"
541             + "      </body>\n"
542             + "    </html>\n"
543             + "  </DIV>\n"
544             + LOG_TEXTAREA
545             + "</body>\n"
546             + "</html>\n";
547 
548         loadPageVerifyTextArea2(html);
549     }
550 
551     /**
552      * Test for a case where complete HTML page is added using document.write() inside DIV tag.
553      * Browsers ignore only HTML, HEAD and BODY tags. Contents of HEAD and BODY are added to
554      * the current node (DIV tag in test case).
555      *
556      * @throws Exception failure
557      */
558     @Test
559     @Alerts({"titles", "HEAD", "Outer Html", "DIV", "Inner Html",
560                 "bodyTitles", "DIV", "Inner Html",
561                 "innerDiv", "outerDiv"})
562     public void writeCompleteHtmlInsideDIV() throws Exception {
563         final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
564             + "<html><head>\n"
565             + "  <title>Outer Html</title>\n"
566             + "  <script>\n"
567             + LOG_TEXTAREA_FUNCTION
568             + "    function test() {\n"
569             + "      log('titles');\n"
570             + "      var titles = document.getElementsByTagName('title');\n"
571             + "      for(var i = 0; i < titles.length; i++) {\n"
572             + "        log(titles[i].parentNode.nodeName);\n"
573             + "        log(titles[i].text);\n"
574             + "      }\n"
575             + "      log('bodyTitles');\n"
576             + "      var bodyTitles = document.body.getElementsByTagName('title');\n"
577             + "      for(var i = 0; i < bodyTitles.length; i++) {\n"
578             + "        log(bodyTitles[i].parentNode.nodeName);\n"
579             + "        log(bodyTitles[i].text);\n"
580             + "      }\n"
581             + "      log('innerDiv');\n"
582             + "      var innerDiv = document.getElementById('innerDiv');\n"
583             + "      log(innerDiv.parentNode.id);\n"
584             + "    }\n"
585             + "  </script>\n"
586             + "</head>\n"
587             + "<body onload='test()'>\n"
588             + "  <DIV id=outerDiv>\n"
589             + "     Outer DIV\n"
590             + "     <script>\n"
591             + "       document.write('<html><head><title>Inner Html</title></head>"
592             + "         <body><DIV id=innerDiv>Inner DIV</DIV></body></html>');\n"
593             + "     </script>\n"
594             + "  </DIV>\n"
595             + LOG_TEXTAREA
596             + "</body>\n"
597             + "</html>\n";
598 
599         loadPageVerifyTextArea2(html);
600     }
601 
602     /**
603      * Test for a case where complete HTML page is set in innerHTML of DIV tag.
604      * Behavior is same for any TAG inside body including BODY tag.
605      * Browsers ignore only HTML, HEAD and BODY tags. Contents of BODY are added to
606      * the current node (DIV tag in test case).
607      *
608      * @throws Exception failure
609      */
610     @Test
611     @Alerts({"titles", "HEAD", "Outer Html", "DIV", "Inner Html",
612                 "bodyTitles", "DIV", "Inner Html",
613                 "innerDiv", "outerDiv"})
614     public void setCompleteHtmlToDIV_innerHTML() throws Exception {
615         final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
616             + "<html><head>\n"
617             + "  <title>Outer Html</title>\n"
618             + "  <script>\n"
619             + LOG_TEXTAREA_FUNCTION
620             + "    function test() {\n"
621             + "      log('titles');\n"
622             + "      var titles = document.getElementsByTagName('title');\n"
623             + "      for(var i = 0; i < titles.length; i++) {\n"
624             + "        log(titles[i].parentNode.nodeName);\n"
625             + "        log(titles[i].text);\n"
626             + "      }\n"
627             + "      log('bodyTitles');\n"
628             + "      var bodyTitles = document.body.getElementsByTagName('title');\n"
629             + "      for(var i = 0; i < bodyTitles.length; i++) {\n"
630             + "        log(bodyTitles[i].parentNode.nodeName);\n"
631             + "        log(bodyTitles[i].text);\n"
632             + "      }\n"
633             + "      log('innerDiv');\n"
634             + "      var innerDiv = document.getElementById('innerDiv');\n"
635             + "      log(innerDiv.parentNode.id);\n"
636             + "    }\n"
637             + "  </script>\n"
638             + "</head>\n"
639             + "<body onload='test()'>\n"
640             + "  <DIV id=outerDiv>\n"
641             + "     Outer DIV\n"
642             + "  </DIV>\n"
643             + "    <script>\n"
644             + "    document.getElementById('outerDiv').innerHTML ="
645             + "        '<html><head><title>Inner Html</title></head>"
646             + "        <body><DIV id=innerDiv>Inner DIV</DIV></body></html>';\n"
647             + "    </script>\n"
648             + LOG_TEXTAREA
649             + "</body>\n"
650             + "</html>\n";
651 
652         loadPageVerifyTextArea2(html);
653     }
654 
655     /**
656      * Test for a case where complete HTML page is set in innerHTML of DIV tag.
657      * Behavior is same for any TAG inside body including BODY tag.
658      * Browsers ignore only HTML, HEAD and BODY tags. Contents of BODY are added to
659      * the current node (DIV tag in test case).
660      *
661      * @throws Exception failure
662      */
663     @Test
664     @Alerts({"titles", "HEAD", "Outer Html", "DIV", "Inner Html",
665                 "bodyTitles", "DIV", "Inner Html",
666                 "innerDiv", "outerDiv"})
667     public void setCompleteHtmlToDIV2_innerHTML() throws Exception {
668         final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
669             + "<html><head>\n"
670             + "  <title>Outer Html</title>\n"
671             + "  <script>\n"
672             + LOG_TEXTAREA_FUNCTION
673             + "    function test() {\n"
674             + "      log('titles');\n"
675             + "      var titles = document.getElementsByTagName('title');\n"
676             + "      for(var i = 0; i < titles.length; i++) {\n"
677             + "        log(titles[i].parentNode.nodeName);\n"
678             + "        log(titles[i].text);\n"
679             + "      }\n"
680             + "      log('bodyTitles');\n"
681             + "      var bodyTitles = document.body.getElementsByTagName('title');\n"
682             + "      for(var i = 0; i < bodyTitles.length; i++) {\n"
683             + "        log(bodyTitles[i].parentNode.nodeName);\n"
684             + "        log(bodyTitles[i].text);\n"
685             + "      }\n"
686             + "      log('innerDiv');\n"
687             + "      var innerDiv = document.getElementById('innerDiv');\n"
688             + "      log(innerDiv.parentNode.id);\n"
689             + "    }\n"
690             + "  </script>\n"
691             + "</head>\n"
692             + "<body onload='test()'>\n"
693             + "  <DIV id=outerDiv>\n"
694             + "     Outer DIV\n"
695             + "  </DIV>\n"
696             + "    <script>\n"
697             + "    document.getElementById('outerDiv').innerHTML ="
698             + "        '<html><head>"
699             + "            <title>Inner Html</title>"
700             + "            <meta name=\"author\" content=\"John Doe\">"
701             + "        </head>"
702             + "        <body><DIV id=innerDiv>Inner DIV</DIV></body></html>';\n"
703             + "    </script>\n"
704             + LOG_TEXTAREA
705             + "</body>\n"
706             + "</html>\n";
707 
708         loadPageVerifyTextArea2(html);
709     }
710 
711     /**
712      * Test for a case where complete HTML page is set in innerHTML of HTML tag.
713      * Others replace the current content of the HTML node by the new one.
714      *
715      * @throws Exception failure
716      */
717     @Test
718     @Alerts({"titles", "HEAD", "Inner Html", "misc", "true", "BODY"})
719     @HtmlUnitNYI(CHROME = {"titles", "HTML", "Inner Html", "misc", "false", "HTML"},
720             EDGE = {"titles", "HTML", "Inner Html", "misc", "false", "HTML"},
721             FF = {"titles", "HTML", "Inner Html", "misc", "false", "HTML"},
722             FF_ESR = {"titles", "HTML", "Inner Html", "misc", "false", "HTML"})
723     // currently the content of HEAD and BODY are added directly to HTML
724     public void setCompleteHtmlToHTML_innerHTML() throws Exception {
725         final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
726             + "<html><head>\n"
727             + "  <title>Outer Html</title>\n"
728             + "  <script>\n"
729             + LOG_WINDOW_NAME_FUNCTION
730             + "    function test() {\n"
731             + "      log('titles');\n"
732             + "      var titles = document.getElementsByTagName('title');\n"
733             + "      for(var i = 0; i < titles.length; i++) {\n"
734             + "        log(titles[i].parentNode.nodeName);\n"
735             + "        log(titles[i].text);\n"
736             + "      }\n"
737             + "      log('misc');\n"
738             + "      log(document.body != null);\n"
739             + "      var innerDiv = document.getElementById('innerDiv');\n"
740             + "      if (innerDiv != null) {\n"
741             + "        log(innerDiv.parentNode.nodeName);\n"
742             + "      }\n"
743             + "    }\n"
744             + "  </script>\n"
745             + "</head>\n"
746             + "<body onload='test()'>\n"
747             + "  <DIV id=outerDiv>\n"
748             + "    Outer DIV\n"
749             + "  </DIV>\n"
750             + "  <script>\n"
751             + "    try {\n"
752             + "      document.getElementsByTagName('html')[0].innerHTML ="
753             + "        '<html><head><title>Inner Html</title></head>"
754             + "        <body><DIV id=innerDiv>Inner DIV</DIV></body></html>';\n"
755             + "    } catch(e) { logEx(e) }\n"
756             + "  </script>\n"
757             + "</body>\n"
758             + "</html>\n";
759 
760         loadPage2(html);
761         verifyWindowName2(getWebDriver(), getExpectedAlerts());
762     }
763 
764     /**
765      * @throws Exception failure
766      */
767     @Test
768     @Alerts("before1after1\\nbefore2after2\\nbefore3after3\\nbefore4after4\\nbefore5after5\\nbefore6<>after6")
769     @HtmlUnitNYI(
770             CHROME = "before1after1\\sbefore2after2\\sbefore3after3\\sbefore4after4\\sbefore5after5\\sbefore6<>after6",
771             EDGE = "before1after1\\sbefore2after2\\sbefore3after3\\sbefore4after4\\sbefore5after5\\sbefore6<>after6",
772             FF = "before1after1\\sbefore2after2\\sbefore3after3\\sbefore4after4\\sbefore5after5\\sbefore6<>after6",
773             FF_ESR = "before1after1\\sbefore2after2\\sbefore3after3\\sbefore4after4\\sbefore5after5\\sbefore6<>after6")
774     public void specialComments() throws Exception {
775         final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
776                 + "<html><head>\n"
777                 + "  <script>\n"
778                 + LOG_TITLE_FUNCTION_NORMALIZE
779                 + "    function test() {\n"
780                 + "      var body = document.getElementById('tester');\n"
781                 + "      var text = body.innerText;"
782                 + "      log(text);\n"
783                 + "    }\n"
784                 + "  </script>\n"
785                 + "</head>\n"
786                 + "<body id='tester' onload='test()'>\n"
787                 + "  <div>before1<!---->after1</div>\n"
788                 + "  <!--good comment-->\n"
789                 + "  <div>before2<!--->after2</div>\n"
790                 + "  <!--good comment-->\n"
791                 + "  <div>before3<!-->after3</div>\n"
792                 + "  <!--good comment-->\n"
793                 + "  <div>before4<!->after4</div>\n"
794                 + "  <!--good comment-->\n"
795                 + "  <div>before5<!>after5</div>\n"
796                 + "  <!--good comment-->\n"
797                 + "  <div>before6<>after6</div>\n"
798                 + "  <!--good comment-->\n"
799                 + "</body>\n"
800                 + "</html>\n";
801 
802         loadPageVerifyTitle2(html, getExpectedAlerts());
803     }
804 
805     /**
806      * @throws Exception failure
807      */
808     @Test
809     @Alerts("before1after1\\nbefore2\\nbefore3\\nbefore4after4\\nbefore5after5\\nbefore6<\\s>after6")
810     @HtmlUnitNYI(CHROME = "before1after1\\sbefore2\\sbefore3\\sbefore4after4\\sbefore5after5\\sbefore6<\\s>after6",
811             EDGE = "before1after1\\sbefore2\\sbefore3\\sbefore4after4\\sbefore5after5\\sbefore6<\\s>after6",
812             FF = "before1after1\\sbefore2\\sbefore3\\sbefore4after4\\sbefore5after5\\sbefore6<\\s>after6",
813             FF_ESR = "before1after1\\sbefore2\\sbefore3\\sbefore4after4\\sbefore5after5\\sbefore6<\\s>after6")
814     public void specialComments2() throws Exception {
815         final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
816                 + "<html><head>\n"
817                 + "  <script>\n"
818                 + LOG_TITLE_FUNCTION_NORMALIZE
819                 + "    function test() {\n"
820                 + "      var body = document.getElementById('tester');\n"
821                 + "      var text = body.innerText;"
822                 + "      log(text);\n"
823                 + "    }\n"
824                 + "  </script>\n"
825                 + "</head>\n"
826                 + "<body id='tester' onload='test()'>\n"
827                 + "  <div>before1<!-- -->after1</div>\n"
828                 + "  <!--good comment-->\n"
829                 + "  <div>before2<!-- ->after2</div>\n"
830                 + "  <!--good comment-->\n"
831                 + "  <div>before3<!-- >after3</div>\n"
832                 + "  <!--good comment-->\n"
833                 + "  <div>before4<!- >after4</div>\n"
834                 + "  <!--good comment-->\n"
835                 + "  <div>before5<! >after5</div>\n"
836                 + "  <!--good comment-->\n"
837                 + "  <div>before6< >after6</div>\n"
838                 + "  <!--good comment-->\n"
839                 + "</body>\n"
840                 + "</html>\n";
841 
842         loadPageVerifyTitle2(html);
843     }
844 
845     /**
846      * @throws Exception failure
847      */
848     @Test
849     @Alerts({"1", "[object HTMLTemplateElement]", "[object DocumentFragment]",
850              "[object HTMLTableElement]", "[object HTMLTableSectionElement]"})
851     public void tableInsideTemplate_addTBody() throws Exception {
852         final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
853             + "<html>\n"
854             + "  <head>\n"
855             + "    <script>\n"
856             + LOG_TITLE_FUNCTION
857             + "      function test() {\n"
858             + "        var bodyChildren = document.getElementsByTagName('body')[0].childNodes;\n"
859             + "        log(bodyChildren.length);\n"
860             + "        log(bodyChildren[0]);\n"
861             + "        log(bodyChildren[0].content);\n"
862 
863             + "        if(bodyChildren[0].content === undefined) { return; }"
864             + "        var table = bodyChildren[0].content.firstElementChild;\n"
865             + "        log(table);\n"
866             + "        log(table.firstChild);\n"
867             + "      }\n"
868             + "    </script>\n"
869             + "  </head>\n"
870             + "  <body onload='test()'><template><table><tr><td>42</td></tr></table></template></body>"
871             + "</html>";
872 
873         loadPageVerifyTitle2(html);
874     }
875 
876     /**
877      * @throws Exception failure
878      */
879     @Test
880     @Alerts({"1", "[object HTMLTemplateElement]", "[object DocumentFragment]",
881              "[object HTMLUListElement]"})
882     public void tableInsideTemplate_addTBodyMoveUlOut() throws Exception {
883         final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
884             + "<html>\n"
885             + "  <head>\n"
886             + "    <script>\n"
887             + LOG_TITLE_FUNCTION
888             + "      function test() {\n"
889             + "        var bodyChildren = document.getElementsByTagName('body')[0].childNodes;\n"
890             + "        log(bodyChildren.length);\n"
891             + "        log(bodyChildren[0]);\n"
892             + "        log(bodyChildren[0].content);\n"
893 
894             + "        if(bodyChildren[0].content === undefined) { return; }"
895             + "        var ul = bodyChildren[0].content.firstElementChild;\n"
896             + "        log(ul);\n"
897             + "      }\n"
898             + "    </script>\n"
899             + "  </head>\n"
900             + "  <body onload='test()'><template><table><ul></ul><tr><td>42</td></tr></table></template></body>"
901             + "</html>";
902 
903         loadPageVerifyTitle2(html);
904     }
905 
906     /**
907      * @throws Exception failure
908      */
909     @Test
910     @Alerts({"1", "[object HTMLElement]", "1", "[object Text]",
911              "<!-- anchor linking to external file -->"
912                      + "<a href='https://www.htmlunit.org/'>External Link</a>"})
913     public void noscript() throws Exception {
914         final String html =
915             "<html>\n"
916             + "  <head>\n"
917             + "    <script>\n"
918             + LOG_TITLE_FUNCTION
919             + "      function test() {\n"
920             + "        var bodyChildren = document.getElementsByTagName('body')[0].childNodes;\n"
921             + "        log(bodyChildren.length);\n"
922             + "        log(bodyChildren[0]);\n"
923 
924             + "        var noscript = bodyChildren[0];\n"
925             + "        log(noscript.childNodes.length);\n"
926             + "        log(noscript.childNodes[0]);\n"
927             + "        log(noscript.childNodes[0].textContent);\n"
928             + "      }\n"
929             + "    </script>\n"
930             + "  </head>\n"
931             + "  <body onload='test()'>"
932                     + "<noscript>"
933                     + "<!-- anchor linking to external file -->"
934                     + "<a href='https://www.htmlunit.org/'>External Link</a>"
935                     + "</noscript>"
936             + "</body>"
937             + "</html>";
938 
939         loadPageVerifyTitle2(html);
940     }
941 
942     /**
943      * @throws Exception failure
944      */
945     @Test
946     @Alerts({"3", "[object HTMLElement]", "[object HTMLDivElement]", "[object Text]",
947              "1", "[object Text]", "<!-- ",
948              "1", "<div>abc</div>",
949              "0", "-->"})
950     public void noscriptBrokenComment() throws Exception {
951         final String html =
952             "<html>\n"
953             + "  <head>\n"
954             + "    <script>\n"
955             + LOG_TITLE_FUNCTION
956             + "      function test() {\n"
957             + "        var bodyChildren = document.getElementsByTagName('body')[0].childNodes;\n"
958             + "        log(bodyChildren.length);\n"
959             + "        log(bodyChildren[0]);\n"
960             + "        log(bodyChildren[1]);\n"
961             + "        log(bodyChildren[2]);\n"
962 
963             + "        var noscript = bodyChildren[0];\n"
964             + "        log(noscript.childNodes.length);\n"
965             + "        log(noscript.childNodes[0]);\n"
966             + "        log(noscript.childNodes[0].textContent);\n"
967 
968             + "        var div = bodyChildren[1];\n"
969             + "        log(div.childNodes.length);\n"
970             + "        log(div.outerHTML);\n"
971 
972             + "        var txt = bodyChildren[2];\n"
973             + "        log(txt.childNodes.length);\n"
974             + "        log(txt.textContent);\n"
975             + "      }\n"
976             + "    </script>\n"
977             + "  </head>\n"
978             + "  <body onload='test()'>"
979                     + "<noscript>"
980                     + "<!-- </noscript><div>abc</div>-->"
981                     + "</noscript>"
982             + "</body>"
983             + "</html>";
984 
985         loadPageVerifyTitle2(html);
986     }
987 
988     /**
989      * @exception Exception If the test fails
990      */
991     @Test
992     @Alerts("ti </head> <body> 1234 </body> </html>")
993     public void badTagInHead() throws Exception {
994         final String html =
995                 "<html>\n"
996                 + "<head><foo/>\n"
997                 + "<title>ti\n"
998                 + "</head>\n"
999                 + "<body>\n"
1000                 + "1234\n"
1001                 + "</body>\n"
1002                 + "</html>";
1003 
1004         final WebDriver driver = loadPage2(html);
1005         assertEquals(getExpectedAlerts()[0], driver.getTitle());
1006     }
1007 }