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.By;
25  import org.openqa.selenium.WebDriver;
26  
27  /**
28   * Set of tests for ill formed HTML code.
29   *
30   * @author Marc Guillemot
31   * @author Sudhan Moghe
32   * @author Ahmed Ashour
33   * @author Frank Danek
34   * @author Carsten Steul
35   * @author Ronald Brill
36   */
37  @RunWith(BrowserRunner.class)
38  public class MalformedHtmlTest extends WebDriverTestCase {
39  
40      /**
41       * @throws Exception if the test fails
42       */
43      @Test
44      @Alerts({"in test", "BODY"})
45      public void bodyAttributeWhenOpeningBodyGenerated() throws Exception {
46          final String content = "<html><head><script>\n"
47              + LOG_TITLE_FUNCTION
48              + "function test() {\n"
49              + "  log('in test');\n"
50              + "  log(document.getElementById('span1').parentNode.tagName);\n"
51              + "}\n"
52              + "</script>\n"
53              + "<span id='span1'>hello</span>\n"
54              + "</head><body onload='test()'>\n"
55              + "</body></html>";
56  
57          loadPageVerifyTitle2(content);
58      }
59  
60      /**
61       * @throws Exception if the test fails
62       */
63      @Test
64      @Alerts({"2", "3", "text3", "text3", "null"})
65      public void lostFormChildren() throws Exception {
66          final String content = "<html><head><script>\n"
67              + LOG_TITLE_FUNCTION
68              + "function test() {\n"
69              + "  log(document.forms[0].childNodes.length);\n"
70              + "  log(document.forms[0].elements.length);\n"
71              + "  log(document.forms[0].elements[2].name);\n"
72              + "  log(document.forms[0].text3.name);\n"
73              + "  log(document.getElementById('text4').form);\n"
74              + "}\n"
75              + "</script>\n"
76              + "</head><body onload='test()'>\n"
77              + "<div>\n"
78              + "<form action='foo'>"
79              + "<input type='text' name='text1'/>"
80              + "<input type='text' name='text2'/>"
81              + "</div>\n"
82              + "<input type='text' name='text3'/>\n"
83              + "</form>\n"
84              + "<input type='text' name='text4' id='text4'/>\n"
85              + "</body></html>";
86  
87          loadPageVerifyTitle2(content);
88      }
89  
90      /**
91       * @throws Exception if the test fails
92       */
93      @Test
94      @Alerts("Test document")
95      public void titleAfterInsertedBody() throws Exception {
96          final String content = "<html><head>\n"
97              + "<noscript><link href='other.css' rel='stylesheet' type='text/css'></noscript>\n"
98              + "<title>Test document§</title>\n"
99              + "</head><body>\n"
100             + "foo"
101             + "</body></html>";
102 
103         loadPageVerifyTitle2(content);
104     }
105 
106     /**
107      * @throws Exception if the test fails
108      */
109     @Test
110     @Alerts("Test document")
111     public void titleTwice() throws Exception {
112         final String content = "<html><head>\n"
113             + "<title>Test document§</title>\n"
114             + "<title>2nd title</title>\n"
115             + "</head><body>\n"
116             + "foo"
117             + "</body></html>";
118 
119         loadPageVerifyTitle2(content);
120     }
121 
122     /**
123      * Test for <a href="https://sourceforge.net/p/nekohtml/bugs/68/">Bug 68</a>.
124      * In fact this is not fully correct because IE (6 at least) does something very strange
125      * and keeps the DIV in TABLE but wraps it in a node without name.
126      * @throws Exception if the test fails
127      */
128     @Test
129     @Alerts({"DIV", "TABLE"})
130     public void div_between_table_and_tr() throws Exception {
131         final String html = "<html><head><script>\n"
132             + LOG_TITLE_FUNCTION
133             + "function test() {\n"
134             + "  var c1 = document.body.firstChild;\n"
135             + "  log(c1.tagName);\n"
136             + "  log(c1.nextSibling.tagName);\n"
137             + "}\n"
138             + "</script>\n"
139             + "</head><body onload='test()'>"
140             + "<table><div>hello</div>\n"
141             + "<tr><td>world</td></tr></table>\n"
142             + "</body></html>";
143 
144         loadPageVerifyTitle2(html);
145     }
146 
147     /**
148      * @throws Exception if the test fails
149      */
150     @Test
151     @Alerts("hello")
152     public void script_between_head_and_body() throws Exception {
153         final String content = "<html><head></head><script>\n"
154             + LOG_TITLE_FUNCTION
155             + "log('hello');\n"
156             + "</script>\n"
157             + "<body>\n"
158             + "</body></html>";
159 
160         loadPageVerifyTitle2(content);
161     }
162 
163     /**
164      * Tests that wrong formed HTML code is parsed like browsers do.
165      * @throws Exception if the test fails
166      */
167     @Test
168     @Alerts("12345")
169     public void wrongHtml_TagBeforeHtml() throws Exception {
170         final String html = "<div>\n"
171             + "<html>\n"
172             + "<head>\n"
173             + "<script>\n"
174             + LOG_TITLE_FUNCTION
175             + "var toto = 12345;\n"
176             + "</script>\n"
177             + "</head>\n"
178             + "<body onload='log(toto)'>\n"
179             + "blabla"
180             + "</body>\n"
181             + "</html>";
182 
183         loadPageVerifyTitle2(html);
184     }
185 
186     /**
187      * Regression test for bug #889.
188      * @throws Exception if an error occurs
189      */
190     @Test
191     @Alerts("0")
192     public void missingSingleQuote() throws Exception {
193         final String html = "<html>\n"
194                 + "<head>\n"
195                 + "<script>\n"
196                 + LOG_TITLE_FUNCTION
197                 + "  function test() {\n"
198                 + "    log(document.links.length);\n"
199                 + "  }\n"
200                 + "  </script>\n"
201                 + "</head>\n"
202                 + "<body onload='test()'>\n"
203                 + "  Go to <a href='http://blah.com>blah</a> now.\n"
204                 + "</body></html>";
205 
206         loadPageVerifyTitle2(html);
207     }
208 
209     /**
210      * Regression test for bug #889.
211      * @throws Exception if an error occurs
212      */
213     @Test
214     @Alerts("0")
215     public void missingDoubleQuote() throws Exception {
216         final String html = "<html>\n"
217                 + "<head>\n"
218                 + "<script>\n"
219                 + LOG_TITLE_FUNCTION
220                 + "  function test() {\n"
221                 + "    log(document.links.length);\n"
222                 + "  }\n"
223                 + "  </script>\n"
224                 + "</head>\n"
225                 + "<body onload='test()'>\n"
226                 + "  Go to <a href=\"http://blah.com>blah</a> now.\n"
227                 + "</body></html>";
228 
229         loadPageVerifyTitle2(html);
230     }
231 
232     /**
233      * Regression test for bug #1192.
234      * @throws Exception if an error occurs
235      */
236     @Test
237     @Alerts({"submit", "button"})
238     public void brokenInputSingleQuote() throws Exception {
239         final String html = "<html>\n"
240                 + "<head>\n"
241                 + "<script>\n"
242                 + LOG_TITLE_FUNCTION
243                 + "  function test() {\n"
244                 + "    log(document.getElementById('myBody').firstChild.type);\n"
245                 + "    log(document.getElementById('myBody').firstChild.value);\n"
246                 + "  }\n"
247                 + "  </script>\n"
248                 + "</head>\n"
249                 + "<body id='myBody' onload='test()'>"
250                 +   "<input width:250px' type='submit' value='button'>"
251                 + "</body></html>";
252         loadPageVerifyTitle2(html);
253     }
254 
255     /**
256      * Regression test for bug #1192.
257      * @throws Exception if an error occurs
258      */
259     @Test
260     @Alerts({"submit", "button"})
261     public void brokenInputDoubleQuote() throws Exception {
262         final String html = "<html>\n"
263                 + "<head>\n"
264                 + "<script>\n"
265                 + LOG_TITLE_FUNCTION
266                 + "  function test() {\n"
267                 + "    log(document.getElementById('myBody').firstChild.type);\n"
268                 + "    log(document.getElementById('myBody').firstChild.value);\n"
269                 + "  }\n"
270                 + "  </script>\n"
271                 + "</head>\n"
272                 + "<body id='myBody' onload='test()'>"
273                 +   "<input width:250px\" type=\"submit\" value=\"button\">"
274                 + "</body></html>";
275         loadPageVerifyTitle2(html);
276     }
277 
278     /**
279      * @throws Exception if an error occurs
280      */
281     @Test
282     @Alerts("inFirst inSecond")
283     public void nestedForms() throws Exception {
284         final String html = "<html><body>\n"
285             + "<form name='TransSearch'>\n"
286             + "<input type='submit' id='button'>\n"
287             + "<table>\n"
288             + "<tr><td><input name='FromDate' value='inFirst'></form></td></tr>\n"
289             + "</table>\n"
290             + "<table>\n"
291             + "<tr><td><form name='ImageSearch'></td></tr>\n"
292             + "<tr><td><input name='FromDate' value='inSecond'></form></td></tr>\n"
293             + "</table>\n"
294             + "<script>\n"
295             + "document.title += ' ' + document.forms[0].elements['FromDate'].value;\n"
296             + "document.title += ' ' + document.forms[1].elements['FromDate'].value;\n"
297             + "</script>\n"
298             + "</body></html>";
299         final WebDriver driver = loadPage2(html);
300         assertTitle(driver, getExpectedAlerts()[0]);
301 
302         driver.findElement(By.id("button")).click();
303         if (useRealBrowser()) {
304             Thread.sleep(400);
305         }
306         assertEquals(URL_FIRST + "?FromDate=inFirst", driver.getCurrentUrl());
307     }
308 
309     /**
310      * @throws Exception if an error occurs
311      */
312     @Test
313     @Alerts("2")
314     public void li_div_li() throws Exception {
315         final String html = "<html><body>\n"
316             + "<ul id='it'><li>item 1<div>in div</li><li>item2</li></ul>"
317             + "<script>\n"
318             + LOG_TITLE_FUNCTION
319             + "log(document.getElementById('it').childNodes.length);\n"
320             + "</script>\n"
321             + "</body></html>";
322         loadPageVerifyTitle2(html);
323     }
324 
325     /**
326      * Regression test for bug 1564.
327      * @throws Exception if an error occurs
328      */
329     @Test
330     @Alerts({"1", "\uFFFD", "65533"})
331     public void entityWithInvalidUTF16Code() throws Exception {
332         final String html = "<html><head><title>&#x1b3d6e;</title></head><body>\n"
333             + LOG_TEXTAREA
334             + "<script>"
335             + LOG_TEXTAREA_FUNCTION
336             + "log(document.title.length);\n"
337             + "log(document.title);\n"
338             + "log(document.title.charCodeAt(0));\n"
339             + "</script></body></html>";
340 
341         loadPageVerifyTextArea2(html);
342     }
343 
344     /**
345      * Regression test for bug 1562.
346      * @throws Exception if an error occurs
347      */
348     @Test
349     @Alerts("hello world")
350     public void sectionWithUnknownClosingTag() throws Exception {
351         final String html = "<html><body><section id='it'>"
352             + "hello</isslot> world"
353             + "</section>\n"
354             + "<script>\n"
355             + LOG_TITLE_FUNCTION
356             + "var elt = document.getElementById('it');\n"
357             + "log(elt.textContent || elt.innerText);\n"
358             + "</script></body></html>";
359 
360         loadPageVerifyTitle2(html);
361     }
362 
363     /**
364      * @throws Exception if an error occurs
365      */
366     @Test
367     @Alerts({"4", "#text:\\n\\s\\s", "A:null", "DIV:null", "#text:Z\\n\\n\\n", "3",
368                 "innerDiv", "BODY:null", "3", "A:null", "A:null", "#text:Y",
369                 "outerA", "BODY:null", "1", "#text:V", "true", "false",
370                 "outerA", "DIV:null", "1", "#text:W", "false", "false",
371                 "innerA", "DIV:null", "1", "#text:X", "false", "true"})
372     @HtmlUnitNYI(
373             CHROME = {"4", "#text:\\n\\s\\s", "A:null", "A:null", "#text:YZ\\n\\n",
374                       "2", "innerDiv", "A:null", "1", "#text:W", "TypeError",
375                       "outerA", "BODY:null", "2", "#text:V", "true", "false",
376                       "innerA", "BODY:null", "1", "#text:X", "false", "true", "TypeError"},
377             EDGE = {"4", "#text:\\n\\s\\s", "A:null", "A:null", "#text:YZ\\n\\n",
378                     "2", "innerDiv", "A:null", "1", "#text:W", "TypeError",
379                     "outerA", "BODY:null", "2", "#text:V", "true", "false",
380                     "innerA", "BODY:null", "1", "#text:X", "false", "true", "TypeError"},
381             FF = {"4", "#text:\\n\\s\\s", "A:null", "A:null", "#text:YZ\\n\\n",
382                   "2", "innerDiv", "A:null", "1", "#text:W", "TypeError",
383                   "outerA", "BODY:null", "2", "#text:V", "true", "false",
384                   "innerA", "BODY:null", "1", "#text:X", "false", "true", "TypeError"},
385             FF_ESR = {"4", "#text:\\n\\s\\s", "A:null", "A:null", "#text:YZ\\n\\n",
386                       "2", "innerDiv", "A:null", "1", "#text:W", "TypeError",
387                       "outerA", "BODY:null", "2", "#text:V", "true", "false",
388                       "innerA", "BODY:null", "1", "#text:X", "false", "true", "TypeError"})
389     // Input:
390     // <a id="outerA">V<div id="innerDiv">W<a id="innerA">X</a>Y</div>Z</a>
391     // CHROME and IE generate:
392     // <a id="outerA">V</a><div id="innerDiv"><a id="outerA">W</a><a id="innerA">X</a>Y</div>Z
393     // HtmlUnit generates:
394     // <a id="outerA">V<div id="innerDiv">W</div></a><a id="innerA">X</a>YZ
395     public void nestedAnchorInDivision() throws Exception {
396         final String html = HtmlPageTest.STANDARDS_MODE_PREFIX_
397             + "<html><head><script>\n"
398             + LOG_TITLE_FUNCTION_NORMALIZE
399             + "  function test() {\n"
400             + "    var outerA = document.getElementById('outerA');\n"
401             + "    var innerDiv = document.getElementById('innerDiv');\n"
402             + "    var innerA = document.getElementById('innerA');\n"
403             + "    var anchors = document.getElementsByTagName('a');\n"
404 
405             + "    try {\n"
406             + "      log(document.body.childNodes.length);\n"
407             + "      dump(document.body.childNodes[0]);\n"
408             + "      dump(document.body.childNodes[1]);\n"
409             + "      dump(document.body.childNodes[2]);\n"
410             + "      dump(document.body.childNodes[3]);\n"
411             + "      log(document.getElementsByTagName('a').length);\n"
412             + "    } catch(e) { logEx(e) }\n"
413 
414             + "    try {\n"
415             + "      log(innerDiv.id);\n"
416             + "      dump(innerDiv.parentNode);\n"
417             + "      log(innerDiv.childNodes.length);\n"
418             + "      dump(innerDiv.childNodes[0]);\n"
419             + "      dump(innerDiv.childNodes[1]);\n"
420             + "      dump(innerDiv.childNodes[2]);\n"
421             + "    } catch(e) { logEx(e) }\n"
422 
423             + "    try {\n"
424             + "      log(anchors[0].id);\n"
425             + "      dump(anchors[0].parentNode);\n"
426             + "      log(anchors[0].childNodes.length);\n"
427             + "      dump(anchors[0].childNodes[0]);\n"
428             + "      log(anchors[0] == outerA);\n"
429             + "      log(anchors[0] == innerA);\n"
430             + "    } catch(e) { logEx(e) }\n"
431 
432             + "    try {\n"
433             + "      log(anchors[1].id);\n"
434             + "      dump(anchors[1].parentNode);\n"
435             + "      log(anchors[1].childNodes.length);\n"
436             + "      dump(anchors[1].childNodes[0]);\n"
437             + "      log(anchors[1] == outerA);\n"
438             + "      log(anchors[1] == innerA);\n"
439             + "    } catch(e) { logEx(e) }\n"
440 
441             + "    try {\n"
442             + "      log(anchors[2].id);\n"
443             + "      dump(anchors[2].parentNode);\n"
444             + "      log(anchors[2].childNodes.length);\n"
445             + "      dump(anchors[2].childNodes[0]);\n"
446             + "      log(anchors[2] == outerA);\n"
447             + "      log(anchors[2] == innerA);\n"
448             + "    } catch(e) { logEx(e) }\n"
449             + "  }\n"
450             + "  function dump(e) {\n"
451             + "    log(e.nodeName + ':' + e.nodeValue);\n"
452             + "  }\n"
453             + "</script></head><body onload='test()'>\n"
454             + "  <a id='outerA'>V<div id='innerDiv'>W<a id='innerA'>X</a>Y</div>Z</a>\n"
455             + "</body>\n"
456             + "</html>\n";
457 
458         loadPageVerifyTitle2(html);
459     }
460 
461     /**
462      * Regression test for bug 1598.
463      * @throws Exception if an error occurs
464      */
465     @Test
466     @Alerts({"DOC", "1"})
467     public void unknownTagInTable() throws Exception {
468         final String html = "<html><body>"
469             + "<table id='it'><doc><tr><td>hello</td></tr></doc></table>"
470             + "<script>\n"
471             + LOG_TITLE_FUNCTION
472             + "log(document.body.firstChild.tagName);\n"
473             + "log(document.getElementById('it').rows.length);\n"
474             + "</script></body></html>";
475 
476         loadPageVerifyTitle2(html);
477     }
478 
479     /**
480      * @throws Exception if an error occurs
481      */
482     @Test
483     @Alerts({"DOC", "1"})
484     public void unknownTagInTbody() throws Exception {
485         final String html = "<html><body>"
486             + "<table id='it'><tbody><doc><tr><td>hello</td></tr></doc></tbody></table>"
487             + "<script>\n"
488             + LOG_TITLE_FUNCTION
489             + "log(document.body.firstChild.tagName);\n"
490             + "log(document.getElementById('it').rows.length);\n"
491             + "</script></body></html>";
492         loadPageVerifyTitle2(html);
493     }
494 
495     /**
496      * @throws Exception if an error occurs
497      */
498     @Test
499     @Alerts("<table id=\"t1\"> "
500             + "<tbody>"
501             + "<tr> "
502             + "<td id=\"td0\"> "
503             + "<form id=\"xyz\"> "
504             + "<input type=\"hidden\"> "
505             + "<input type=\"submit\" value=\"Submit\"> "
506             + "</form> "
507             + "</td> "
508             + "</tr> "
509             + "</tbody>"
510             + "</table>"
511             + "<script> function log(msg) { window.document.title += msg + '\\u00a7'; } "
512                 + "function logEx(e) { let toStr = null; "
513                 + "if (toStr === null && e instanceof EvalError) { toStr = ''; } "
514                 + "if (toStr === null && e instanceof RangeError) { toStr = ''; } "
515                 + "if (toStr === null && e instanceof ReferenceError) { toStr = ''; } "
516                 + "if (toStr === null && e instanceof SyntaxError) { toStr = ''; } "
517                 + "if (toStr === null && e instanceof TypeError) { toStr = ''; } "
518                 + "if (toStr === null && e instanceof URIError) { toStr = ''; } "
519                 + "if (toStr === null && e instanceof AggregateError) { toStr = '/AggregateError'; } "
520                 + "if (toStr === null && typeof InternalError == 'function' "
521                 + "&& e instanceof InternalError) { toStr = '/InternalError'; } "
522                 + "if (toStr === null) { let rx = /\\[object (.*)\\]/; "
523                 + "toStr = Object.prototype.toString.call(e); "
524                 + "let match = rx.exec(toStr); if (match != null) { toStr = '/' + match[1]; } } "
525                 + "log(e.name + toStr); } "
526                 + "log(document.getElementById('bdy').innerHTML); </script>")
527     public void formInTableData() throws Exception {
528         final String html = "<html>\n"
529                 + "<body id='bdy'>\n"
530                 + "<table id='t1'>\n"
531                 + "  <tr>\n"
532                 + "    <td id='td0'>\n"
533                 + "      <form id='xyz'>\n"
534                 + "        <input type='hidden'>\n"
535                 + "        <input type='submit' value='Submit'>\n"
536                 + "      </form>\n"
537                 + "    </td>\n"
538                 + "  </tr>\n"
539                 + "</table>"
540                 + "<script>\n"
541                 + LOG_TITLE_FUNCTION
542                 + "  log(document.getElementById('bdy').innerHTML);\n"
543                 + "</script>\n"
544                 + "</body></html>";
545         loadPageVerifyTitle2(html);
546     }
547 
548     /**
549      * @throws Exception if an error occurs
550      */
551     @Test
552     @Alerts("<input type=\"submit\" value=\"Submit\">"
553             + "<table id=\"t1\"> "
554             + "<tbody>"
555             + "<tr> "
556             + "<td id=\"td0\"> "
557             + "</td> "
558             + "<form id=\"xyz\"></form> "
559             + "<input type=\"hidden\"> "
560             + "</tr> "
561             + "</tbody>"
562             + "</table>"
563             + "<script> function log(msg) { window.document.title += msg + '\\u00a7'; } "
564                 + "function logEx(e) { let toStr = null; "
565                 + "if (toStr === null && e instanceof EvalError) { toStr = ''; } "
566                 + "if (toStr === null && e instanceof RangeError) { toStr = ''; } "
567                 + "if (toStr === null && e instanceof ReferenceError) { toStr = ''; } "
568                 + "if (toStr === null && e instanceof SyntaxError) { toStr = ''; } "
569                 + "if (toStr === null && e instanceof TypeError) { toStr = ''; } "
570                 + "if (toStr === null && e instanceof URIError) { toStr = ''; } "
571                 + "if (toStr === null && e instanceof AggregateError) { toStr = '/AggregateError'; } "
572                 + "if (toStr === null && typeof InternalError == 'function' "
573                 + "&& e instanceof InternalError) { toStr = '/InternalError'; } "
574                 + "if (toStr === null) { let rx = /\\[object (.*)\\]/; "
575                 + "toStr = Object.prototype.toString.call(e); "
576                 + "let match = rx.exec(toStr); if (match != null) { toStr = '/' + match[1]; } } "
577                 + "log(e.name + toStr); } "
578                 + "log(document.getElementById('bdy').innerHTML); </script>")
579     public void formInTableRow() throws Exception {
580         final String html = "<html>\n"
581                 + "<body id='bdy'>\n"
582                 + "<table id='t1'>\n"
583                 + "  <tr>\n"
584                 + "    <td id='td0'>\n"
585                 + "    </td>\n"
586 
587                 + "    <form id='xyz'>\n"
588                 + "      <input type='hidden'>\n"
589                 + "      <input type='submit' value='Submit'>\n"
590                 + "    </form>\n"
591 
592                 + "  </tr>\n"
593                 + "</table>"
594                 + "<script>\n"
595                 + LOG_TITLE_FUNCTION
596                 + "  log(document.getElementById('bdy').innerHTML);\n"
597                 + "</script>\n"
598                 + "</body></html>";
599         loadPageVerifyTitle2(html);
600     }
601 
602     /**
603      * @throws Exception if an error occurs
604      */
605     @Test
606     @Alerts("<input value=\"x\">"
607             + "<input type=\"text\">"
608             + "<input type=\"date\">"
609             + "<input type=\"number\">"
610             + "<input type=\"file\">"
611             + "<input type=\"radio\" value=\"on\">"
612             + "<input type=\"submit\" value=\"Submit\">"
613             + "<input type=\"reset\" value=\"Reset\">"
614             + "<table id=\"t1\"> "
615             + "<tbody>"
616             + "<tr> "
617             + "<td id=\"td0\"> "
618             + "</td> "
619             + "</tr> "
620             + "<form id=\"xyz\"></form> "
621             + "<input type=\"hidden\"> "
622             + "</tbody>"
623             + "</table>"
624             + "<script> function log(msg) { window.document.title += msg + '\\u00a7'; } "
625                 + "function logEx(e) { let toStr = null; "
626                 + "if (toStr === null && e instanceof EvalError) { toStr = ''; } "
627                 + "if (toStr === null && e instanceof RangeError) { toStr = ''; } "
628                 + "if (toStr === null && e instanceof ReferenceError) { toStr = ''; } "
629                 + "if (toStr === null && e instanceof SyntaxError) { toStr = ''; } "
630                 + "if (toStr === null && e instanceof TypeError) { toStr = ''; } "
631                 + "if (toStr === null && e instanceof URIError) { toStr = ''; } "
632                 + "if (toStr === null && e instanceof AggregateError) { toStr = '/AggregateError'; } "
633                 + "if (toStr === null && typeof InternalError == 'function' "
634                 + "&& e instanceof InternalError) { toStr = '/InternalError'; } "
635                 + "if (toStr === null) { let rx = /\\[object (.*)\\]/; "
636                 + "toStr = Object.prototype.toString.call(e); "
637                 + "let match = rx.exec(toStr); if (match != null) { toStr = '/' + match[1]; } } "
638                 + "log(e.name + toStr); } "
639                 + "log(document.getElementById('bdy').innerHTML); </script>")
640     public void formInTable() throws Exception {
641         final String html = "<html>\n"
642                 + "<body id='bdy'>\n"
643                 + "<table id='t1'>\n"
644                 + "  <tr>\n"
645                 + "    <td id='td0'>\n"
646                 + "    </td>\n"
647                 + "  </tr>\n"
648 
649                 + "  <form id='xyz'>\n"
650                 + "    <input type='hidden'>\n"
651                 + "    <input value='x'>\n"
652                 + "    <input type='text'>\n"
653                 + "    <input type='date'>\n"
654                 + "    <input type='number'>\n"
655                 + "    <input type='file'>\n"
656                 + "    <input type='radio' value='on'>\n"
657                 + "    <input type='submit' value='Submit'>\n"
658                 + "    <input type='reset' value='Reset'>\n"
659                 + "  </form>\n"
660                 + "</table>"
661                 + "<script>\n"
662                 + LOG_TITLE_FUNCTION
663                 + "  log(document.getElementById('bdy').innerHTML);\n"
664                 + "</script>\n"
665                 + "</body></html>";
666         loadPageVerifyTitle2(html);
667     }
668 
669     /**
670      * @throws Exception if an error occurs
671      */
672     @Test
673     @Alerts("<tbody>"
674             + "<tr> "
675             + "<td id=\"td0\"> "
676             + "<table> <tbody><tr> <td id=\"td1\"> <table> "
677             + "<form id=\"xyz\"></form> "
678             + "<tbody><tr> "
679             + "<td> "
680             + "<input type=\"hidden\"> "
681             + "<input type=\"submit\" value=\"Submit\"> "
682             + "</td> "
683             + "</tr> </tbody>"
684             + "</table> "
685             + "</td> </tr> <tr><td></td></tr> "
686             + "</tbody></table> "
687             + "</td> "
688             + "</tr> "
689             + "</tbody>")
690     public void formInTable1() throws Exception {
691         final String html = "<html>\n"
692                 + "<body id='bdy'>\n"
693                 + "<table id='t1'>\n"
694                 + "  <tr>\n"
695                 + "    <td id='td0'>\n"
696                 + "      <table>\n"
697                 + "        <tr>\n"
698                 + "          <td id='td1'>\n"
699                 + "            <table>\n"
700                 + "              <form id='xyz'>\n"
701                 + "              <tr>\n"
702                 + "                <td>\n"
703                 + "                  <input type='hidden'>\n"
704                 + "                  <input type='submit' value='Submit'>\n"
705                 + "                </td>\n"
706                 + "              </tr>\n"
707                 + "              </form>\n"
708                 + "            </table>"
709                 + "          </td>\n"
710                 + "        </tr>\n"
711                 + "        <tr><td></td></tr>\n"
712                 + "      </table>\n"
713                 + "    </td>\n"
714                 + "  </tr>\n"
715                 + "</table>"
716                 + "<script>\n"
717                 + LOG_TITLE_FUNCTION
718                 + "  log(document.getElementById('t1').innerHTML);\n"
719                 + "</script>\n"
720                 + "</body></html>";
721         loadPageVerifyTitle2(html);
722     }
723 
724     /**
725      * @throws Exception if an error occurs
726      */
727     @Test
728     @Alerts({"3", "1a", "1b", "1c", "0", "TBODY", "3", "2a", "2b", "2c", "0", "TBODY"})
729     public void formInTable2() throws Exception {
730         final String html = "<html>\n"
731                 + "<body>\n"
732                 + "<table>\n"
733                 + "  <tr>\n"
734                 + "    <td>xyz</td>\n"
735                 + "  </tr>\n"
736                 + "  <form name='form1' action='' method='post'>\n"
737                 + "    <input type='hidden' name='1a' value='a1' />\n"
738                 + "    <tr>\n"
739                 + "      <td>\n"
740                 + "        <table>\n"
741                 + "          <tr>\n"
742                 + "            <td>\n"
743                 + "              <input type='text' name='1b' value='b1' />\n"
744                 + "            </td>\n"
745                 + "          </tr>\n"
746                 + "        </table>\n"
747                 + "      </td>\n"
748                 + "    </tr>\n"
749                 + "    <input type='hidden' name='1c' value='c1'>\n"
750                 + "  </form>\n"
751                 + "  <form name='form2' action='' method='post'>\n"
752                 + "    <input type='hidden' name='2a' value='a2' />\n"
753                 + "    <tr>\n"
754                 + "      <td>\n"
755                 + "        <table>\n"
756                 + "          <tr>\n"
757                 + "            <td>\n"
758                 + "              <input type='text' name='2b' value='b2' />\n"
759                 + "            </td>\n"
760                 + "          </tr>\n"
761                 + "        </table>\n"
762                 + "      </td>\n"
763                 + "    </tr>\n"
764                 + "    <input type='hidden' name='2c' value='c2'>\n"
765                 + "  </form>\n"
766                 + "</table>"
767                 + "<script>\n"
768                 + LOG_TITLE_FUNCTION
769                 + "  for(var i = 0; i < document.forms.length; i++) {\n"
770                 + "  log(document.forms[i].elements.length);\n"
771                 + "    for(var j = 0; j < document.forms[i].elements.length; j++) {\n"
772                 + "      log(document.forms[i].elements[j].name);\n"
773                 + "    }\n"
774                 + "    log(document.forms[i].children.length);\n"
775                 + "    log(document.forms[i].parentNode.tagName);\n"
776                 + "  }\n"
777                 + "</script>\n"
778                 + "</body></html>";
779         loadPageVerifyTitle2(html);
780     }
781 
782     /**
783      * @throws Exception if an error occurs
784      */
785     @Test
786     @Alerts({"3", "1a", "1b", "", "0", "TABLE"})
787     public void formInTable3() throws Exception {
788         final String html = "<html>\n"
789                 + "<body>\n"
790                 + "  <table>\n"
791                 + "    <form name='form1' action='' method='get'>\n"
792                 + "      <input type='hidden' name='1a' value='a1'>\n"
793                 + "      <tr>\n"
794                 + "        <td>\n"
795                 + "          <input type='hidden' name='1b' value='b1'>\n"
796                 + "          <input type='submit' value='Submit'>\n"
797                 + "        </td>\n"
798                 + "      </tr>\n"
799                 + "    </form>\n"
800                 + "  </table>"
801                 + "<script>\n"
802                 + LOG_TITLE_FUNCTION
803                 + "  for(var i = 0; i < document.forms.length; i++) {\n"
804                 + "  log(document.forms[i].elements.length);\n"
805                 + "    for(var j = 0; j < document.forms[i].elements.length; j++) {\n"
806                 + "      log(document.forms[i].elements[j].name);\n"
807                 + "    }\n"
808                 + "    log(document.forms[i].children.length);\n"
809                 + "    log(document.forms[i].parentNode.tagName);\n"
810                 + "  }\n"
811                 + "</script>\n"
812                 + "</body></html>";
813         loadPageVerifyTitle2(html);
814     }
815 
816     /**
817      * @throws Exception if an error occurs
818      */
819     @Test
820     @Alerts({"3", "1a", "1b", "", "0", "DIV"})
821     public void formInTable4() throws Exception {
822         final String html = "<html>\n"
823                 + "<body>\n"
824                 + "  <table>\n"
825                 + "    <div>\n"
826                 + "      <form name='form1' action='' method='get'>\n"
827                 + "        <input type='hidden' name='1a' value='a1'>\n"
828                 + "        <tr>\n"
829                 + "          <td>\n"
830                 + "            <input type='hidden' name='1b' value='b1'>\n"
831                 + "            <input type='submit' value='Submit'>\n"
832                 + "          </td>\n"
833                 + "        </tr>\n"
834                 + "      </form>\n"
835                 + "    </div>\n"
836                 + "  </table>\n"
837                 + "<script>\n"
838                 + LOG_TITLE_FUNCTION
839                 + "  for(var i = 0; i < document.forms.length; i++) {\n"
840                 + "  log(document.forms[i].elements.length);\n"
841                 + "    for(var j = 0; j < document.forms[i].elements.length; j++) {\n"
842                 + "      log(document.forms[i].elements[j].name);\n"
843                 + "    }\n"
844                 + "    log(document.forms[i].children.length);\n"
845                 + "    log(document.forms[i].parentNode.tagName);\n"
846                 + "  }\n"
847                 + "</script>\n"
848                 + "</body></html>";
849 
850         loadPageVerifyTitle2(html);
851     }
852 
853     /**
854      * @throws Exception if an error occurs
855      */
856     @Test
857     @Alerts({"1", "1a", "0", "TR", "1", "2a", "0", "TR"})
858     public void formInTable5() throws Exception {
859         final String html = "<html>\n"
860                 + "<body>\n"
861                 + "  <table>\n"
862                 + "    <tr>\n"
863                 + "      <form name='form1'>\n"
864                 + "        <input value='a1' name='1a' type='hidden'></input>\n"
865                 + "      </form>\n"
866                 + "      <form name='form2'>\n"
867                 + "        <input value='a2' name='2a' type='hidden'></input>\n"
868                 + "      </form>\n"
869                 + "      <td>\n"
870                 + "      </td>\n"
871                 + "    </tr>\n"
872                 + "  </table>\n"
873                 + "<script>\n"
874                 + LOG_TITLE_FUNCTION
875                 + "  for(var i = 0; i < document.forms.length; i++) {\n"
876                 + "  log(document.forms[i].elements.length);\n"
877                 + "    for(var j = 0; j < document.forms[i].elements.length; j++) {\n"
878                 + "      log(document.forms[i].elements[j].name);\n"
879                 + "    }\n"
880                 + "    log(document.forms[i].children.length);\n"
881                 + "    log(document.forms[i].parentNode.tagName);\n"
882                 + "  }\n"
883                 + "</script>\n"
884                 + "</body></html>";
885         loadPageVerifyTitle2(html);
886     }
887 
888     /**
889      * @throws Exception if an error occurs
890      */
891     @Test
892     @Alerts({"2", "1a", "1b", "0", "TR"})
893     public void formInTable6() throws Exception {
894         final String html = "<html>\n"
895                 + "<body>\n"
896                 + "<table>\n"
897                 + "  <tr>\n"
898                 + "    <td></td>\n"
899                 + "    <form name='form1'>\n"
900                 + "      <input name='1a' value='a1' type='hidden'></input>\n"
901                 + "      <td>\n"
902                 + "        <div>\n"
903                 + "          <table>\n"
904                 + "            <tr>\n"
905                 + "              <td>\n"
906                 + "                <input name='1b' value='b1'></input>\n"
907                 + "              </td>\n"
908                 + "            </tr>\n"
909                 + "          </table>\n"
910                 + "        </div>\n"
911                 + "      </td>\n"
912                 + "    </form>\n"
913                 + "  </tr>\n"
914                 + "</table>\n"
915                 + "<script>\n"
916                 + LOG_TITLE_FUNCTION
917                 + "  for(var i = 0; i < document.forms.length; i++) {\n"
918                 + "  log(document.forms[i].elements.length);\n"
919                 + "    for(var j = 0; j < document.forms[i].elements.length; j++) {\n"
920                 + "      log(document.forms[i].elements[j].name);\n"
921                 + "    }\n"
922                 + "    log(document.forms[i].children.length);\n"
923                 + "    log(document.forms[i].parentNode.tagName);\n"
924                 + "  }\n"
925                 + "</script>\n"
926                 + "</body></html>";
927         loadPageVerifyTitle2(html);
928     }
929 
930     /**
931      * @throws Exception if an error occurs
932      */
933     @Test
934     @Alerts({"3", "1a", "1b", "1c", "0", "TR", "1", "2a", "1", "DIV"})
935     public void formInTable7() throws Exception {
936         final String html = "<html>\n"
937                 + "<body>\n"
938                 + "  <table>\n"
939                 + "    <tbody>\n"
940                 + "      <tr>\n"
941                 + "        <form name='form1'>\n"
942                 + "          <input type='hidden' name='1a' value='a1' />\n"
943                 + "          <td>\n"
944                 + "            <input type='hidden' name='1b' value='b1' />\n"
945                 + "            <div>\n"
946                 + "              <input name='1c' value='c1'>\n"
947                 + "            </div>\n"
948                 + "          </td>\n"
949                 + "        </form>\n"
950                 + "      </tr>\n"
951                 + "    </tbody>\n"
952                 + "  </table>\n"
953                 + "  <div>\n"
954                 + "    <form name='form2'>\n"
955                 + "      <input type='hidden' name='2a' value='a2' />\n"
956                 + "    </form>\n"
957                 + "  </div>\n"
958                 + "<script>\n"
959                 + LOG_TITLE_FUNCTION
960                 + "  for(var i = 0; i < document.forms.length; i++) {\n"
961                 + "  log(document.forms[i].elements.length);\n"
962                 + "    for(var j = 0; j < document.forms[i].elements.length; j++) {\n"
963                 + "      log(document.forms[i].elements[j].name);\n"
964                 + "    }\n"
965                 + "    log(document.forms[i].children.length);\n"
966                 + "    log(document.forms[i].parentNode.tagName);\n"
967                 + "  }\n"
968                 + "</script>\n"
969                 + "</body></html>";
970         loadPageVerifyTitle2(html);
971     }
972 
973     /**
974      * @throws Exception if an error occurs
975      */
976     @Test
977     @Alerts({"2", "1a", "1b", "2", "BODY", "TR", "TABLE", "2"})
978     public void formInTable8() throws Exception {
979         final String html = "<html>\n"
980                 + "<body>\n"
981                 + "  <form name='form1'>\n"
982                 + "    <input type='hidden' name='1a' value='a1' />\n"
983                 + "    <div>\n"
984                 + "      <table>\n"
985                 + "        <colgroup id='colgroup'>\n"
986                 + "          <col width='50%' />\n"
987                 + "          <col width='50%' />\n"
988                 + "        </colgroup>\n"
989                 + "        <thead>\n"
990                 + "          <tr>\n"
991                 + "            <th>A</th>\n"
992                 + "            <th>B</th>\n"
993                 + "          </tr>\n"
994                 + "        </thead>\n"
995                 + "        <tbody>\n"
996                 + "          <tr>\n"
997                 + "            <input type='hidden' name='1b' value='b1' />\n"
998                 + "            <td>1</td>\n"
999                 + "            <td>2</td>\n"
1000                 + "          </tr>\n"
1001                 + "        </tbody>\n"
1002                 + "      </table>\n"
1003                 + "    </div>\n"
1004                 + "  </form>\n"
1005                 + "<script>\n"
1006                 + LOG_TITLE_FUNCTION
1007                 + "  log(document.form1.elements.length);\n"
1008                 + "  for(var j = 0; j < document.form1.elements.length; j++) {\n"
1009                 + "    log(document.form1.elements[j].name);\n"
1010                 + "  }\n"
1011                 + "  log(document.form1.children.length);\n"
1012                 + "  log(document.form1.parentNode.tagName);\n"
1013                 + "  log(document.form1['1b'].parentNode.tagName);\n"
1014                 + "  log(document.getElementById('colgroup').parentNode.tagName);\n"
1015                 + "  log(document.getElementById('colgroup').children.length);\n"
1016                 + "</script>\n"
1017                 + "</body></html>";
1018         loadPageVerifyTitle2(html);
1019     }
1020 
1021     /**
1022      * @throws Exception if an error occurs
1023      */
1024     @Test
1025     @Alerts({"3", "1b", "1a", "1c", "0", "TABLE"})
1026     public void formInTable9() throws Exception {
1027         final String html = "<html>\n"
1028                 + "<body>\n"
1029                 + "  <table>\n"
1030                 + "    <form name='form1'>\n"
1031                 + "      <input type='hidden' name='1a' value='a1' />\n"
1032                 + "      <div>\n"
1033                 + "        <input type='hidden' name='1b' value='b1' />\n"
1034                 + "      </div>\n"
1035                 + "      <tbody>\n"
1036                 + "        <tr>\n"
1037                 + "          <input type='hidden' name='1c' value='c1' />\n"
1038                 + "          <td>1</td>\n"
1039                 + "          <td>2</td>\n"
1040                 + "        </tr>\n"
1041                 + "      </tbody>\n"
1042                 + "    </form>\n"
1043                 + "  </table>\n"
1044                 + "<script>\n"
1045                 + LOG_TITLE_FUNCTION
1046                 + "  log(document.form1.elements.length);\n"
1047                 + "  for(var j = 0; j < document.form1.elements.length; j++) {\n"
1048                 + "    log(document.form1.elements[j].name);\n"
1049                 + "  }\n"
1050                 + "  log(document.form1.children.length);\n"
1051                 + "  log(document.form1.parentNode.tagName);\n"
1052                 + "</script>\n"
1053                 + "</body></html>";
1054         loadPageVerifyTitle2(html);
1055     }
1056 
1057     /**
1058      * Test case for issue #1621.
1059      * @throws Exception if an error occurs
1060      */
1061     @Test
1062     @Alerts({"1", "form1_submit", "0", "TABLE"})
1063     public void formInTable10() throws Exception {
1064         final String html = "<html>\n"
1065                 + "<body>\n"
1066                 + "  <table>\n"
1067                 + "    <form name='form1'>\n"
1068                 + "      <tr>\n"
1069                 + "        <td>\n"
1070                 + "          <input name='form1_submit' type='submit'/>\n"
1071                 + "        </td>\n"
1072                 + "      </tr>\n"
1073                 + "    </form>\n"
1074                 + "    <form name='form2'>\n"
1075                 + "    </form>\n"
1076                 + "  </table>\n"
1077                 + "<script>\n"
1078                 + LOG_TITLE_FUNCTION
1079                 + "  log(document.form1.elements.length);\n"
1080                 + "  for(var j = 0; j < document.form1.elements.length; j++) {\n"
1081                 + "    log(document.form1.elements[j].name);\n"
1082                 + "  }\n"
1083                 + "  log(document.form1.children.length);\n"
1084                 + "  log(document.form1.parentNode.tagName);\n"
1085                 + "</script>\n"
1086                 + "</body></html>";
1087         loadPageVerifyTitle2(html);
1088     }
1089 
1090     /**
1091      * @throws Exception if an error occurs
1092      */
1093     @Test
1094     @Alerts({"<div>caption</div>", "TABLE"})
1095     public void nonInlineElementInCaption() throws Exception {
1096         final String html = "<html>\n"
1097                 + "<body>\n"
1098                 + "  <table>\n"
1099                 + "    <caption id='caption'>\n"
1100                 + "      <div>caption</div>\n"
1101                 + "    </caption>\n"
1102                 + "    <tr>\n"
1103                 + "      <td>content</td>\n"
1104                 + "    </tr>\n"
1105                 + "  </table>"
1106                 + "<script>\n"
1107                 + LOG_TITLE_FUNCTION
1108                 + "  log(document.getElementById('caption').innerHTML.replace(/\\s+/g, ''));\n"
1109                 + "  log(document.getElementById('caption').parentNode.tagName);\n"
1110                 + "</script>\n"
1111                 + "</body></html>";
1112         loadPageVerifyTitle2(html);
1113     }
1114 
1115     /**
1116      * @throws Exception if an error occurs
1117      */
1118     @Test
1119     @Alerts({"2", "input1", "submit1", "1", "LI", "2", "input2", "submit2", "2", "DIV"})
1120     public void synthesizedDivInForm() throws Exception {
1121         final String html = "<html>\n"
1122                 + "<body>\n"
1123                 + "  <ul>\n"
1124                 + "    <li>\n"
1125                 + "      <form name='form1' action='action1' method='POST'>\n"
1126                 + "        <div>\n"
1127                 + "          <input name='input1' value='value1'>\n"
1128                 + "          <input name='submit1' type='submit'>\n"
1129                 + "      </form>\n"
1130                 + "    </li>\n"
1131                 + "  </ul>\n"
1132                 + "  <div>\n"
1133                 + "    <form name='form2' action='action2' method='POST'>\n"
1134                 + "      <input name='input2' value='value2'>\n"
1135                 + "      <input name='submit2' type='submit'>\n"
1136                 + "    </form>\n"
1137                 + "  </div>\n"
1138                 + "<script>\n"
1139                 + LOG_TITLE_FUNCTION
1140                 + "  for(var i = 0; i < document.forms.length; i++) {\n"
1141                 + "  log(document.forms[i].elements.length);\n"
1142                 + "    for(var j = 0; j < document.forms[i].elements.length; j++) {\n"
1143                 + "      log(document.forms[i].elements[j].name);\n"
1144                 + "    }\n"
1145                 + "    log(document.forms[i].children.length);\n"
1146                 + "    log(document.forms[i].parentNode.tagName);\n"
1147                 + "  }\n"
1148                 + "</script>\n"
1149                 + "</body></html>";
1150         loadPageVerifyTitle2(html);
1151     }
1152 
1153     /**
1154      * @throws Exception if an error occurs
1155      */
1156     @Test
1157     @Alerts({"frame loaded", "1", "0"})
1158     @HtmlUnitNYI(CHROME = {"", "0", "1"},
1159             EDGE = {"", "0", "1"},
1160             FF = {"", "0", "1"},
1161             FF_ESR = {"", "0", "1"})
1162     public void siblingWithoutContentBeforeFrameset() throws Exception {
1163         final String html = "<html>\n"
1164                 + "<div id='div1'><span></span></div>\n"
1165                 + "<frameset>\n"
1166                 + "  <frame name='main' src='" + URL_SECOND + "' />\n"
1167                 + "</frameset>\n"
1168                 + "</html>";
1169 
1170         final String html2 = "<html><body>\n"
1171                 + "<script>\n"
1172                 + "  alert('frame loaded');\n"
1173                 + "</script>\n"
1174                 + "</body></html>";
1175 
1176         getMockWebConnection().setResponse(URL_SECOND, html2);
1177 
1178         final WebDriver webDriver = loadPage2(html);
1179         assertEquals(getExpectedAlerts()[0], String.join("§", getCollectedAlerts(webDriver)));
1180         assertEquals(Integer.parseInt(getExpectedAlerts()[1]), webDriver.findElements(By.name("main")).size());
1181         assertEquals(Integer.parseInt(getExpectedAlerts()[2]), webDriver.findElements(By.id("div1")).size());
1182     }
1183 
1184     /**
1185      * @throws Exception if an error occurs
1186      */
1187     @Test
1188     @Alerts({"frame loaded", "1", "0"})
1189     @HtmlUnitNYI(CHROME = {"", "0", "1"},
1190             EDGE = {"", "0", "1"},
1191             FF = {"", "0", "1"},
1192             FF_ESR = {"", "0", "1"})
1193     public void siblingWithWhitespaceContentBeforeFrameset() throws Exception {
1194         final String html = "<html>\n"
1195                 + "<div id='div1'>     \t \r \r\n</div>\n"
1196                 + "<frameset>\n"
1197                 + "  <frame name='main' src='" + URL_SECOND + "' />\n"
1198                 + "</frameset>\n"
1199                 + "</html>";
1200 
1201         final String html2 = "<html><body>\n"
1202                 + "<script>\n"
1203                 + "  alert('frame loaded');\n"
1204                 + "</script>\n"
1205                 + "</body></html>";
1206 
1207         getMockWebConnection().setResponse(URL_SECOND, html2);
1208 
1209         final WebDriver webDriver = loadPage2(html);
1210         assertEquals(getExpectedAlerts()[0], String.join("§", getCollectedAlerts(webDriver)));
1211         assertEquals(Integer.parseInt(getExpectedAlerts()[1]), webDriver.findElements(By.name("main")).size());
1212         assertEquals(Integer.parseInt(getExpectedAlerts()[2]), webDriver.findElements(By.id("div1")).size());
1213     }
1214 
1215     /**
1216      * @throws Exception if an error occurs
1217      */
1218     @Test
1219     @Alerts({"", "0", "1"})
1220     public void siblingWithNbspContentBeforeFrameset() throws Exception {
1221         final String html = "<html>\n"
1222                 + "<div id='div1'>&nbsp;</div>\n"
1223                 + "<frameset>\n"
1224                 + "  <frame name='main' src='" + URL_SECOND + "' />\n"
1225                 + "</div>\n"
1226                 + "</html>";
1227 
1228         final String html2 = "<html><body>\n"
1229                 + "<script>\n"
1230                 + "  alert('frame loaded');\n"
1231                 + "</script>\n"
1232                 + "</body></html>";
1233 
1234         getMockWebConnection().setResponse(URL_SECOND, html2);
1235 
1236         final WebDriver webDriver = loadPage2(html);
1237         assertEquals(getExpectedAlerts()[0], String.join("§", getCollectedAlerts(webDriver)));
1238         assertEquals(Integer.parseInt(getExpectedAlerts()[1]), webDriver.findElements(By.name("main")).size());
1239         assertEquals(Integer.parseInt(getExpectedAlerts()[2]), webDriver.findElements(By.id("div1")).size());
1240     }
1241 
1242     /**
1243      * @throws Exception if an error occurs
1244      */
1245     @Test
1246     @Alerts({"", "0", "1"})
1247     public void siblingWithContentBeforeFrameset() throws Exception {
1248         final String html = "<html>\n"
1249                 + "<div id='div1'><span>CONTENT</span></div>\n"
1250                 + "<frameset>\n"
1251                 + "  <frame name='main' src='" + URL_SECOND + "' />\n"
1252                 + "</frameset>\n"
1253                 + "</html>";
1254 
1255         final String html2 = "<html><body>\n"
1256                 + "<script>\n"
1257                 + "  alert('frame loaded');\n"
1258                 + "</script>\n"
1259                 + "</body></html>";
1260 
1261         getMockWebConnection().setResponse(URL_SECOND, html2);
1262 
1263         final WebDriver webDriver = loadPage2(html);
1264         assertEquals(getExpectedAlerts()[0], String.join("§", getCollectedAlerts(webDriver)));
1265         assertEquals(Integer.parseInt(getExpectedAlerts()[1]), webDriver.findElements(By.name("main")).size());
1266         assertEquals(Integer.parseInt(getExpectedAlerts()[2]), webDriver.findElements(By.id("div1")).size());
1267     }
1268 
1269     /**
1270      * @throws Exception if an error occurs
1271      */
1272     @Test
1273     @Alerts({"", "0", "1"})
1274     public void siblingWithoutContentAndBodyBeforeFrameset() throws Exception {
1275         final String html = "<html>\n"
1276                 + "<div id='div1'><span></span></div>\n"
1277                 + "<body>\n"
1278                 + "<frameset>\n"
1279                 + "  <frame name='main' src='" + URL_SECOND + "' />\n"
1280                 + "</frameset>\n"
1281                 + "</html>";
1282 
1283         final String html2 = "<html><body>\n"
1284                 + "<script>\n"
1285                 + "  alert('frame loaded');\n"
1286                 + "</script>\n"
1287                 + "</body></html>";
1288 
1289         getMockWebConnection().setResponse(URL_SECOND, html2);
1290 
1291         final WebDriver webDriver = loadPage2(html);
1292         assertEquals(getExpectedAlerts()[0], String.join("§", getCollectedAlerts(webDriver)));
1293         assertEquals(Integer.parseInt(getExpectedAlerts()[1]), webDriver.findElements(By.name("main")).size());
1294         assertEquals(Integer.parseInt(getExpectedAlerts()[2]), webDriver.findElements(By.id("div1")).size());
1295     }
1296 
1297 
1298     /**
1299      * @throws Exception if an error occurs
1300      */
1301     @Test
1302     @Alerts({"", "0", "1"})
1303     public void siblingWithContentAndBodyBeforeFrameset() throws Exception {
1304         final String html = "<html>\n"
1305                 + "<div id='div1'>x<span></span></div>\n"
1306                 + "<body>\n"
1307                 + "<frameset>\n"
1308                 + "  <frame name='main' src='" + URL_SECOND + "' />\n"
1309                 + "</frameset>\n"
1310                 + "</html>";
1311 
1312         final String html2 = "<html><body>\n"
1313                 + "<script>\n"
1314                 + "  alert('frame loaded');\n"
1315                 + "</script>\n"
1316                 + "</body></html>";
1317 
1318         getMockWebConnection().setResponse(URL_SECOND, html2);
1319 
1320         final WebDriver webDriver = loadPage2(html);
1321         assertEquals(getExpectedAlerts()[0], String.join("§", getCollectedAlerts(webDriver)));
1322         assertEquals(Integer.parseInt(getExpectedAlerts()[1]), webDriver.findElements(By.name("main")).size());
1323         assertEquals(Integer.parseInt(getExpectedAlerts()[2]), webDriver.findElements(By.id("div1")).size());
1324     }
1325 
1326     /**
1327      * @throws Exception if an error occurs
1328      */
1329     @Test
1330     @Alerts({"frame loaded", "1", "0"})
1331     @HtmlUnitNYI(CHROME = {"", "0", "1"},
1332             EDGE = {"", "0", "1"},
1333             FF = {"", "0", "1"},
1334             FF_ESR = {"", "0", "1"})
1335     public void framesetInsideDiv() throws Exception {
1336         final String html = "<html>\n"
1337                 + "<div id='tester'>\n"
1338                 + "  <frameset>\n"
1339                 + "    <frame name='main' src='" + URL_SECOND + "' />\n"
1340                 + "  </frameset>\n"
1341                 + "</div>\n"
1342                 + "</html>";
1343 
1344         final String html2 = "<html><body>\n"
1345                 + "<script>\n"
1346                 + "  alert('frame loaded');\n"
1347                 + "</script>\n"
1348                 + "</body></html>";
1349 
1350         getMockWebConnection().setResponse(URL_SECOND, html2);
1351 
1352         final WebDriver webDriver = loadPage2(html);
1353         assertEquals(getExpectedAlerts()[0], String.join("§", getCollectedAlerts(webDriver)));
1354         assertEquals(Integer.parseInt(getExpectedAlerts()[1]), webDriver.findElements(By.name("main")).size());
1355         assertEquals(Integer.parseInt(getExpectedAlerts()[2]), webDriver.findElements(By.id("tester")).size());
1356     }
1357 
1358     /**
1359      * @throws Exception if an error occurs
1360      */
1361     @Test
1362     @Alerts({"frame loaded", "1", "0"})
1363     @HtmlUnitNYI(CHROME = {"", "0", "1"},
1364             EDGE = {"", "0", "1"},
1365             FF = {"", "0", "1"},
1366             FF_ESR = {"", "0", "1"})
1367     public void framesetInsideForm() throws Exception {
1368         final String html = "<html>\n"
1369                 + "<form id='tester'>\n"
1370                 + "  <frameset>\n"
1371                 + "    <frame name='main' src='" + URL_SECOND + "' />\n"
1372                 + "  </frameset>\n"
1373                 + "</form>\n"
1374                 + "</html>";
1375 
1376         final String html2 = "<html><body>\n"
1377                 + "<script>\n"
1378                 + "  alert('frame loaded');\n"
1379                 + "</script>\n"
1380                 + "</body></html>";
1381 
1382         getMockWebConnection().setResponse(URL_SECOND, html2);
1383 
1384         final WebDriver webDriver = loadPage2(html);
1385         assertEquals(getExpectedAlerts()[0], String.join("§", getCollectedAlerts(webDriver)));
1386         assertEquals(Integer.parseInt(getExpectedAlerts()[1]), webDriver.findElements(By.name("main")).size());
1387         assertEquals(Integer.parseInt(getExpectedAlerts()[2]), webDriver.findElements(By.id("tester")).size());
1388     }
1389 
1390     /**
1391      * @throws Exception if an error occurs
1392      */
1393     @Test
1394     @Alerts({"", "0", "1"})
1395     public void framesetInsideFormContent() throws Exception {
1396         final String html = "<html>\n"
1397                 + "<form id='tester'>Content\n"
1398                 + "  <frameset>\n"
1399                 + "    <frame name='main' src='" + URL_SECOND + "' />\n"
1400                 + "  </frameset>\n"
1401                 + "</form>\n"
1402                 + "</html>";
1403 
1404         final String html2 = "<html><body>\n"
1405                 + "<script>\n"
1406                 + "  alert('frame loaded');\n"
1407                 + "</script>\n"
1408                 + "</body></html>";
1409 
1410         getMockWebConnection().setResponse(URL_SECOND, html2);
1411 
1412         final WebDriver webDriver = loadPage2(html);
1413         assertEquals(getExpectedAlerts()[0], String.join("§", getCollectedAlerts(webDriver)));
1414         assertEquals(Integer.parseInt(getExpectedAlerts()[1]), webDriver.findElements(By.name("main")).size());
1415         assertEquals(Integer.parseInt(getExpectedAlerts()[2]), webDriver.findElements(By.id("tester")).size());
1416     }
1417 
1418     /**
1419      * @throws Exception if an error occurs
1420      */
1421     @Test
1422     @Alerts({"", "0", "1"})
1423     public void framesetInsideTable() throws Exception {
1424         final String html = "<html>\n"
1425                 + "<table id='tester'>\n"
1426                 + "  <frameset>\n"
1427                 + "    <frame name='main' src='" + URL_SECOND + "' />\n"
1428                 + "  </frameset>\n"
1429                 + "</table>\n"
1430                 + "</html>";
1431 
1432         final String html2 = "<html><body>\n"
1433                 + "<script>\n"
1434                 + "  alert('frame loaded');\n"
1435                 + "</script>\n"
1436                 + "</body></html>";
1437 
1438         getMockWebConnection().setResponse(URL_SECOND, html2);
1439 
1440         final WebDriver webDriver = loadPage2(html);
1441         assertEquals(getExpectedAlerts()[0], String.join("§", getCollectedAlerts(webDriver)));
1442         assertEquals(Integer.parseInt(getExpectedAlerts()[1]), webDriver.findElements(By.name("main")).size());
1443         assertEquals(Integer.parseInt(getExpectedAlerts()[2]), webDriver.findElements(By.id("tester")).size());
1444     }
1445 
1446     /**
1447      * @throws Exception if the test fails
1448      */
1449     @Test
1450     @Alerts("§§URL§§foo?a=1&copy=2&prod=3")
1451     public void incompleteEntities() throws Exception {
1452         final String html = "<html><head>\n"
1453             + "<title>Test document</title>\n"
1454             + "</head><body>\n"
1455             + "<a href='foo?a=1&copy=2&prod=3' id='myLink'>my link</a>\n"
1456             + "</body></html>";
1457 
1458         getMockWebConnection().setDefaultResponse("<html><head><title>foo</title></head><body></body></html>");
1459         expandExpectedAlertsVariables(URL_FIRST);
1460 
1461         final WebDriver driver = loadPage2(html);
1462         driver.findElement(By.id("myLink")).click();
1463 
1464         assertEquals(getExpectedAlerts()[0], getMockWebConnection().getLastWebRequest().getUrl());
1465     }
1466 
1467     /**
1468      * @throws Exception if the test fails
1469      */
1470     @Test
1471     @Alerts({"5", "3", "[object HTMLSelectElement]", "[object HTMLTableElement]", "[object HTMLScriptElement]"})
1472     public void selectInsideEmptyTable() throws Exception {
1473         final String html = "<html><head></head><body>\n"
1474                 + "<table><select name='Lang'><option value='da'>Dansk</option></select></table>\n"
1475                 + "<script>\n"
1476                 + LOG_TITLE_FUNCTION
1477                 + "log(document.body.childNodes.length);\n"
1478                 + "log(document.body.children.length);\n"
1479                 + "log(document.body.children[0]);\n"
1480                 + "log(document.body.children[1]);\n"
1481                 + "log(document.body.children[2]);\n"
1482                 + "</script>\n"
1483                 + "</body></html>";
1484 
1485         expandExpectedAlertsVariables(URL_FIRST);
1486 
1487         loadPageVerifyTitle2(html);
1488     }
1489 }