View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host.dom;
16  
17  import static org.htmlunit.javascript.host.xml.XMLDocumentTest.LOAD_XML_DOCUMENT_FROM_STRING_FUNCTION;
18  import static org.htmlunit.javascript.host.xml.XMLDocumentTest.SERIALIZE_XML_DOCUMENT_TO_STRING_FUNCTION;
19  import static org.htmlunit.javascript.host.xml.XMLDocumentTest.callLoadXMLDocumentFromString;
20  import static org.htmlunit.javascript.host.xml.XMLDocumentTest.callSerializeXMLDocumentToString;
21  
22  import org.apache.commons.lang3.ArrayUtils;
23  import org.htmlunit.WebDriverTestCase;
24  import org.htmlunit.junit.BrowserRunner;
25  import org.htmlunit.junit.annotation.Alerts;
26  import org.htmlunit.junit.annotation.HtmlUnitNYI;
27  import org.htmlunit.util.MimeType;
28  import org.junit.Test;
29  import org.junit.runner.RunWith;
30  import org.openqa.selenium.By;
31  import org.openqa.selenium.WebDriver;
32  import org.openqa.selenium.WebElement;
33  
34  /**
35   * Tests for {@link Node}.
36   *
37   * @author Brad Clarke
38   * @author <a href="mailto:george@murnock.com">George Murnock</a>
39   * @author Bruce Faulkner
40   * @author Marc Guillemot
41   * @author Ahmed Ashour
42   * @author Frank Danek
43   * @author Ronald Brill
44   */
45  @RunWith(BrowserRunner.class)
46  public class NodeTest extends WebDriverTestCase {
47  
48      /**
49       * @throws Exception on test failure
50       */
51      @Test
52      @Alerts({"[object HTMLSpanElement]", "[object Text]", "null"})
53      public void lastChild() throws Exception {
54          final String html = DOCTYPE_HTML
55                  + "<html><head>\n"
56                  + "<script>\n"
57                  + LOG_TITLE_FUNCTION
58                  + "function doTest() {\n"
59                  + "  log(document.getElementById('myNode').lastChild);\n"
60                  + "  log(document.getElementById('onlyTextNode').lastChild);\n"
61                  + "  log(document.getElementById('emptyNode').lastChild);\n"
62                  + "}\n"
63                  + "</script>\n"
64                  + "</head>\n"
65                  + "<body onload='doTest()'>\n"
66                  + "  <div id='myNode'>hello world<span>Child Node</span></div>\n"
67                  + "  <div id='onlyTextNode'>hello</div>\n"
68                  + "  <div id='emptyNode'></div>\n"
69                  + "</body></html>";
70  
71          loadPageVerifyTitle2(html);
72      }
73  
74      /**
75       * @throws Exception on test failure
76       */
77      @Test
78      @Alerts("true")
79      public void hasChildNodes_true() throws Exception {
80          final String html = DOCTYPE_HTML
81                  + "<html><head>\n"
82                  + "<script>\n"
83                  + LOG_TITLE_FUNCTION
84                  + "function doTest() {\n"
85                  + "  log(document.getElementById('myNode').hasChildNodes());\n"
86                  + "}\n"
87                  + "</script>\n"
88                  + "</head><body onload='doTest()'>\n"
89                  + "<p id='myNode'>hello world<span>Child Node</span></p>\n"
90                  + "</body></html>";
91  
92          loadPageVerifyTitle2(html);
93      }
94  
95      /**
96       * @throws Exception on test failure
97       */
98      @Test
99      @Alerts("false")
100     public void hasChildNodes_false() throws Exception {
101         final String html = DOCTYPE_HTML
102                 + "<html><head>\n"
103                 + "<script>\n"
104                 + LOG_TITLE_FUNCTION
105                 + "function doTest() {\n"
106                 + "  log(document.getElementById('myNode').hasChildNodes());\n"
107                 + "}\n"
108                 + "</script>\n"
109                 + "</head><body onload='doTest()'>\n"
110                 + "<p id='myNode'></p>\n"
111                 + "</body></html>";
112 
113         loadPageVerifyTitle2(html);
114     }
115 
116     /**
117      * @throws Exception if the test fails
118      */
119     @Test
120     @Alerts({"4", "function", "3"})
121     public void remove() throws Exception {
122         final String html = DOCTYPE_HTML
123             + "<html><body>\n"
124             + "<div id='div1'></div>\n"
125             + "<script>\n"
126             + LOG_TITLE_FUNCTION
127             + "var div1 = document.getElementById('div1');\n"
128             + "try {\n"
129             + "  log(document.body.childNodes.length);\n"
130             + "  log(typeof div1.remove);\n"
131             + "  div1.remove();\n"
132             + "  log(document.body.childNodes.length);\n"
133             + "}\n"
134             + "catch(e) { logEx(e); }\n"
135             + "</script></body></html>";
136 
137         loadPageVerifyTitle2(html);
138     }
139 
140     /**
141      * Regression test for removeChild.
142      * @throws Exception if the test fails
143      */
144     @Test
145     @Alerts({"true", "true"})
146     public void removeChild() throws Exception {
147         final String html = DOCTYPE_HTML
148             + "<html><head><script>\n"
149             + LOG_TITLE_FUNCTION
150             + "function doTest() {\n"
151             + "  var form = document.forms['form1'];\n"
152             + "  var div = form.firstChild;\n"
153             + "  var removedDiv = form.removeChild(div);\n"
154             + "  log(div==removedDiv);\n"
155             + "  log(form.firstChild == null);\n"
156             + "}\n"
157             + "</script></head><body onload='doTest()'>\n"
158             + "<form name='form1'><div id='formChild'/></form>\n"
159             + "</body></html>";
160 
161         loadPageVerifyTitle2(html);
162     }
163 
164     /**
165      * @throws Exception if the test fails
166      */
167     @Test
168     @Alerts("NotFoundError/DOMException")
169     public void removeChildSibling() throws Exception {
170         final String html = DOCTYPE_HTML
171             + "<html><head><script>\n"
172             + LOG_TITLE_FUNCTION
173             + "function doTest() {\n"
174             + "  var div1 = document.getElementById('div1');\n"
175             + "  var div2 = document.getElementById('div2');\n"
176             + "  try {\n"
177             + "    div1.removeChild(div2);\n"
178             + "  } catch(e) { logEx(e) }\n"
179             + "}\n"
180             + "</script></head>\n"
181             + "<body onload='doTest()'>\n"
182             + "  <div id='div1'></div>\n"
183             + "  <div id='div2'></div>\n"
184             + "</body></html>";
185 
186         loadPageVerifyTitle2(html);
187     }
188 
189     /**
190      * Regression test for replaceChild.
191      * @throws Exception if the test fails
192      */
193     @Test
194     @Alerts({"true", "true", "true"})
195     public void replaceChild_Normal() throws Exception {
196         final String html = DOCTYPE_HTML
197             + "<html><head><script>\n"
198             + LOG_TITLE_FUNCTION
199             + "function doTest() {\n"
200             + "  var form = document.forms['form1'];\n"
201             + "  var div1 = form.firstChild;\n"
202             + "  var div2 = document.getElementById('newChild');\n"
203             + "  var removedDiv = form.replaceChild(div2,div1);\n"
204             + "  log(div1 == removedDiv);\n"
205             + "  log(form.firstChild == div2);\n"
206             + "  var newDiv = document.createElement('div');\n"
207             + "  form.replaceChild(newDiv, div2);\n"
208             + "  log(form.firstChild == newDiv);\n"
209             + "}\n"
210             + "</script></head><body onload='doTest()'>\n"
211             + "<form name='form1'><div id='formChild'/></form>\n"
212             + "</body><div id='newChild'/></html>";
213 
214         loadPageVerifyTitle2(html);
215     }
216 
217     /**
218      * The common browsers always return node names in uppercase. Test this.
219      * @throws Exception on test failure
220      */
221     @Test
222     @Alerts("DIV")
223     public void nodeNameIsUppercase() throws Exception {
224         final String html = DOCTYPE_HTML
225                 + "<html><head>\n"
226                 + "<script>\n"
227                 + LOG_TITLE_FUNCTION
228                 + "function doTest() {\n"
229                 + "  log(document.getElementById('myNode').nodeName);\n"
230                 + "}\n"
231                 + "</script>\n"
232                 + "</head><body onload='doTest()'>\n"
233                 + "<div id='myNode'>hello world<span>Child Node</span></div>\n"
234                 + "</body></html>";
235 
236         loadPageVerifyTitle2(html);
237     }
238 
239     /**
240      * @throws Exception on test failure
241      */
242     @Test
243     @Alerts({"2", "SPAN", "2", "#text", "H1", "H2"})
244     public void getChildNodes() throws Exception {
245         final String html = DOCTYPE_HTML
246             + "<html><head>\n"
247             + "<script>\n"
248             + LOG_TITLE_FUNCTION
249             + "function doTest() {\n"
250             + "  var aNode = document.getElementById('myNode');\n"
251             + "  log(aNode.childNodes.length);\n"
252             + "  log(aNode.childNodes[0].nodeName);\n"
253             + "  log(aNode.childNodes[0].childNodes.length);\n"
254             + "  log(aNode.childNodes[0].childNodes[0].nodeName);\n"
255             + "  log(aNode.childNodes[0].childNodes[1].nodeName);\n"
256             + "  log(aNode.childNodes[1].nodeName);\n"
257             + "}\n"
258             + "</script>\n"
259             + "</head><body onload='doTest()'>\n"
260             + "<div id='myNode'><span>Child Node 1-A"
261             + "<h1>Child Node 1-B</h1></span>"
262             + "<h2>Child Node 2-A</h2></div>"
263             + "</body></html>";
264 
265         loadPageVerifyTitle2(html);
266     }
267 
268     /**
269      * @throws Exception on test failure
270      */
271     @Test
272     @Alerts({"nb nodes: 2", "8", "1"})
273     public void childNodes_Comments() throws Exception {
274         final String html = DOCTYPE_HTML
275             + "<html><head>\n"
276             + "</head>\n"
277             + "<body><!-- comment --><script>\n"
278             + LOG_TITLE_FUNCTION
279             + "var nodes = document.body.childNodes;\n"
280             + "log('nb nodes: ' + nodes.length);\n"
281             + "for (var i = 0; i < nodes.length; i++)\n"
282             + "  log(nodes[i].nodeType);\n"
283             + "</script></body></html>";
284 
285         loadPageVerifyTitle2(html);
286     }
287 
288     /**
289      * @throws Exception on test failure
290      */
291     @Test
292     @Alerts({"length: 5",
293         "tempNode.name: undefined", "tempNode.name: input1", "tempNode.name: undefined",
294         "tempNode.name: input2", "tempNode.name: undefined"})
295     public void getChildNodesProperties() throws Exception {
296         final String html = DOCTYPE_HTML
297             + "<html><head>\n"
298             + "<script>\n"
299             + LOG_TITLE_FUNCTION
300             + "function doTest() {\n"
301             + "  var testForm = document.getElementById('testForm');\n"
302             + "  var childNodes = testForm.childNodes;\n"
303             + "  var length = childNodes.length;\n"
304             + "  log('length: ' + length);\n"
305             + "  for (var i = 0; i < length; i++) {\n"
306             + "    var tempNode = childNodes.item(i);\n"
307             + "    log('tempNode.name: ' + tempNode.name);\n"
308             + "  }\n"
309             + "}\n"
310             + "</script>\n"
311             + "</head><body onload='doTest()'>\n"
312             + "<form name='testForm' id='testForm'>foo\n" // some text, because IE doesn't see "\n" as a text node here
313             + "<input type='hidden' name='input1' value='1'>\n"
314             + "<input type='hidden' name='input2' value='2'>\n"
315             + "</form>\n"
316             + "</body></html>";
317 
318         loadPageVerifyTitle2(html);
319     }
320 
321     /**
322      * The common browsers always return node names in uppercase. Test this.
323      * @throws Exception on test failure
324      */
325     @Test
326     @Alerts({"document: 9", "document.body: 1", "body child 1: 3", "body child 2: 8"})
327     public void nodeType() throws Exception {
328         final String html = DOCTYPE_HTML
329                 + "<html><head>\n"
330                 + "<script>\n"
331                 + LOG_TITLE_FUNCTION
332                 + "function doTest() {\n"
333                 + "  log('document: ' + document.nodeType);\n"
334                 + "  log('document.body: ' + document.body.nodeType);\n"
335                 + "  log('body child 1: ' + document.body.childNodes[0].nodeType);\n"
336                 + "  log('body child 2: ' + document.body.childNodes[1].nodeType);\n"
337                 + "}\n"
338                 + "</script>\n"
339                 + "</head><body onload='doTest()'>\n"
340                 + "some text<!-- some comment -->\n"
341                 + "</body></html>";
342 
343         loadPageVerifyTitle2(html);
344     }
345 
346     /**
347      * Test for bug 1716129.
348      * @throws Exception on test failure
349      */
350     @Test
351     @Alerts("TypeError")
352     public void attachEvent() throws Exception {
353         final String html = DOCTYPE_HTML
354             + "<html><head>\n"
355             + "<script>\n"
356             + LOG_TITLE_FUNCTION
357             + "function test() {\n"
358             + "  var oField = document.getElementById('div1');\n"
359             + "  try {\n"
360             + "    oField.attachEvent('onclick', foo1);\n"
361             + "    oField.attachEvent('onclick', foo2);\n"
362             + "  } catch(e) { logEx(e) }\n"
363             + "}\n"
364             + "function foo1() {log('in foo1');}\n"
365             + "function foo2() {log('in foo2');}\n"
366             + "</script></head><body onload='test()'>\n"
367             + "<div id='div1'>bla</div>\n"
368             + "</body></html>";
369 
370         final WebDriver driver = loadPage2(html);
371         verifyTitle2(driver, getExpectedAlerts());
372 
373         driver.findElement(By.id("div1")).click();
374         verifyTitle2(driver, getExpectedAlerts());
375     }
376 
377 
378     /**
379      * @throws Exception if the test fails
380      */
381     @Test
382     @Alerts("true")
383     public void isEqualNodeSame() throws Exception {
384         final String html = DOCTYPE_HTML
385                 + "<html><head><script>\n"
386                 + LOG_TITLE_FUNCTION
387                 + "  function test() {\n"
388                 + "    var list1 = document.getElementById('list1');\n"
389                 + "    log(list1.isEqualNode(list1));\n"
390                 + "\n"
391                 + "  }\n"
392                 + "</script></head>\n"
393                 + "<body onload='test()'>\n"
394                 + "  <ul id='list1'>\n"
395                 + "    <li>foo</li>\n"
396                 + "    <li>bar</li>\n"
397                 + "  </ul>\n"
398                 + "</body></html>";
399         loadPageVerifyTitle2(html);
400     }
401 
402     /**
403      * @throws Exception if the test fails
404      */
405     @Test
406     @Alerts({"false", "false"})
407     public void isEqualNodeNull() throws Exception {
408         final String html = DOCTYPE_HTML
409                 + "<html><head><script>\n"
410                 + LOG_TITLE_FUNCTION
411                 + "  function test() {\n"
412                 + "    var list1 = document.getElementById('list1');\n"
413                 + "    log(list1.isEqualNode(null));\n"
414                 + "    log(list1.isEqualNode(undefined));\n"
415                 + "  }\n"
416                 + "</script></head>\n"
417                 + "<body onload='test()'>\n"
418                 + "  <ul id='list1'>\n"
419                 + "    <li>foo</li>\n"
420                 + "    <li>bar</li>\n"
421                 + "  </ul>\n"
422                 + "</body></html>";
423         loadPageVerifyTitle2(html);
424     }
425 
426     /**
427      * @throws Exception if the test fails
428      */
429     @Test
430     @Alerts({"true", "true", "false", "true", "true", "false", "false", "false", "true"})
431     public void isEqualNodeEmpty() throws Exception {
432         final String html = DOCTYPE_HTML
433                 + "<html><head><script>\n"
434                 + LOG_TITLE_FUNCTION
435                 + "  function test() {\n"
436                 + "    var list1 = document.getElementById('list1');\n"
437                 + "    var list1 = document.getElementById('list2');\n"
438 
439                 + "    log(list1.isEqualNode(list1));\n"
440                 + "    log(list1.isEqualNode(list2));\n"
441                 + "    log(list1.isEqualNode(list3));\n"
442 
443                 + "    log(list2.isEqualNode(list1));\n"
444                 + "    log(list2.isEqualNode(list2));\n"
445                 + "    log(list2.isEqualNode(list3));\n"
446 
447                 + "    log(list3.isEqualNode(list1));\n"
448                 + "    log(list3.isEqualNode(list2));\n"
449                 + "    log(list3.isEqualNode(list3));\n"
450                 + "  }\n"
451                 + "</script></head>\n"
452                 + "<body onload='test()'>\n"
453                 + "  <ul id='list1'>\n"
454                 + "  </ul>\n"
455                 + "  <ul id='list2'>\n"
456                 + "  </ul>\n"
457                 + "  <ul id='list3'>\n"
458                 + "    <li>foo</li>\n"
459                 + "    <li>bar</li>\n"
460                 + "  </ul>\n"
461                 + "</body></html>";
462         loadPageVerifyTitle2(html);
463     }
464 
465     /**
466      * @throws Exception if the test fails
467      */
468     @Test
469     @Alerts({"6", "false", "true", "false", "false", "false",
470              "true", "false", "false", "false", "false",
471              "false", "true", "false", "false", "false",
472              "false", "false", "true", "false", "false",
473              "false", "false", "false", "true", "false",
474              "false", "false", "false", "false", "true"})
475     public void isEqualNodeAttr() throws Exception {
476         final String html = DOCTYPE_HTML
477                 + "<html><head><script>\n"
478                 + LOG_TITLE_FUNCTION
479                 + "  function test() {\n"
480                 + "    var nodes = document.getElementsByClassName('test');\n"
481                 + "    log(nodes.length);\n"
482 
483                 + "    log(nodes[0].isEqualNode(nodes[1]));\n"
484                 + "    log(nodes[0].isEqualNode(nodes[2]));\n"
485                 + "    log(nodes[0].isEqualNode(nodes[3]));\n"
486                 + "    log(nodes[0].isEqualNode(nodes[4]));\n"
487                 + "    log(nodes[0].isEqualNode(nodes[5]));\n"
488 
489                 + "    log(nodes[1].isEqualNode(nodes[1]));\n"
490                 + "    log(nodes[1].isEqualNode(nodes[2]));\n"
491                 + "    log(nodes[1].isEqualNode(nodes[3]));\n"
492                 + "    log(nodes[1].isEqualNode(nodes[4]));\n"
493                 + "    log(nodes[1].isEqualNode(nodes[5]));\n"
494 
495                 + "    log(nodes[2].isEqualNode(nodes[1]));\n"
496                 + "    log(nodes[2].isEqualNode(nodes[2]));\n"
497                 + "    log(nodes[2].isEqualNode(nodes[3]));\n"
498                 + "    log(nodes[2].isEqualNode(nodes[4]));\n"
499                 + "    log(nodes[2].isEqualNode(nodes[5]));\n"
500 
501                 + "    log(nodes[3].isEqualNode(nodes[1]));\n"
502                 + "    log(nodes[3].isEqualNode(nodes[2]));\n"
503                 + "    log(nodes[3].isEqualNode(nodes[3]));\n"
504                 + "    log(nodes[3].isEqualNode(nodes[4]));\n"
505                 + "    log(nodes[3].isEqualNode(nodes[5]));\n"
506 
507                 + "    log(nodes[4].isEqualNode(nodes[1]));\n"
508                 + "    log(nodes[4].isEqualNode(nodes[2]));\n"
509                 + "    log(nodes[4].isEqualNode(nodes[3]));\n"
510                 + "    log(nodes[4].isEqualNode(nodes[4]));\n"
511                 + "    log(nodes[4].isEqualNode(nodes[5]));\n"
512 
513                 + "    log(nodes[5].isEqualNode(nodes[1]));\n"
514                 + "    log(nodes[5].isEqualNode(nodes[2]));\n"
515                 + "    log(nodes[5].isEqualNode(nodes[3]));\n"
516                 + "    log(nodes[5].isEqualNode(nodes[4]));\n"
517                 + "    log(nodes[5].isEqualNode(nodes[5]));\n"
518                 + "  }\n"
519                 + "</script></head>\n"
520                 + "<body onload='test()'>\n"
521                 + "  <ul class='test'>\n"
522                 + "    <li>foo</li>\n"
523                 + "    <li>bar</li>\n"
524                 + "  </ul>\n"
525                 + "  <ul class='test'>\n"
526                 + "    <li>foo</li>     \n"
527                 + "    <li>bar</li>\n"
528                 + "  </ul>\n"
529                 + "  <ul class='test'>\n"
530                 + "    <li>foo</li>\n"
531                 + "    <li>bar</li>\n"
532                 + "  </ul>\n"
533                 + "  <ul class='test'>\n"
534                 + "    <li>foo</li>\n"
535                 + "\n"
536                 + "    <li>bar</li>\n"
537                 + "  </ul>\n"
538                 + "  <ul class='test'>\n"
539                 + "    <li>foo</li>\n"
540                 + "    <li>bar</li>\n"
541                 + "    <li></li>\n"
542                 + "  </ul>\n"
543                 + "  <ul class='test'>\n"
544                 + "    <li>foobar</li>\n"
545                 + "    <li></li>\n"
546                 + "  </ul>\n"
547                 + "</body></html>";
548         loadPageVerifyTitle2(html);
549     }
550 
551     /**
552      * @throws Exception if the test fails
553      */
554     @Test
555     @Alerts({"true", "false"})
556     public void isSameNode() throws Exception {
557         final String html = DOCTYPE_HTML
558             + "<html><head><script>\n"
559             + LOG_TITLE_FUNCTION
560             + "  function test() {\n"
561             + "    var d1 = document.getElementById('div1');\n"
562             + "    var d2 = document.getElementById('div2');\n"
563             + "    try {\n"
564             + "      log(d1.isSameNode(d1));\n"
565             + "      log(d1.isSameNode(d2));\n"
566             + "    } catch(e) {\n"
567             + "      log('isSameNode not supported');\n"
568             + "    }\n"
569             + "  }\n"
570             + "</script></head><body onload='test()'>\n"
571             + "<div id='div1'/>\n"
572             + "<div id='div2'/>\n"
573             + "</body></html>";
574         loadPageVerifyTitle2(html);
575     }
576 
577     /**
578      * Test element.appendChild: If the parent has a null parentNode,
579      * IE creates a DocumentFragment be the parent's parentNode.
580      *
581      * @throws Exception if the test fails
582      */
583     @Test
584     @Alerts({"null", "null"})
585     public void appendChild_parentNode() throws Exception {
586         final String html = DOCTYPE_HTML
587             + "<html><head><script>\n"
588             + LOG_TITLE_FUNCTION
589             + "  function test() {\n"
590             + "    var div1 = document.createElement('div');\n"
591             + "    var div2 = document.createElement('div');\n"
592             + "    log(div1.parentNode);\n"
593             + "    div1.appendChild(div2);\n"
594             + "    if(div1.parentNode)\n"
595             + "      log(div1.parentNode.nodeName);\n"
596             + "    else\n"
597             + "      log(div1.parentNode);\n"
598             + "  }\n"
599             + "</script></head><body onload='test()'>\n"
600             + "</body></html>";
601 
602         loadPageVerifyTitle2(html);
603     }
604 
605     /**
606      * The HTML node can't be inserted anywhere else!
607      * @throws Exception if the test fails
608      */
609     @Test
610     @Alerts({"1", "HierarchyRequestError/DOMException", "1",
611              "HierarchyRequestError/DOMException", "1", "HierarchyRequestError/DOMException", "1"})
612     public void append_insert_html_node() throws Exception {
613         final String html = DOCTYPE_HTML
614             + "<html><head><script>\n"
615             + LOG_TITLE_FUNCTION
616             + "function test() {\n"
617             + "  var htmlNode = document.documentElement;\n"
618             + "  var body = document.body;\n"
619             + "  log(body.childNodes.length);\n"
620             + "  try { body.appendChild(htmlNode); } catch(e) { logEx(e); }\n"
621             + "  log(body.childNodes.length);\n"
622             + "  try { body.insertBefore(htmlNode, body.firstChild); } catch(e) { logEx(e); }\n"
623             + "  log(body.childNodes.length);\n"
624             + "  try { body.replaceChild(htmlNode, body.firstChild); } catch(e) { logEx(e); }\n"
625             + "  log(body.childNodes.length);\n"
626             + "}\n"
627             + "</script></head><body onload='test()'><span>hi</span></body></html>";
628 
629         loadPageVerifyTitle2(html);
630     }
631 
632     /**
633      * @throws Exception if the test fails
634      */
635     @Test
636     @Alerts("2")
637     public void appendChild_of_DocumentFragment() throws Exception {
638         final String html = DOCTYPE_HTML
639             + "<html><head><script>\n"
640             + LOG_TITLE_FUNCTION
641             + "  function test() {\n"
642             + "    var fragment = document.createDocumentFragment();\n"
643             + "    var div1 = document.createElement('div');\n"
644             + "    div1.id = 'div1';\n"
645             + "    var div2 = document.createElement('div');\n"
646             + "    div2.id = 'div2';\n"
647             + "    fragment.appendChild(div1);\n"
648             + "    fragment.appendChild(div2);\n"
649             + "    var div = document.getElementById('myDiv');\n"
650             + "    div.appendChild(fragment);\n"
651             + "    log(div.childNodes.length);\n"
652             + "  }\n"
653             + "</script></head><body onload='test()'>\n"
654             + "<div id='myDiv'></div>\n"
655             + "</body></html>";
656 
657         loadPageVerifyTitle2(html);
658     }
659 
660     /**
661      * @throws Exception if the test fails
662      */
663     @Test
664     @Alerts({"3", "3", "3", "3", "3", "3", "3", "3"})
665     public void nodePrototype() throws Exception {
666         final String html = DOCTYPE_HTML
667             + "<html><head><script>\n"
668             + LOG_TITLE_FUNCTION
669             + "  function test() {\n"
670             + "    try {\n"
671             + "      log(document.body.TEXT_NODE);\n"
672             + "      log(Node.TEXT_NODE);\n"
673             + "      document.body.TEXT_NODE = 123;\n"
674             + "      log(document.body.TEXT_NODE);\n"
675             + "      log(Node.TEXT_NODE);\n"
676             + "      Node.TEXT_NODE = 456;\n"
677             + "      log(document.body.TEXT_NODE);\n"
678             + "      log(Node.TEXT_NODE);\n"
679             + "      delete Node.TEXT_NODE;\n"
680             + "      delete document.body.TEXT_NODE;\n"
681             + "      log(document.body.TEXT_NODE);\n"
682             + "      log(Node.TEXT_NODE);\n"
683             + "    } catch(e) {\n"
684             + "      log('not supported');\n"
685             + "    }\n"
686             + "  }\n"
687             + "</script></head><body onload='test()'>\n"
688             + "</body></html>";
689 
690         loadPageVerifyTitle2(html);
691     }
692 
693     /**
694      * @throws Exception if the test fails
695      */
696     @Test
697     @Alerts({"<div id=\"myDiv2\"></div><div id=\"myDiv3\"></div>", "myDiv2",
698              "<div>one</div><div>two</div><div id=\"myDiv3\"></div>"})
699     public void replaceChild() throws Exception {
700         final String html = DOCTYPE_HTML
701             + "<html><head><script>\n"
702             + LOG_TITLE_FUNCTION
703             + "  function test() {\n"
704             + "    try {\n"
705             + "      var element = document.getElementById('myDiv2');\n"
706             + "      var range = element.ownerDocument.createRange();\n"
707             + "      range.setStartAfter(element);\n"
708             + "      var fragment = range.createContextualFragment('<div>one</div><div>two</div>');\n"
709             + "      var parent = element.parentNode;\n"
710             + "      log(parent.innerHTML);\n"
711             + "      log(parent.replaceChild(fragment, parent.firstChild).id);\n"
712             + "      log(parent.innerHTML);\n"
713             + "    } catch(e) { logEx(e); }\n"
714             + "  }\n"
715             + "</script></head><body onload='test()'>\n"
716             + "  <div id='myDiv'><div id='myDiv2'></div><div id='myDiv3'></div></div>\n"
717             + "</body></html>";
718 
719         loadPageVerifyTitle2(html);
720     }
721 
722     /**
723      * @throws Exception if the test fails
724      */
725     @Test
726     @Alerts({"<div id=\"myDiv2\"></div><div id=\"myDiv3\"></div>", "myDiv2",
727              "<div id=\"myDiv3\"></div>"})
728     public void replaceChild_EmptyDocumentFragment() throws Exception {
729         final String html = DOCTYPE_HTML
730             + "<html><head><script>\n"
731             + LOG_TITLE_FUNCTION
732             + "  function test() {\n"
733             + "    var element = document.getElementById('myDiv2');\n"
734             + "    try {\n"
735             + "      var range = element.ownerDocument.createRange();\n"
736             + "      range.setStartAfter(element);\n"
737             + "      var fragment = range.createContextualFragment('');\n"
738             + "      var parent = element.parentNode;\n"
739             + "      log(parent.innerHTML);\n"
740             + "      log(parent.replaceChild(fragment, parent.firstChild).id);\n"
741             + "      log(parent.innerHTML);\n"
742             + "    } catch(e) { logEx(e); }\n"
743             + "  }\n"
744             + "</script></head><body onload='test()'>\n"
745             + "  <div id='myDiv'><div id='myDiv2'></div><div id='myDiv3'></div></div>\n"
746             + "</body></html>";
747 
748         loadPageVerifyTitle2(html);
749     }
750 
751     /**
752      * Verifies that listeners are copied only for IE.
753      * @throws Exception if an error occurs
754      */
755     @Test
756     @Alerts("in click")
757     public void cloneNode_copiesListenerOnlyForIE() throws Exception {
758         final String html = DOCTYPE_HTML
759             + "<html>\n"
760             + "  <head>\n"
761             + "  <script>\n"
762             + LOG_TITLE_FUNCTION
763             + "    function go() {\n"
764             + "      var node = document.createElement('button');\n"
765             + "      var f = function() { log('in click') };\n"
766             + "      if (node.attachEvent)\n"
767             + "        node.attachEvent('onclick', f);\n"
768             + "      else\n"
769             + "        node.addEventListener('click', f, true);\n"
770             + "      document.body.appendChild(node);\n"
771             + "      node.click();\n"
772             + "      var clone = node.cloneNode(true);\n"
773             + "      document.body.appendChild(clone);\n"
774             + "      clone.click();\n"
775             + "      var div = document.createElement('div');\n"
776             + "      div.appendChild(node);\n"
777             + "      var cloneDiv = div.cloneNode(true);\n"
778             + "      document.body.appendChild(cloneDiv);\n"
779             + "      cloneDiv.firstChild.click();\n"
780             + "    }\n"
781             + "  </script>\n"
782             + "  </head>\n"
783             + "  <body onload='go()'>\n"
784             + "    <div id='foo'></div>\n"
785             + "  </body>\n"
786             + "</html>";
787 
788         loadPageVerifyTitle2(html);
789     }
790 
791     /**
792      * @throws Exception if the test fails
793      */
794     @Test
795     @Alerts({"1", "1", "2", "4", "8", "16", "32"})
796     public void documentPositionConstants() throws Exception {
797         final String html = DOCTYPE_HTML
798             + "<html><head><script>\n"
799             + LOG_TITLE_FUNCTION
800             + "  function test() {\n"
801             + "    try {\n"
802             + "      log(document.body.DOCUMENT_POSITION_DISCONNECTED);\n"
803             + "      log(Node.DOCUMENT_POSITION_DISCONNECTED);\n"
804             + "      log(Node.DOCUMENT_POSITION_PRECEDING);\n"
805             + "      log(Node.DOCUMENT_POSITION_FOLLOWING);\n"
806             + "      log(Node.DOCUMENT_POSITION_CONTAINS);\n"
807             + "      log(Node.DOCUMENT_POSITION_CONTAINED_BY);\n"
808             + "      log(Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);\n"
809             + "    } catch(e) {\n"
810             + "      log('not supported');\n"
811             + "    }\n"
812             + "  }\n"
813             + "</script></head><body onload='test()'>\n"
814             + "</body></html>";
815 
816         loadPageVerifyTitle2(html);
817     }
818 
819     /**
820      * @throws Exception if the test fails
821      */
822     @Test
823     @Alerts({"0", "20", "20", "4", "10", "10", "2", "20", "TypeError"})
824     public void compareDocumentPosition() throws Exception {
825         final String html = DOCTYPE_HTML
826             + "<html><head>\n"
827             + "<script>\n"
828             + LOG_TITLE_FUNCTION
829             + "function test() {\n"
830             + "  var div1 = document.getElementById('div1');\n"
831             + "  var div2 = document.getElementById('div2');\n"
832             + "  var div3 = document.getElementById('div3');\n"
833             + "  if (!div1.compareDocumentPosition) { log('compareDocumentPosition not available'); return }\n"
834 
835             + "  log(div1.compareDocumentPosition(div1));\n"
836             + "  log(div1.compareDocumentPosition(div2));\n"
837             + "  log(div1.compareDocumentPosition(div3));\n"
838             + "  log(div1.compareDocumentPosition(div4));\n"
839             + "  log(div2.compareDocumentPosition(div1));\n"
840             + "  log(div3.compareDocumentPosition(div1));\n"
841             + "  log(div4.compareDocumentPosition(div1));\n"
842             + "  log(div2.compareDocumentPosition(div3));\n"
843             + "  try {\n"
844             + "    log(div2.compareDocumentPosition({}));\n"
845             + "  } catch(e) { logEx(e); }\n"
846             + "}\n"
847             + "</script></head><body onload='test()'>\n"
848             + "<div id='div1'>\n"
849             + "  <div id='div2'>\n"
850             + "    <div id='div3'>\n"
851             + "    </div>\n"
852             + "  </div>\n"
853             + "</div>\n"
854             + "<div id='div4'>\n"
855             + "</div>\n"
856             + "</body></html>";
857 
858         loadPageVerifyTitle2(html);
859     }
860 
861     /**
862      * @throws Exception if the test fails
863      */
864     @Test
865     @Alerts({"0", "16"})
866     public void compareDocumentPosition2() throws Exception {
867         final String html = DOCTYPE_HTML
868             + "<html><head><script>\n"
869             + LOG_TITLE_FUNCTION
870             + "  function test() {\n"
871             + "    var div = document.createElement('div');\n"
872             + "    var childDiv = document.createElement('div');\n"
873             + "    try {\n"
874             + "      log(div.compareDocumentPosition(childDiv) & Node.DOCUMENT_POSITION_CONTAINED_BY);\n"
875             + "      div.appendChild(childDiv);\n"
876             + "      log(div.compareDocumentPosition(childDiv) & Node.DOCUMENT_POSITION_CONTAINED_BY);\n"
877             + "    } catch(e) {logEx(e);}\n"
878             + "  }\n"
879             + "</script></head><body onload='test()'>\n"
880             + "</body></html>";
881 
882         loadPageVerifyTitle2(html);
883     }
884 
885     /**
886      * @throws Exception if the test fails
887      */
888     @Test
889     @Alerts({"false", "37", "35"})
890     public void compareDocumentPositionFragment() throws Exception {
891         final String html = DOCTYPE_HTML
892             + "<html><head><script>\n"
893             + LOG_TITLE_FUNCTION
894             + "  function test() {\n"
895             + "    let range = document.createRange();\n"
896             + "    let documentFragment1 = range.createContextualFragment(\"<div id='d1'></div>\");\n"
897             + "    let div1 = documentFragment1.getElementById('d1');\n"
898             + "    let documentFragment2 = range.createContextualFragment(\"<div id='d2'></div>\");\n"
899             + "    let div2 = documentFragment2.getElementById('d2');\n"
900 
901             + "    log(documentFragment1 === documentFragment2);\n"
902             + "    let cmp1 = div1.compareDocumentPosition(div2);\n"
903             + "    let cmp2 = div2.compareDocumentPosition(div1);\n"
904             // spec only likes to have a consistent order
905             + "    if (cmp1 > cmp2) { log(cmp1); log(cmp2); } else { log(cmp2); log(cmp1); }\n"
906             + "  }\n"
907             + "</script></head>\n"
908             + "<body onload='test()'>\n"
909             + "</body></html>";
910 
911         loadPageVerifyTitle2(html);
912     }
913 
914     /**
915      * @throws Exception if the test fails
916      */
917     @Test
918     @Alerts("bk")
919     public void prefix() throws Exception {
920         final String html = DOCTYPE_HTML
921             + "<html><head><script>\n"
922             + LOG_TITLE_FUNCTION
923             + "function test() {\n"
924             + "  var text = \"<bk:book xmlns:bk='urn:loc.gov:books'></bk:book>\";\n"
925             + "  var doc = " + callLoadXMLDocumentFromString("text") + ";\n"
926             + "  log(doc.documentElement.prefix);\n"
927             + "}\n"
928             + LOAD_XML_DOCUMENT_FROM_STRING_FUNCTION
929             + "</script></head><body onload='test()'>\n"
930             + "</body></html>";
931 
932         loadPageVerifyTitle2(html);
933     }
934 
935     /**
936      * @throws Exception if the test fails
937      */
938     @Test
939     @Alerts("<root><![CDATA[abc]]><![CDATA[def]]></root>")
940     public void xml() throws Exception {
941         final String html = DOCTYPE_HTML
942             + "<html><head><script>\n"
943             + LOG_TITLE_FUNCTION
944             + "  function test() {\n"
945             + "    var doc = document.implementation.createDocument('', '', null);\n"
946             + "    var root = doc.appendChild(doc.createElement('root'));\n"
947             + "    var cdata = root.appendChild(doc.createCDATASection('abcdef'));\n"
948             + "    cdata.splitText(3);\n"
949             + "    log(" + callSerializeXMLDocumentToString("doc") + ");\n"
950             + "  }\n"
951             + SERIALIZE_XML_DOCUMENT_TO_STRING_FUNCTION
952             + "</script></head><body onload='test()'>\n"
953             + "</body></html>";
954 
955         loadPageVerifyTitle2(html);
956     }
957 
958     /**
959      * Regression test to verify that insertBefore correctly appends
960      * the new child object when the reference child object is null.
961      * @throws Exception if the test fails
962      */
963     @Test
964     @Alerts({"3", "SPAN"})
965     public void insertBefore_nullRef() throws Exception {
966         insertBefore("aNode.insertBefore(newNode, null);");
967     }
968 
969     /**
970      * @throws Exception if the test fails
971      */
972     @Test
973     @Alerts("NotFoundError/DOMException")
974     public void insertBefore_myself() throws Exception {
975         insertBefore("aNode.insertBefore(newNode, newNode);");
976     }
977 
978     /**
979      * @throws Exception if the test fails
980      */
981     @Test
982     @Alerts("NotFoundError/DOMException")
983     public void insertBefore_sibling() throws Exception {
984         insertBefore("aNode.insertBefore(newNode, siblingNode);");
985     }
986 
987     /**
988      * @throws Exception on test failure
989      */
990     @Test
991     @Alerts("done")
992     public void insertBefore_undefinedRef() throws Exception {
993         final String html = DOCTYPE_HTML
994                 + "<html><head>\n"
995                 + "<script>\n"
996                 + LOG_TITLE_FUNCTION
997                 + "function doTest() {\n"
998                 + "  try {\n"
999                 + "    var e = document.createElement('div');\n"
1000                 + "    e.innerHTML = 'new element';\n"
1001                 + "    document.body.insertBefore(e, undefined);\n"
1002                 + "    log('done');"
1003                 + "  } catch(e) {logEx(e);}\n"
1004                 + "}\n"
1005                 + "</script>\n"
1006                 + "</head><body onload='doTest()'>\n"
1007                 + "</body></html>";
1008 
1009         loadPageVerifyTitle2(html);
1010     }
1011 
1012     /**
1013      * Regression test to verify that insertBefore correctly appends
1014      * the new child object when the reference child object is null.
1015      * @throws Exception if the test fails
1016      */
1017     @Test
1018     @Alerts("TypeError")
1019     public void insertBefore_noArgs() throws Exception {
1020         insertBefore("aNode.insertBefore();");
1021     }
1022 
1023     /**
1024      * Regression test to verify that insertBefore correctly appends
1025      * the new child object when the reference child object is null.
1026      * @throws Exception if the test fails
1027      */
1028     @Test
1029     @Alerts("TypeError")
1030     public void insertBefore_noSecondArg() throws Exception {
1031         insertBefore("aNode.insertBefore(newNode);");
1032     }
1033 
1034     /**
1035      * @throws Exception if the test fails
1036      */
1037     private void insertBefore(final String insertJSLine) throws Exception {
1038         final String html = DOCTYPE_HTML
1039             + "<html>\n"
1040             + "<head>\n"
1041             + "  <script>\n"
1042             + LOG_TITLE_FUNCTION
1043             + "    function doTest() {\n"
1044             + "      var newNode = document.createElement('span');\n"
1045             + "      var siblingNode = document.getElementById('sibingNode');\n"
1046             + "      var aNode = document.getElementById('myNode');\n"
1047             + "      try {\n"
1048             + insertJSLine
1049             + "        log(aNode.childNodes.length);\n"
1050             + "        log(aNode.childNodes[2].nodeName);\n"
1051             + "      }\n"
1052             + "      catch(e) { logEx(e); }\n"
1053             + "    }\n"
1054             + "  </script>\n"
1055             + "</head>\n"
1056             + "<body onload='doTest()'>\n"
1057             + "<div id='myNode'><span>Child Node 1-A</span><h1>Child Node 2-A</h1></div>\n"
1058             + "<h2 id='sibingNode'>Sibling</h2>\n"
1059             + "</body></html>";
1060 
1061         loadPageVerifyTitle2(html);
1062     }
1063 
1064     /**
1065      * Regression test to verify that insertBefore correctly appends
1066      * the new child object when the reference child object is null.
1067      * @throws Exception if the test fails
1068      */
1069     @Test
1070     @Alerts({"3", "SPAN"})
1071     public void insertBeforeFragment_nullRef() throws Exception {
1072         insertBeforeFragment("aNode.insertBefore(fragment, null);");
1073     }
1074 
1075     /**
1076      * @throws Exception if the test fails
1077      */
1078     @Test
1079     @Alerts("NotFoundError/DOMException")
1080     public void insertBeforeFragment_myself() throws Exception {
1081         insertBeforeFragment("aNode.insertBefore(fragment, fragment);");
1082     }
1083 
1084     /**
1085      * @throws Exception if the test fails
1086      */
1087     @Test
1088     @Alerts("ReferenceError")
1089     public void insertBeforeFragment_sibling() throws Exception {
1090         insertBeforeFragment("aNode.insertBefore(fragment, siblingNode);");
1091     }
1092 
1093     /**
1094      * Regression test to verify that insertBefore correctly appends
1095      * the new child object when the reference child object is null.
1096      * @throws Exception if the test fails
1097      */
1098     @Test
1099     @Alerts("TypeError")
1100     public void insertBeforeFragment_noSecondArg() throws Exception {
1101         insertBeforeFragment("aNode.insertBefore(fragment);");
1102     }
1103 
1104     /**
1105      * @throws Exception if the test fails
1106      */
1107     private void insertBeforeFragment(final String insertJSLine) throws Exception {
1108         final String html = DOCTYPE_HTML
1109             + "<html>\n"
1110             + "<head>\n"
1111             + "  <script>\n"
1112             + LOG_TITLE_FUNCTION
1113             + "    function doTest() {\n"
1114             + "      var fragment = document.createDocumentFragment('span');\n"
1115             + "      fragment.appendChild(document.createElement('span'));\n"
1116             + "      var aNode = document.getElementById('myNode');\n"
1117             + "      try {\n"
1118             + insertJSLine
1119             + "        log(aNode.childNodes.length);\n"
1120             + "        log(aNode.childNodes[2].nodeName);\n"
1121             + "      }\n"
1122             + "      catch(e) { logEx(e); }\n"
1123             + "    }\n"
1124             + "  </script>\n"
1125             + "</head>\n"
1126             + "<body onload='doTest()'>\n"
1127             + "<div id='myNode'><h6>Child Node 1-A</h6><h1>Child Node 2-A</h1></div>\n"
1128             + "<h2 id='sibingNode'>Sibling</h2>\n"
1129             + "</body></html>";
1130 
1131         loadPageVerifyTitle2(html);
1132     }
1133 
1134     /**
1135      * Test element.appendChild: If the parent has a null parentNode,
1136      * IE creates a DocumentFragment be the parent's parentNode.
1137      *
1138      * @throws Exception if the test fails
1139      */
1140     @Test
1141     @Alerts({"null", "null"})
1142     public void insertBefore_parentNode() throws Exception {
1143         final String html = DOCTYPE_HTML
1144             + "<html><head><script>\n"
1145             + LOG_TITLE_FUNCTION
1146             + "  function test() {\n"
1147             + "    var div1 = document.createElement('div');\n"
1148             + "    var div2 = document.createElement('div');\n"
1149             + "    log(div1.parentNode);\n"
1150             + "    div1.insertBefore(div2, null);\n"
1151             + "    if(div1.parentNode)\n"
1152             + "      log(div1.parentNode.nodeName);\n"
1153             + "    else\n"
1154             + "      log(div1.parentNode);\n"
1155             + "  }\n"
1156             + "</script></head><body onload='test()'>\n"
1157             + "</body></html>";
1158 
1159         loadPageVerifyTitle2(html);
1160     }
1161 
1162     /**
1163      * @throws Exception if the test fails
1164      */
1165     @Test
1166     @Alerts("[object HTMLTableColElement]")
1167     public void insertBefore_inTable() throws Exception {
1168         final String html = DOCTYPE_HTML
1169             + "<html><head>\n"
1170             + "<script>\n"
1171             + LOG_TITLE_FUNCTION
1172             + "function test() {\n"
1173             + "  var table = document.getElementById('myTable');\n"
1174             + "  var colGroup = table.insertBefore(document.createElement('colgroup'), null);\n"
1175             + "  log(colGroup);\n"
1176             + "}\n"
1177             + "</script></head><body onload='test()'>\n"
1178             + "  <table id='myTable'></table>\n"
1179             + "</body></html>";
1180 
1181         loadPageVerifyTitle2(html);
1182     }
1183 
1184     /**
1185      * @throws Exception on test failure
1186      */
1187     @Test
1188     @Alerts("TypeError")
1189     public void insertBefore_newElement() throws Exception {
1190         final String html = DOCTYPE_HTML
1191                 + "<html><head>\n"
1192                 + "<script>\n"
1193                 + LOG_TITLE_FUNCTION
1194                 + "function doTest() {\n"
1195                 + "  try {\n"
1196                 + "    var e = document.createElement('div');\n"
1197                 + "    e.innerHTML = 'new element';\n"
1198                 + "    document.body.insertBefore(e);\n"
1199                 + "  } catch(e) {logEx(e);}\n"
1200                 + "}\n"
1201                 + "</script>\n"
1202                 + "</head><body onload='doTest()'>\n"
1203                 + "</body></html>";
1204 
1205         loadPageVerifyTitle2(html);
1206     }
1207 
1208     /**
1209      * @throws Exception if the test fails
1210      */
1211     @Test
1212     @Alerts({"4", "3", "abc", "def", "123456", "true", "0", "2", "123", "456", "1", "true"})
1213     public void normalize() throws Exception {
1214         final String html = DOCTYPE_HTML
1215             + "<html><head><script>\n"
1216             + LOG_TITLE_FUNCTION
1217             + "  function test() {\n"
1218             + "    var doc = document.implementation.createDocument('', '', null);\n"
1219             + "    var root = doc.appendChild(doc.createElement('root'));\n"
1220             + "    var cdata = root.appendChild(doc.createCDATASection('abcdef'));\n"
1221             + "    cdata.splitText(3);\n"
1222             + "    var text = root.appendChild(doc.createTextNode('123456'));\n"
1223             + "    text.splitText(3);\n"
1224             + "    log(root.childNodes.length);\n"
1225             + "    root.normalize();\n"
1226             + "    log(root.childNodes.length);\n"
1227             + "    log(root.childNodes.item(0).data);\n"
1228             + "    log(root.childNodes.item(1).data);\n"
1229             + "    log(root.childNodes.item(2).data);\n"
1230             + "    log(root.childNodes.item(2) == text);\n"
1231             + "\n"
1232             + "    var body = document.body;\n"
1233             + "    log(body.childNodes.length);\n"
1234             + "    text = body.appendChild(document.createTextNode('123456'));\n"
1235             + "    text.splitText(3);\n"
1236             + "    log(body.childNodes.length);\n"
1237             + "    log(body.childNodes.item(0).nodeValue);\n"
1238             + "    log(body.childNodes.item(1).nodeValue);\n"
1239             + "    body.normalize();\n"
1240             + "    log(body.childNodes.length);\n"
1241             + "    log(body.childNodes.item(0) == text);\n"
1242             + "  }\n"
1243             + "</script></head><body onload='test()'></body></html>";
1244         loadPageVerifyTitle2(html);
1245     }
1246 
1247     /**
1248      * @throws Exception if the test fails
1249      */
1250     @Test
1251     @Alerts({"[object Element]", "[object HTMLHtmlElement]"})
1252     public void parentElement() throws Exception {
1253         final String html = DOCTYPE_HTML
1254             + "<html><head><script>\n"
1255             + LOG_TITLE_FUNCTION
1256             + "function test() {\n"
1257             + "  var text = '<hello>hi</hello>';\n"
1258             + "  var doc = " + callLoadXMLDocumentFromString("text") + ";\n"
1259             + "  log(doc.documentElement.firstChild.parentElement);\n"
1260             + "  log(document.body.parentElement);\n"
1261             + "}\n"
1262             + LOAD_XML_DOCUMENT_FROM_STRING_FUNCTION
1263             + "</script></head><body onload='test()'>\n"
1264             + "</body></html>";
1265 
1266         loadPageVerifyTitle2(html);
1267     }
1268 
1269     /**
1270      * @throws Exception if the test fails
1271      */
1272     @Test
1273     @Alerts({"hi", "undefined", "abcd", "undefined"})
1274     public void attributes() throws Exception {
1275         final String html = DOCTYPE_HTML
1276             + "<html><head><script>\n"
1277             + LOG_TITLE_FUNCTION
1278             + "function test() {\n"
1279             + "  var text = '<hello>hi</hello>';\n"
1280             + "  var doc = " + callLoadXMLDocumentFromString("text") + ";\n"
1281             + "  var node = doc.documentElement.firstChild;\n"
1282             + "  log(node.nodeValue);\n"
1283             + "  log(node.attributes);\n"
1284             + "\n"
1285             + "  node = document.getElementById('myId').firstChild;\n"
1286             + "  log(node.nodeValue);\n"
1287             + "  log(node.attributes);\n"
1288             + "}\n"
1289             + LOAD_XML_DOCUMENT_FROM_STRING_FUNCTION
1290             + "</script></head><body onload='test()'>\n"
1291             + "  <div id='myId'>abcd</div>\n"
1292             + "</body></html>";
1293 
1294         loadPageVerifyTitle2(html);
1295     }
1296 
1297     /**
1298      * @throws Exception if an error occurs
1299      */
1300     @Test
1301     @Alerts({"true", "true"})
1302     public void addEventListener() throws Exception {
1303         final String html = DOCTYPE_HTML
1304             + "<html>\n"
1305             + "  <head>\n"
1306             + "  <script>\n"
1307             + LOG_TITLE_FUNCTION
1308             + "    function test() {\n"
1309             + "      var node = document.createElement('button');\n"
1310             + "      log(node.addEventListener !== undefined);\n"
1311             + "      log(node.removeEventListener !== undefined);\n"
1312             + "    }\n"
1313             + "  </script>\n"
1314             + "  </head>\n"
1315             + "  <body onload='test()'>\n"
1316             + "  </body>\n"
1317             + "</html>";
1318 
1319         loadPageVerifyTitle2(html);
1320     }
1321 
1322     /**
1323      * @throws Exception if the test fails
1324      */
1325     @Test
1326     @Alerts("TypeError")
1327     public void event() throws Exception {
1328         final String firstHtml = DOCTYPE_HTML
1329             + "<html>\n"
1330             + "<head><title>First Page</title>\n"
1331             + "<script>\n"
1332             + LOG_WINDOW_NAME_FUNCTION
1333             + "  function test() {\n"
1334             + "    var iframe = document.createElement('iframe');\n"
1335             + "    document.body.appendChild(iframe);\n"
1336             + "    iframe.contentWindow.location.replace('" + URL_SECOND + "');\n"
1337             + "}\n"
1338             + "</script>\n"
1339             + "</head>\n"
1340             + "<body onload='test()'>\n"
1341             + "  <input type='button' id='myInput' value='Test me'>\n"
1342             + "  <div id='myDiv'></div>\n"
1343             + "</body>\n"
1344             + "</html>";
1345         final String secondHtml = DOCTYPE_HTML
1346             + "<html>\n"
1347             + "  <head>\n"
1348             + "    <script>\n"
1349             + LOG_WINDOW_NAME_FUNCTION
1350             + "      var handler = function() {\n"
1351             + "        log(parent.event);\n"
1352             + "        parent.document.getElementById('myDiv').style.display = 'none';\n"
1353             + "        log(parent.event);\n"
1354             + "      }\n"
1355             + "      function test() {\n"
1356             + "        try {\n"
1357             + "          parent.document.body.attachEvent('onclick', handler);\n"
1358             + "        } catch(e) { logEx(e) }\n"
1359             + "      }\n"
1360             + "    </script>\n"
1361             + "  </head>\n"
1362             + "  <body onload='test()'>\n"
1363             + "  </body>\n"
1364             + "</html>";
1365 
1366         getMockWebConnection().setResponse(URL_SECOND, secondHtml);
1367 
1368         final WebDriver driver = loadPage2(firstHtml);
1369         Thread.sleep(200);
1370         verifyWindowName2(driver, getExpectedAlerts());
1371 
1372         driver.findElement(By.id("myInput")).click();
1373     }
1374 
1375     /**
1376      * Verifies that attributes belonging to cloned nodes are available via JavaScript.
1377      * http://sourceforge.net/p/htmlunit/bugs/659/
1378      * @throws Exception if an error occurs
1379      */
1380     @Test
1381     @Alerts("id=bar")
1382     public void cloneAttributesAvailable() throws Exception {
1383         final String html = DOCTYPE_HTML
1384             + "<html>\n"
1385             + "  <head>\n"
1386             + "  <script>\n"
1387             + LOG_TITLE_FUNCTION
1388             + "    function go() {\n"
1389             + "      var node = document.getElementById('foo');\n"
1390             + "      var clone = node.cloneNode(true);\n"
1391             + "      clone.id = 'bar';\n"
1392             + "      node.appendChild(clone);\n"
1393             + "      log(clone.attributes['id'].nodeName + '=' + clone.attributes['id'].nodeValue);\n"
1394             + "    }\n"
1395             + "  </script>\n"
1396             + "  </head>\n"
1397             + "  <body onload='go()'>\n"
1398             + "    <div id='foo'></div>\n"
1399             + "  </body>\n"
1400             + "</html>";
1401 
1402         final WebDriver driver = loadPageVerifyTitle2(html);
1403 
1404         final WebElement element = driver.findElement(By.id("bar"));
1405         final String value = element.getAttribute("id");
1406         assertEquals("bar", value);
1407     }
1408 
1409     /**
1410      * @throws Exception if an error occurs
1411      */
1412     @Test
1413     @Alerts("Hello")
1414     public void setTextContent() throws Exception {
1415         final String html = DOCTYPE_HTML
1416             + "<html>\n"
1417             + "  <head>\n"
1418             + "  <script>\n"
1419             + LOG_TITLE_FUNCTION
1420             + "    function test() {\n"
1421             + "      var foo = document.getElementById('foo');\n"
1422             + "      foo.textContent = 'Hello';\n"
1423             + "      if (foo.firstChild) {\n"
1424             + "        log(foo.firstChild.wholeText);\n"
1425             + "      }\n"
1426             + "    }\n"
1427             + "  </script>\n"
1428             + "  </head>\n"
1429             + "  <body onload='test()'>\n"
1430             + "    <span id='foo'></span>\n"
1431             + "  </body>\n"
1432             + "</html>";
1433 
1434         loadPageVerifyTitle2(html);
1435     }
1436 
1437     /**
1438      * @throws Exception if an error occurs
1439      */
1440     @Test
1441     @Alerts("null")
1442     public void cloneParent() throws Exception {
1443         final String html =
1444               "<!DOCTYPE><html>\n"
1445             + "  <head>\n"
1446             + "  <script>\n"
1447             + LOG_TITLE_FUNCTION
1448             + "    function test() {\n"
1449             + "      var foo = document.getElementById('foo');\n"
1450             + "      var clone = foo.cloneNode(true);\n"
1451             + "      log(clone.parentNode);\n"
1452             + "      if (clone.parentNode) {\n"
1453             + "        log(clone.parentNode.URL);\n"
1454             + "        log(clone.parentNode.nodeType);\n"
1455             + "      }\n"
1456             + "    }\n"
1457             + "  </script>\n"
1458             + "  </head>\n"
1459             + "  <body onload='test()'>\n"
1460             + "    <span id='foo'></span>\n"
1461             + "  </body>\n"
1462             + "</html>";
1463 
1464         loadPageVerifyTitle2(html);
1465     }
1466 
1467     /**
1468      * @throws Exception if an error occurs
1469      */
1470     @Test
1471     @Alerts("<div><span></span>nullundefinedhello<p></p></div>")
1472     public void before() throws Exception {
1473         final String html = DOCTYPE_HTML
1474             + "<html><head>\n"
1475             + "  <script>\n"
1476             + LOG_TITLE_FUNCTION
1477             + "    function test() {\n"
1478             + "      var parent = document.createElement('div');\n"
1479             + "      var child = document.createElement('p');\n"
1480             + "      parent.appendChild(child);\n"
1481             + "      var span = document.createElement('span');\n"
1482             + "      if (child.before) {"
1483             + "        child.before(span, null, undefined, 'hello');\n"
1484             + "      }\n"
1485             + "      log(parent.outerHTML);\n"
1486             + "    }\n"
1487             + "  </script>\n"
1488             + "</head>\n"
1489             + "<body onload='test()'></body>\n"
1490             + "</html>";
1491 
1492         loadPageVerifyTitle2(html);
1493     }
1494 
1495     /**
1496      * @throws Exception if an error occurs
1497      */
1498     @Test
1499     @Alerts("<div><p></p><span></span>nullundefinedhello</div>")
1500     public void after() throws Exception {
1501         final String html = DOCTYPE_HTML
1502             + "<html><head>\n"
1503             + "  <script>\n"
1504             + LOG_TITLE_FUNCTION
1505             + "    function test() {\n"
1506             + "      var parent = document.createElement('div');\n"
1507             + "      var child = document.createElement('p');\n"
1508             + "      parent.appendChild(child);\n"
1509             + "      var span = document.createElement('span');\n"
1510             + "      if (child.after) {"
1511             + "        child.after(span, null, undefined, 'hello');\n"
1512             + "      }\n"
1513             + "      log(parent.outerHTML);\n"
1514             + "    }\n"
1515             + "  </script>\n"
1516             + "</head>\n"
1517             + "<body onload='test()'></body>\n"
1518             + "</html>";
1519 
1520         loadPageVerifyTitle2(html);
1521     }
1522 
1523     /**
1524      * @throws Exception if an error occurs
1525      */
1526     @Test
1527     @Alerts("<div><span></span>nullundefinedhello</div>")
1528     public void replaceWith() throws Exception {
1529         final String html = DOCTYPE_HTML
1530             + "<html><head>\n"
1531             + "  <script>\n"
1532             + LOG_TITLE_FUNCTION
1533             + "    function test() {\n"
1534             + "      var parent = document.createElement('div');\n"
1535             + "      var child = document.createElement('p');\n"
1536             + "      parent.appendChild(child);\n"
1537             + "      var span = document.createElement('span');\n"
1538             + "      if (child.replaceWith) {"
1539             + "        child.replaceWith(span, null, undefined, 'hello');\n"
1540             + "      }\n"
1541             + "      log(parent.outerHTML);\n"
1542             + "    }\n"
1543             + "  </script>\n"
1544             + "</head>\n"
1545             + "<body onload='test()'></body>\n"
1546             + "</html>";
1547 
1548         loadPageVerifyTitle2(html);
1549     }
1550 
1551     /**
1552      * @throws Exception if the test fails
1553      */
1554     @Test
1555     @Alerts({"1", "2", "§§URL§§second"})
1556     public void eventListener() throws Exception {
1557         final String html = DOCTYPE_HTML
1558             + "<html><head>\n"
1559             + "<script>\n"
1560             + LOG_WINDOW_NAME_FUNCTION
1561             + "  function clicking1() {\n"
1562             + "    log(1);\n"
1563             + "  }\n"
1564             + "  function clicking2() {\n"
1565             + "    log(2);\n"
1566             + "  }\n"
1567             + "  function test() {\n"
1568             + "    var e = document.getElementById('myAnchor');\n"
1569             + "    e.addEventListener('click', clicking1, false);\n"
1570             + "    e.addEventListener('click', clicking2, false);\n"
1571             + "  }\n"
1572             + "</script></head><body onload='test()'>\n"
1573             + "  <a href='second' id='myAnchor'>Click me</a>\n"
1574             + "</body></html>";
1575 
1576         getMockWebConnection().setDefaultResponse(DOCTYPE_HTML + "<html><body>Test</body></html>");
1577         expandExpectedAlertsVariables(URL_FIRST);
1578 
1579         final WebDriver driver = loadPage2(html);
1580         driver.findElement(By.id("myAnchor")).click();
1581         verifyWindowName2(driver, ArrayUtils.subarray(getExpectedAlerts(), 0, 2));
1582         Thread.sleep(200);
1583         assertEquals(getExpectedAlerts()[2], driver.getCurrentUrl());
1584     }
1585 
1586     /**
1587      * @throws Exception if the test fails
1588      */
1589     @Test
1590     @Alerts({"1", "2", "§§URL§§second"})
1591     public void eventListener_return_false() throws Exception {
1592         final String html = DOCTYPE_HTML
1593             + "<html><head>\n"
1594             + "<script>\n"
1595             + LOG_WINDOW_NAME_FUNCTION
1596             + "  function clicking1() {\n"
1597             + "    log(1);\n"
1598             + "  }\n"
1599             + "  function clicking2() {\n"
1600             + "    log(2);\n"
1601             + "    return false;\n"
1602             + "  }\n"
1603             + "  function test() {\n"
1604             + "    var e = document.getElementById('myAnchor');\n"
1605             + "    e.addEventListener('click', clicking1, false);\n"
1606             + "    e.addEventListener('click', clicking2, false);\n"
1607             + "  }\n"
1608             + "</script></head>\n"
1609             + "<body onload='test()'>\n"
1610             + "  <a href='second' id='myAnchor'>Click me</a>\n"
1611             + "</body></html>";
1612 
1613         getMockWebConnection().setDefaultResponse(DOCTYPE_HTML + "<html><body>Test</body></html>");
1614         expandExpectedAlertsVariables(URL_FIRST);
1615 
1616         final WebDriver driver = loadPage2(html);
1617         driver.findElement(By.id("myAnchor")).click();
1618         verifyWindowName2(driver, ArrayUtils.subarray(getExpectedAlerts(), 0, 2));
1619         Thread.sleep(200);
1620         assertEquals(getExpectedAlerts()[2], driver.getCurrentUrl());
1621     }
1622 
1623     /**
1624      * @throws Exception if the test fails
1625      */
1626     @Test
1627     @Alerts({"1", "2", "§§URL§§"})
1628     public void eventListener_returnValue_false() throws Exception {
1629         final String html = DOCTYPE_HTML
1630             + "<html><head>\n"
1631             + "<script>\n"
1632             + LOG_WINDOW_NAME_FUNCTION
1633             + "  function clicking1() {\n"
1634             + "    log(1);\n"
1635             + "  }\n"
1636             + "  function clicking2() {\n"
1637             + "    log(2);\n"
1638             + "    if (window.event)\n"
1639             + "      window.event.returnValue = false;\n"
1640             + "  }\n"
1641             + "  function test() {\n"
1642             + "    var e = document.getElementById('myAnchor');\n"
1643             + "    e.addEventListener('click', clicking1, false);\n"
1644             + "    e.addEventListener('click', clicking2, false);\n"
1645             + "  }\n"
1646             + "</script></head>\n"
1647             + "<body onload='test()'>\n"
1648             + "  <a href='second' id='myAnchor'>Click me</a>\n"
1649             + "</body></html>";
1650 
1651         getMockWebConnection().setDefaultResponse(DOCTYPE_HTML + "<html><body>Test</body></html>");
1652         expandExpectedAlertsVariables(URL_FIRST);
1653 
1654         final WebDriver driver = loadPage2(html);
1655         driver.findElement(By.id("myAnchor")).click();
1656         verifyWindowName2(driver, ArrayUtils.subarray(getExpectedAlerts(), 0, 2));
1657         Thread.sleep(200);
1658         assertEquals(getExpectedAlerts()[2], driver.getCurrentUrl());
1659     }
1660 
1661     /**
1662      * @throws Exception if the test fails
1663      */
1664     @Test
1665     @Alerts({"null", "null", "null", "null", "null", "null", "null"})
1666     public void lookupPrefix() throws Exception {
1667         final String html = DOCTYPE_HTML
1668             + "<html><head>\n"
1669             + "<script>\n"
1670             + LOG_TITLE_FUNCTION
1671             + "</script></head>\n"
1672             + "<body>\n"
1673             + "  <div id='tester'>abcd</div>\n"
1674             + "<script>\n"
1675             + "  var e = document.getElementById('tester');\n"
1676 
1677             + "  log(e.lookupPrefix('http://www.w3.org/1999/xhtml'));\n"
1678             + "  log(e.lookupPrefix('http://www.w3.org/2000/svg'));\n"
1679             + "  log(e.lookupPrefix('https://www.w3.org/1999/xlink'));\n"
1680             + "  log(e.lookupPrefix('http://www.w3.org/XML/1998/namespace'));\n"
1681             + "  log(e.lookupPrefix('http://www.w3.org/TR/html4/'));\n"
1682             + "  log(e.lookupPrefix('http://www.w3.org/1998/Math/MathML'));\n"
1683             + "  log(e.lookupPrefix('http://www.w3.org/2000/xmlns/'));\n"
1684             + "</script>\n"
1685             + "</body></html>";
1686 
1687         loadPageVerifyTitle2(html);
1688     }
1689 
1690     /**
1691      * @throws Exception if the test fails
1692      */
1693     @Test
1694     @Alerts({"null", "null", "null", "null", "null", "null", "null"})
1695     public void lookupPrefixXhtml() throws Exception {
1696         final String html
1697             = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1698             + "<!DOCTYPE html PUBLIC \n"
1699             + "  \"-//W3C//DTD XHTML 1.0 Strict//EN\" \n"
1700             + "  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
1701             + "<html xmlns='http://www.w3.org/1999/xhtml' xmlns:xhtml='http://www.w3.org/1999/xhtml'>\n"
1702             + "<head>\n"
1703             + "<script>\n"
1704             + LOG_TITLE_FUNCTION
1705             + "</script></head>\n"
1706             + "<body>\n"
1707             + "  <div id='tester'>abcd</div>\n"
1708             + "<script>\n"
1709             + "  var e = document.getElementById('tester');\n"
1710 
1711             + "  log(e.lookupPrefix('http://www.w3.org/1999/xhtml'));\n"
1712             + "  log(e.lookupPrefix('http://www.w3.org/2000/svg'));\n"
1713             + "  log(e.lookupPrefix('https://www.w3.org/1999/xlink'));\n"
1714             + "  log(e.lookupPrefix('http://www.w3.org/XML/1998/namespace'));\n"
1715             + "  log(e.lookupPrefix('http://www.w3.org/TR/html4/'));\n"
1716             + "  log(e.lookupPrefix('http://www.w3.org/1998/Math/MathML'));\n"
1717             + "  log(e.lookupPrefix('http://www.w3.org/2000/xmlns/'));\n"
1718             + "</script>\n"
1719             + "</body></html>";
1720 
1721         loadPageVerifyTitle2(html);
1722     }
1723 
1724     /**
1725      * @throws Exception if an error occurs
1726      */
1727     @Test
1728     @Alerts({"c", "null", "x", "null", "null", "null", "null", "null", "null", "null"})
1729     @HtmlUnitNYI(
1730             CHROME = {"null", "null", "null", "null", "null", "null", "null", "null", "null", "null"},
1731             EDGE = {"null", "null", "null", "null", "null", "null", "null", "null", "null", "null"},
1732             FF = {"null", "null", "null", "null", "null", "null", "null", "null", "null", "null"},
1733             FF_ESR = {"null", "null", "null", "null", "null", "null", "null", "null", "null", "null"})
1734     public void lookupPrefixXml() throws Exception {
1735         final String html = DOCTYPE_HTML
1736             + "<html>\n"
1737             + "<head>\n"
1738             + "<script>\n"
1739             + LOG_TITLE_FUNCTION
1740             + "</script>\n"
1741             + "</head>\n"
1742             + "<body>\n"
1743             + "<script>\n"
1744             + "  function tester(xml) {\n"
1745             + "    var xmlDoc = xml.responseXML;\n"
1746             + "    var x = xmlDoc.getElementsByTagName('book')[0];\n"
1747             + "    var y = xmlDoc.getElementsByTagName('book')[1];\n"
1748 
1749             + "    log(x.lookupPrefix('https://www.w3schools.com/children/'));\n"
1750             + "    log(y.lookupPrefix('https://www.w3schools.com/children/'));\n"
1751             + "    log(y.lookupPrefix('https://www.w3schools.com/xml/'));\n"
1752 
1753             + "    log(x.lookupPrefix('http://www.w3.org/1999/xhtml'));\n"
1754             + "    log(x.lookupPrefix('http://www.w3.org/2000/svg'));\n"
1755             + "    log(x.lookupPrefix('https://www.w3.org/1999/xlink'));\n"
1756             + "    log(x.lookupPrefix('http://www.w3.org/XML/1998/namespace'));\n"
1757             + "    log(x.lookupPrefix('http://www.w3.org/TR/html4/'));\n"
1758             + "    log(x.lookupPrefix('http://www.w3.org/1998/Math/MathML'));\n"
1759             + "    log(x.lookupPrefix('http://www.w3.org/2000/xmlns/'));\n"
1760 
1761             + "  }"
1762 
1763             + "  var xhr = new XMLHttpRequest();\n"
1764             + "  xhr.onreadystatechange = function() {\n"
1765             + "    if (this.readyState == 4 && this.status == 200) {\n"
1766             + "      tester(this);\n"
1767             + "    }\n"
1768             + "  };\n"
1769             + "  xhr.open('GET', '" + URL_SECOND + "', true);\n"
1770             + "  xhr.send();\n"
1771             + "</script>\n"
1772             + "</body></html>\n";
1773 
1774         final String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1775                 + "<bookstore>\n"
1776                 + "<book xmlns:c=\"https://www.w3schools.com/children/\" category=\"children\">\n"
1777                 + "<c:title c:lang=\"en\">Harry Potter</c:title>\n"
1778                 + "<c:author>J K. Rowling</c:author>\n"
1779                 + "<c:year>2005</c:year>\n"
1780                 + "<c:price>29.99</c:price>\n"
1781                 + "</book>\n"
1782                 + "<book xmlns:x=\"https://www.w3schools.com/xml/\" category=\"web\">\n"
1783                 + "<x:title x:lang=\"en\">Learning XML</x:title>\n"
1784                 + "<x:author>Erik T. Ray</x:author>\n"
1785                 + "<x:year>2003</x:year>\n"
1786                 + "<x:price>39.95</x:price>\n"
1787                 + "</book>\n"
1788                 + "</bookstore>";
1789         getMockWebConnection().setResponse(URL_SECOND, xml, MimeType.APPLICATION_XML);
1790 
1791         loadPage2(html);
1792         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), getExpectedAlerts());
1793     }
1794 }