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