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