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;
16  
17  import java.io.InputStream;
18  import java.net.URL;
19  import java.util.Arrays;
20  import java.util.Collections;
21  import java.util.Comparator;
22  import java.util.Map;
23  import java.util.regex.Pattern;
24  import java.util.stream.Collectors;
25  
26  import org.apache.commons.io.IOUtils;
27  import org.apache.commons.lang3.StringUtils;
28  import org.htmlunit.HttpHeader;
29  import org.htmlunit.WebDriverTestCase;
30  import org.htmlunit.junit.annotation.Alerts;
31  import org.htmlunit.junit.annotation.HtmlUnitNYI;
32  import org.junit.jupiter.api.Test;
33  import org.openqa.selenium.By;
34  import org.openqa.selenium.WebDriver;
35  
36  /**
37   * Tests for {@link Window}.
38   *
39   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
40   * @author <a href="mailto:chen_jun@users.sourceforge.net">Chen Jun</a>
41   * @author David K. Taylor
42   * @author Darrell DeBoer
43   * @author Marc Guillemot
44   * @author Dierk Koenig
45   * @author Chris Erskine
46   * @author David D. Kilzer
47   * @author Ahmed Ashour
48   * @author Daniel Gredler
49   * @author Frank Danek
50   * @author Ronald Brill
51   * @author Atsushi Nakagawa
52   */
53  public class Window3Test extends WebDriverTestCase {
54  
55      /**
56       * @throws Exception if the test fails
57       */
58      @Test
59      @Alerts("about:blank")
60      public void openWindow_emptyUrl() throws Exception {
61          final String html = DOCTYPE_HTML
62              + "<html><head>\n"
63              + "<script>\n"
64              + LOG_TITLE_FUNCTION
65              + "var w = window.open('');\n"
66              + "log(w ? w.document.location : w);\n"
67              + "</script></head>\n"
68              + "<body></body></html>";
69  
70          loadPageVerifyTitle2(html);
71      }
72  
73      /**
74       * @throws Exception if the test fails
75       */
76      @Test
77      @Alerts({"null", "one", "two", "three"})
78      public void opener() throws Exception {
79          final URL urlThird = new URL(URL_FIRST, "third/");
80  
81          final String firstContent = DOCTYPE_HTML
82              + "<html><head>\n"
83              + "<title>First</title>\n"
84              + "<script>\n"
85              + LOG_WINDOW_NAME_FUNCTION
86              + "function test() {\n"
87              + "  log(window.opener);\n"
88              + "  log('one');\n"
89              + "  open('" + URL_SECOND + "', 'foo');\n"
90              + "}\n"
91              + "function calllog(text) {\n"
92              + "  log(text);\n"
93              + "}\n"
94              + "</script></head><body onload='test()'>\n"
95              + "</body></html>";
96          final String secondContent = DOCTYPE_HTML
97              + "<html><head>\n"
98              + "<title>Second</title>\n"
99              + "<script>\n"
100             + "function test() {\n"
101             + "  opener.calllog('two');\n"
102             + "  document.form1.submit();\n"
103             + "}\n"
104             + "</script></head>\n"
105             + "<body onload='test()'>\n"
106             + "<form name='form1' action='" + urlThird + "' method='post'><input type='submit'></form>\n"
107             + "</body></html>";
108         final String thirdContent = DOCTYPE_HTML
109             + "<html><head>\n"
110             + "<title>Third</title>\n"
111             + "<script>\n"
112             + "function test() {\n"
113             + "  opener.calllog('three');\n"
114             + "}\n"
115             + "</script></head><body onload='test()'>\n"
116             + "</body></html>";
117 
118         getMockWebConnection().setResponse(URL_SECOND, secondContent);
119         getMockWebConnection().setResponse(urlThird, thirdContent);
120 
121         final WebDriver driver = loadPage2(firstContent);
122         assertTitle(driver, "First");
123         verifyWindowName2(DEFAULT_WAIT_TIME, driver, getExpectedAlerts());
124     }
125 
126     /**
127      * @throws Exception if the test fails
128      */
129     @Test
130     @Alerts("one")
131     public void windowFrames() throws Exception {
132         final String html = DOCTYPE_HTML
133             + "<html><body>\n"
134             + "<script language='JavaScript'>\n"
135             + LOG_TITLE_FUNCTION
136             + "if (typeof top.frames['anyXXXname'] == 'undefined') {\n"
137             + "  log('one');\n"
138             + "}\n"
139             + "</script></body></html>";
140 
141         loadPageVerifyTitle2(html);
142     }
143 
144     /**
145      * Variables that are defined inside JavaScript should be accessible through the
146      * window object (i.e. window.myVariable). Test that this works.
147      * @throws Exception if the test fails
148      */
149     @Test
150     @Alerts("foo")
151     public void javascriptVariableFromWindow() throws Exception {
152         final String html = DOCTYPE_HTML
153             + "<html><head></head>\n"
154             + "<body>\n"
155             + "<script>\n"
156             + LOG_TITLE_FUNCTION
157             + "myVariable = 'foo';\n"
158             + "log(window.myVariable);\n"
159             + "</script></body></head>";
160 
161         loadPageVerifyTitle2(html);
162     }
163 
164     /**
165      * Variables that are defined inside JavaScript should be accessible through the
166      * window object (ie window.myVariable). Test that this works.
167      * @throws Exception if the test fails
168      */
169     @Test
170     @Alerts({"parent.myVariable = second", "top.myVariable = first"})
171     public void javascriptVariableFromTopAndParentFrame() throws Exception {
172         final URL urlThird = new URL(URL_FIRST, "third/");
173 
174         final String firstContent = DOCTYPE_HTML
175             + "<html><head>\n"
176             + "<title>First</title>\n"
177             + "</head><body>\n"
178             + "<script>myVariable = 'first'</script>\n"
179             + "<iframe name='left' src='" + URL_SECOND + "'></iframe>\n"
180             + "</body></html>";
181 
182         final String secondContent = DOCTYPE_HTML
183             + "<html><head>\n"
184             + "<title>Second</title>\n"
185             + "</head>\n"
186             + "<body>\n"
187             + "<script>myVariable = 'second'</script>\n"
188             + "<iframe name='innermost' src='" + urlThird + "'></iframe>\n"
189             + "</body></html>";
190         getMockWebConnection().setResponse(URL_SECOND, secondContent);
191 
192         final String thirdContent = DOCTYPE_HTML
193             + "<html><head>\n"
194             + "<title>Third</title>\n"
195             + "<script>\n"
196             + "myVariable = 'third';\n"
197 
198             + LOG_WINDOW_NAME_FUNCTION
199             + "function doTest() {\n"
200             + "  log('parent.myVariable = ' + parent.myVariable);\n"
201             + "  log('top.myVariable = ' + top.myVariable);\n"
202             + "}\n"
203             + "</script></head>\n"
204             + "<body onload='doTest()'></body></html>";
205         getMockWebConnection().setResponse(urlThird, thirdContent);
206 
207         final WebDriver driver = loadPage2(firstContent);
208         assertTitle(driver, "First");
209         verifyWindowName2(driver, getExpectedAlerts());
210     }
211 
212     /**
213      * Variables that are defined inside JavaScript should be accessible through the
214      * window object (i.e. window.myVariable). Test that this works.
215      * @throws Exception if the test fails
216      */
217     @Test
218     @Alerts({"parent.second.myVariable = second", "parent.third.myVariable = third"})
219     public void javascriptVariableFromNamedFrame() throws Exception {
220         final URL urlThird = new URL(URL_FIRST, "third/");
221         final URL urlFourth = new URL(URL_FIRST, "fourth/");
222 
223         final String firstContent = DOCTYPE_HTML
224             + "<html><head><title>first</title></head>\n"
225             + "<frameset cols='20%,80%'>\n"
226             + "  <frameset rows='30%,70%'>\n"
227             + "    <frame src='" + URL_SECOND + "' name='second'>\n"
228             + "    <frame src='" + urlThird + "' name='third'>\n"
229             + "  </frameset>\n"
230             + "  <frame src='" + urlFourth + "' name='fourth'>\n"
231             + "</frameset></html>";
232 
233         final String secondContent = DOCTYPE_HTML
234             + "<html><head>\n"
235             + "<title>second</title>\n"
236             + "</head><body>\n"
237             + "<script>myVariable = 'second';</script>\n"
238             + "<p>second</p></body></html>";
239         getMockWebConnection().setResponse(URL_SECOND, secondContent);
240 
241         final String thirdContent = DOCTYPE_HTML
242             + "<html><head>\n"
243             + "<title>third</title>\n"
244             + "</head>\n"
245             + "<body>\n"
246             + "<script>myVariable = 'third';</script>\n"
247             + "<p>third</p></body></html>";
248         getMockWebConnection().setResponse(urlThird, thirdContent);
249 
250         final String fourthContent = DOCTYPE_HTML
251             + "<html><head>\n"
252             + "<title>fourth</title>\n"
253             + "</head>\n"
254             + "<body onload='doTest()'>\n"
255             + "<script>\n"
256             + "  myVariable = 'fourth';\n"
257             + LOG_WINDOW_NAME_FUNCTION
258             + "  function doTest() {\n"
259             + "    log('parent.second.myVariable = ' + parent.second.myVariable);\n"
260             + "    log('parent.third.myVariable = ' + parent.third.myVariable);\n"
261             + "}\n"
262             + "</script></body></html>";
263         getMockWebConnection().setResponse(urlFourth, fourthContent);
264 
265         final WebDriver driver = loadPage2(firstContent);
266         assertTitle(driver, "first");
267         verifyWindowName2(driver, getExpectedAlerts());
268     }
269 
270     /**
271      * Variables that have not been defined should return null when accessed.
272      * @throws Exception if the test fails
273      */
274     @Test
275     @Alerts("true")
276     public void javascriptVariableFromWindow_NotFound() throws Exception {
277         final String html = DOCTYPE_HTML
278             + "<html><head></head>\n"
279             + "<body>\n"
280             + "<script>\n"
281             + LOG_TITLE_FUNCTION
282             + "myVariable = 'foo';\n"
283             + "log(window.myOtherVariable == null);\n"
284             + "</script></body></head>";
285 
286         loadPageVerifyTitle2(html);
287     }
288 
289     /**
290      * @throws Exception if the test fails
291      */
292     @Test
293     @Alerts({"fourth-second=§§URL2§§", "fourth-third=§§URL3§§"})
294     public void getFrameByName() throws Exception {
295         final URL urlThird = new URL(URL_FIRST, "third/");
296         final URL urlFourth = new URL(URL_FIRST, "fourth/");
297 
298         final String firstContent = DOCTYPE_HTML
299             + "<html><head><title>first</title></head>\n"
300             + "<frameset cols='20%,80%'>\n"
301             + "  <frameset rows='30%,70%'>\n"
302             + "    <frame src='" + URL_SECOND + "' name='second'>\n"
303             + "    <frame src='" + urlThird + "' name='third'>\n"
304             + "  </frameset>\n"
305             + "  <frame src='" + urlFourth + "' name='fourth'>\n"
306             + "</frameset></html>";
307 
308         final String secondContent = DOCTYPE_HTML
309             + "<html><head><title>second</title></head><body><p>second</p></body></html>";
310         getMockWebConnection().setResponse(URL_SECOND, secondContent);
311 
312         final String thirdContent = DOCTYPE_HTML
313             + "<html><head><title>third</title></head><body><p>third</p></body></html>";
314         getMockWebConnection().setResponse(urlThird, thirdContent);
315 
316         final String fourthContent = DOCTYPE_HTML
317             + "<html><head>\n"
318             + "<title>fourth</title>\n"
319             + "</head>\n"
320             + "<body onload='doTest()'><script>\n"
321             + LOG_WINDOW_NAME_FUNCTION
322             + "  function doTest() {\n"
323             + "    log('fourth-second='+parent.second.document.location);\n"
324             + "    log('fourth-third='+parent.third.document.location);\n"
325             + "}\n"
326             + "</script></body></html>";
327         getMockWebConnection().setResponse(urlFourth, fourthContent);
328 
329         final String[] expectedAlerts = getExpectedAlerts();
330         for (int i = 0; i < expectedAlerts.length; i++) {
331             expectedAlerts[i] = expectedAlerts[i].replaceAll("§§URL2§§", URL_SECOND.toExternalForm())
332                     .replaceAll("§§URL3§§", urlThird.toExternalForm());
333         }
334         setExpectedAlerts(expectedAlerts);
335 
336         final WebDriver driver = loadPage2(firstContent);
337         assertTitle(driver, "first");
338         verifyWindowName2(driver, expectedAlerts);
339     }
340 
341     /**
342      * Test the <tt>window.closed</tt> property.
343      * @throws Exception if the test fails
344      */
345     @Test
346     @Alerts({"false", "false", "true"})
347     public void closed() throws Exception {
348         final String html = DOCTYPE_HTML
349             + "<html><head>\n"
350             + "<script>\n"
351             + LOG_TITLE_FUNCTION
352             + "function test() {\n"
353             + "  log(window.closed);\n"
354             + "  var newWindow = window.open('about:blank', 'foo');\n"
355             + "  log(newWindow.closed);\n"
356             + "  newWindow.close();\n"
357             + "  log(newWindow.closed);\n"
358             + "}\n"
359             + "</script></head><body onload='test()'>\n"
360             + "</body></html>";
361 
362         loadPageVerifyTitle2(html);
363     }
364 
365     /**
366      * Test that Window.moveTo method gets correctly called and handled by the scripting engine.
367      * @throws Exception if the test fails
368      */
369     @Test
370     public void moveTo() throws Exception {
371         final String html = DOCTYPE_HTML
372             + "<html><head>\n"
373             + "<script>\n"
374             + LOG_TITLE_FUNCTION
375             + "  window.moveTo(10, 20);\n"
376             + "</script></head><body>\n"
377             + "</body></html>";
378         loadPageVerifyTitle2(html);
379     }
380 
381     /**
382      * Test that Window.moveBy method gets correctly called and handled by the scripting engine.
383      * @throws Exception if the test fails
384      */
385     @Test
386     public void moveBy() throws Exception {
387         final String html = DOCTYPE_HTML
388             + "<html><head>\n"
389             + "<script>\n"
390             + LOG_TITLE_FUNCTION
391             + "  window.moveBy(10, 20);\n"
392             + "</script></head><body>\n"
393             + "</body></html>";
394         loadPageVerifyTitle2(html);
395     }
396 
397     /**
398      * Tests that the Window.resizeTo method gets correctly called and handled by the scripting engine.
399      * @throws Exception if the test fails
400      */
401     @Test
402     public void resizeTo() throws Exception {
403         final String html = DOCTYPE_HTML
404             + "<html><head>\n"
405             + "<script>\n"
406             + LOG_TITLE_FUNCTION
407             + "window.resizeTo(10, 20);\n"
408             + "window.resizeTo(-10, 20);\n"
409             + "</script></head><body></body></html>";
410         loadPageVerifyTitle2(html);
411     }
412 
413     /**
414      * Tests that the Window.resizeBy method gets correctly called and handled by the scripting engine.
415      * @throws Exception if the test fails
416      */
417     @Test
418     public void resizeBy() throws Exception {
419         final String html = DOCTYPE_HTML
420             + "<html><head>\n"
421             + "<script>\n"
422             + LOG_TITLE_FUNCTION
423             + "window.resizeBy(10, 20);\n"
424             + "window.resizeBy(-10, 20);\n"
425             + "</script></head><body></body></html>";
426         loadPageVerifyTitle2(html);
427     }
428 
429     /**
430      * Test that Window.scroll method gets correctly called and handled by the scripting engine.
431      * @throws Exception if the test fails
432      */
433     @Test
434     public void scroll() throws Exception {
435         final String html = DOCTYPE_HTML
436             + "<html><head>\n"
437             + "<script>\n"
438             + LOG_TITLE_FUNCTION
439             + "window.scroll(10, 20);\n"
440             + "</script></head><body>\n"
441             + "</body></html>";
442         loadPageVerifyTitle2(html);
443     }
444 
445     /**
446      * @throws Exception if the test fails
447      */
448     @Test
449     @Alerts({"document", "body"})
450     public void scrollEvents() throws Exception {
451         final String html = DOCTYPE_HTML
452             + "<html>\n"
453             + "<head>\n"
454             + "<script>\n"
455             + LOG_TEXTAREA_FUNCTION
456             + "  function test() {\n"
457             + "    document.addEventListener('scroll', function(e) { log(\"document\") });\n"
458             + "    window.scroll(10, 20);\n"
459             + "  }\n"
460             + "</script>\n"
461             + "</head>\n"
462             + "<body onload='test()' onscroll='log(\"body\")'>\n"
463             + "  <div onscroll='log(\"div\")' style='height: 1000px;'></div>\n"
464             + LOG_TEXTAREA
465             + "</body>\n"
466             + "</html>";
467 
468         loadPageVerifyTextArea2(html);
469     }
470 
471     /**
472      * Test that Window.scrollBy method gets correctly called and handled by the scripting engine.
473      * @throws Exception if the test fails
474      */
475     @Test
476     public void scrollBy() throws Exception {
477         final String html = DOCTYPE_HTML
478             + "<html><head>\n"
479             + "<script>\n"
480             + LOG_TITLE_FUNCTION
481             + "window.scrollBy(10, 20);\n"
482             + "</script></head>\n"
483             + "<body>\n"
484             + "</body></html>";
485         loadPageVerifyTitle2(html);
486     }
487 
488     /**
489      * @throws Exception if the test fails
490      */
491     @Test
492     @Alerts({"document [object HTMLDocument]", "body", "window [object HTMLDocument]"})
493     public void scrollByEvents() throws Exception {
494         final String html = DOCTYPE_HTML
495             + "<html>\n"
496             + "<head>\n"
497             + "<script>\n"
498             + LOG_TEXTAREA_FUNCTION
499             + "  function test() {\n"
500             + "    window.addEventListener('scroll', function(e) { log(\"window \" + e.target) });\n"
501             + "    document.addEventListener('scroll', function(e) { log(\"document \" + e.target) });\n"
502 
503             + "    window.scrollBy(10, 20);\n"
504             + "  }\n"
505             + "</script>\n"
506             + "</head>\n"
507             + "<body onload='test()' onscroll='log(\"body\")'>\n"
508             + "  <div onscroll='log(\"div\")' style='height: 1000px;'></div>\n"
509             + LOG_TEXTAREA
510             + "</body>\n"
511             + "</html>";
512 
513         loadPageVerifyTextArea2(html);
514     }
515 
516     /**
517      * Test that Window.scrollByLines method gets correctly called and handled by the scripting engine.
518      * @throws Exception if the test fails
519      */
520     @Test
521     @Alerts(DEFAULT = "TypeError",
522             FF = {},
523             FF_ESR = {})
524     public void scrollByLines() throws Exception {
525         final String html = DOCTYPE_HTML
526             + "<html><head>\n"
527             + "<script>\n"
528             + LOG_TITLE_FUNCTION
529             + "try {\n"
530             + "  window.scrollByLines(2);\n"
531             + "} catch(e) { logEx(e); }\n"
532             + "</script></head><body>\n"
533             + "</body></html>";
534         loadPageVerifyTitle2(html);
535     }
536 
537     /**
538      * Test that Window.scrollByPages method gets correctly called and handled by the scripting engine.
539      * @throws Exception if the test fails
540      */
541     @Test
542     @Alerts(DEFAULT = "TypeError",
543             FF = {},
544             FF_ESR = {})
545     public void scrollByPages() throws Exception {
546         final String html = DOCTYPE_HTML
547             + "<html><head>\n"
548             + "<script>\n"
549             + LOG_TITLE_FUNCTION
550             + "try {\n"
551             + "  window.scrollByPages(2);\n"
552             + "} catch(e) { logEx(e); }\n"
553             + "</script></head><body>\n"
554             + "</body></html>";
555         loadPageVerifyTitle2(html);
556     }
557 
558     /**
559      * Test that Window.scrollTo method gets correctly called and handled by the scripting engine.
560      * @throws Exception if the test fails
561      */
562     @Test
563     public void scrollTo() throws Exception {
564         final String html = DOCTYPE_HTML
565             + "<html><head>\n"
566             + "<script>\n"
567             + LOG_TITLE_FUNCTION
568             + "window.scrollTo(10, 20);\n"
569             + "</script></head><body>\n"
570             + "</body></html>";
571         loadPageVerifyTitle2(html);
572     }
573 
574     /**
575      * @throws Exception if the test fails
576      */
577     @Test
578     @Alerts({"document[object HTMLDocument]", "body", "document[object HTMLDocument]"})
579     public void scrollToEvents() throws Exception {
580         final String html = DOCTYPE_HTML
581             + "<html>\n"
582             + "<head>\n"
583             + "<script>\n"
584             + LOG_TEXTAREA_FUNCTION
585             + "  function test() {\n"
586             + "    window.addEventListener('scroll', function(e) { log(\"document\" + e.target) });\n"
587             + "    document.addEventListener('scroll', function(e) { log(\"document\" + e.target) });\n"
588             + "    window.scrollTo(10, 20);\n"
589             + "  }\n"
590             + "</script>\n"
591             + "</head>\n"
592             + "<body onload='test()' onscroll='log(\"body\")'>\n"
593             + "  <div onscroll='log(\"div\")' style='height: 1000px;'></div>\n"
594             + LOG_TEXTAREA
595             + "</body>\n"
596             + "</html>";
597 
598         loadPageVerifyTextArea2(html);
599     }
600 
601     /**
602      * @throws Exception if the test fails
603      */
604     @Test
605     @Alerts({"form1", "form1", "2", "2"})
606     public void formByName() throws Exception {
607         final String html = DOCTYPE_HTML
608             + "<html><head>\n"
609             + "<script>\n"
610             + LOG_TITLE_FUNCTION
611             + "  function test() {\n"
612             + "    log(window.form1.name);\n"
613             + "    log(form1.name);\n"
614             + "    log(window.form2.length);\n"
615             + "    log(form2.length);\n"
616             + "  }\n"
617             + "</script></head><body onload='test()'>\n"
618             + "  <form name='form1'></form>\n"
619             + "  <form name='form2'></form>\n"
620             + "  <form name='form2'></form>\n"
621             + "</body></html>";
622 
623         loadPageVerifyTitle2(html);
624     }
625 
626     /**
627      * @throws Exception if the test fails
628      */
629     @Test
630     @Alerts({"frame1", "frame1", "0", "0"})
631     public void frameByName() throws Exception {
632         final String html = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Frameset//EN\""
633             + "\"http://www.w3.org/TR/html4/frameset.dtd\">\n"
634             + "<html><head>\n"
635             + "<script>\n"
636             + LOG_TITLE_FUNCTION
637             + "  function test() {\n"
638             + "    log(window.frame1.name);\n"
639             + "    log(frame1.name);\n"
640             + "    log(window.frame2.length);\n"
641             + "    log(frame2.length);\n"
642             + "  }\n"
643             + "</script></head>\n"
644             + "<frameset onload='test()'>\n"
645             + "  <frame src='" + URL_SECOND + "' name='frame1'>\n"
646             + "  <frame src='" + URL_SECOND + "' name='frame2'>\n"
647             + "  <frame src='" + URL_SECOND + "' name='frame2'>\n"
648             + "</frameset>\n"
649             + "</html>";
650 
651         final String frame = DOCTYPE_HTML
652                 + "<html><head><title>frame</title></head><body></body></html>";
653         getMockWebConnection().setDefaultResponse(frame);
654 
655         loadPageVerifyTitle2(html);
656     }
657 
658     /**
659      * @throws Exception if the test fails
660      */
661     @Test
662     @Alerts({"frame1", "frame1", "0", "0"})
663     public void iframeByName() throws Exception {
664         final String html = DOCTYPE_HTML
665             + "<html><head>\n"
666             + "<script>\n"
667             + LOG_TITLE_FUNCTION
668             + "  function test() {\n"
669             + "    log(window.frame1.name);\n"
670             + "    log(frame1.name);\n"
671             + "    log(window.frame2.length);\n"
672             + "    log(frame2.length);\n"
673             + "  }\n"
674             + "</script></head><body onload='test()'>\n"
675             + "  <iframe name='frame1'></iframe>\n"
676             + "  <iframe name='frame2'></iframe>\n"
677             + "  <iframe name='frame2'></iframe>\n"
678             // iframes are treated as frames and as such have priority over other elements
679             + "  <form name='frame2'></form>\n"
680             + "</body></html>";
681 
682         loadPageVerifyTitle2(html);
683     }
684 
685     /**
686      * @throws Exception if the test fails
687      */
688     @Test
689     @Alerts({"5", "EMBED", "FORM", "IMG", "IMG", "OBJECT", "5", "EMBED", "FORM", "IMG", "IMG", "OBJECT"})
690     // The following tags cause problems with WebDriver:
691     // body, frame, frameset, head, html, isindex, meta, plaintext, title
692     // The iframe tag is treated as frame and as such has priority over the other tags, which would make the test
693     // useless.
694     public void elementsByName() throws Exception {
695         final String html = DOCTYPE_HTML
696             + "<html><head>\n"
697             + "<script>\n"
698             + LOG_TITLE_FUNCTION
699             + "  function test() {\n"
700             + "    dump(window.element1);\n"
701             + "    dump(element1);\n"
702             + "  }\n"
703             + "  function dump(c) {\n"
704             + "    log(c.length);\n"
705             + "    for (i = 0; i < c.length; i++) {\n"
706             + "      log(c.item(i).nodeName);\n"
707             + "    }\n"
708             + "  }\n"
709             + "</script></head>\n"
710             + "<body onload='test()'>\n"
711             + "  <abbr name='element1'></abbr>\n"
712             + "  <acronym name='element1'></acronym>\n"
713             + "  <a name='element1'></a>\n"
714             + "  <address name='element1'></address>\n"
715             + "  <article name='element1'></article>\n"
716             + "  <audio name='element1'></audio>\n"
717             + "  <bgsound name='element1'>\n"
718             + "  <base name='element1'>\n"
719             + "  <basefont name='element1'>\n"
720             + "  <bdo name='element1'></bdo>\n"
721             + "  <big name='element1'></big>\n"
722             + "  <blink name='element1'></blink>\n"
723             + "  <blockquote name='element1'></blockquote>\n"
724             // + "  <body name='element1'></body>\n"
725             + "  <b name='element1'></b>\n"
726             + "  <br name='element1'>\n"
727             + "  <button name='element1'></button>\n"
728             + "  <canvas name='element1'></canvas>\n"
729             + "  <caption name='element1'></caption>\n"
730             + "  <center name='element1'></center>\n"
731             + "  <cite name='element1'></cite>\n"
732             + "  <code name='element1'></code>\n"
733             + "  <datalist name='element1'></datalist>\n"
734             + "  <dfn name='element1'></dfn>\n"
735             + "  <del name='element1'></del>\n"
736             + "  <dir name='element1'></dir>\n"
737             + "  <div name='element1'></div>\n"
738             + "  <dl name='element1'>\n"
739             + "    <dt name='element1'></dt>\n"
740             + "    <dd name='element1'></dd>\n"
741             + "  </dl>\n"
742             + "  <embed name='element1'>\n"
743             + "  <em name='element1'></em>\n"
744             + "  <fieldset name='element1'></fieldset>\n"
745             + "  <figcaption name='element1'></figcaption>\n"
746             + "  <figure name='element1'></figure>\n"
747             + "  <font name='element1'></font>\n"
748             + "  <form name='element1'></form>\n"
749             + "  <footer name='element1'></footer>\n"
750             // + "  <frame name='element1'>\n"
751             // + "  <frameset name='element1'></frameset>\n"
752             + "  <h1 name='element1'></h1>\n"
753             + "  <h2 name='element1'></h2>\n"
754             + "  <h3 name='element1'></h3>\n"
755             + "  <h4 name='element1'></h4>\n"
756             + "  <h5 name='element1'></h5>\n"
757             + "  <h6 name='element1'></h6>\n"
758             // + "  <head name='element1'></head>\n"
759             + "  <header name='element1'></header>\n"
760             + "  <hr name='element1'>\n"
761             // + "  <html name='element1'></html>\n"
762             // + "  <iframe name='element1'></iframe>\n"
763             + "  <q name='element1'></q>\n"
764             + "  <ruby name='element1'>\n"
765             + "    <rt name='element1'></rt>\n"
766             + "    <rp name='element1'></rp>\n"
767             + "  </ruby>\n"
768             + "  <image name='element1'></image>\n"
769             + "  <img name='element1'>\n"
770             + "  <input name='element1'>\n"
771             + "  <ins name='element1'></ins>\n"
772             // + "  <isindex name='element1'></isindex>\n"
773             + "  <i name='element1'></i>\n"
774             + "  <kbd name='element1'></kbd>\n"
775             + "  <keygen name='element1'>\n"
776             + "  <label name='element1'></label>\n"
777             + "  <legend name='element1'></legend>\n"
778             + "  <listing name='element1'></listing>\n"
779             + "  <link name='element1'>\n"
780             + "  <map name='element1'>\n"
781             + "    <area name='element1'>\n"
782             + "  </map>\n"
783             + "  <marquee name='element1'></marquee>\n"
784             + "  <mark name='element1'></mark>\n"
785             + "  <menu name='element1'></menu>\n"
786             // + "  <meta name='element1'>\n"
787             + "  <meter name='element1'></meter>\n"
788             + "  <multicol name='element1'></multicol>\n"
789             + "  <nav name='element1'></nav>\n"
790             + "  <nextid name='element1'></nextid>\n"
791             + "  <nobr name='element1'></nobr>\n"
792             + "  <noembed name='element1'></noembed>\n"
793             + "  <noframes name='element1'></noframes>\n"
794             + "  <noscript name='element1'></noscript>\n"
795             + "  <object name='element1'>\n"
796             + "    <param name='element1'>\n"
797             + "  </object>\n"
798             + "  <ol name='element1'>\n"
799             + "    <li name='element1'></li>\n"
800             + "  </ol>\n"
801             + "  <output name='element1'></output>\n"
802             + "  <p name='element1'></p>\n"
803             // + "  <plaintext name='element1'></plaintext>\n"
804             + "  <pre name='element1'></pre>\n"
805             + "  <progress name='element1'></progress>\n"
806             + "  <s name='element1'></s>\n"
807             + "  <samp name='element1'></samp>\n"
808             + "  <script name='element1'></script>\n"
809             + "  <section name='element1'></section>\n"
810             + "  <select name='element1'>\n"
811             + "    <optgroup name='element1'>\n"
812             + "      <option name='element1'></option>\n"
813             + "    </optgroup>\n"
814             + "  </select>\n"
815             + "  <small name='element1'></small>\n"
816             + "  <source name='element1'>\n"
817             + "  <spacer name='element1'></spacer>\n"
818             + "  <span name='element1'></span>\n"
819             + "  <strike name='element1'></strike>\n"
820             + "  <strong name='element1'></strong>\n"
821             + "  <style name='element1'></style>\n"
822             + "  <sub name='element1'></sub>\n"
823             + "  <sup name='element1'></sup>\n"
824             + "  <table name='element1'>\n"
825             + "    <colgroup name='element1'>\n"
826             + "      <col name='element1'></col>\n"
827             + "    </colgroup>\n"
828             + "    <thead name='element1'>\n"
829             + "      <tr name='element1'>\n"
830             + "        <th name='element1'></th>\n"
831             + "      </tr>\n"
832             + "    </thead>\n"
833             + "    <tbody name='element1'>\n"
834             + "      <tr name='element1'>\n"
835             + "        <td name='element1'></td>\n"
836             + "      </tr>\n"
837             + "    </tbody>\n"
838             + "    <tfoot name='element1'></tfoot>\n"
839             + "  </table>\n"
840             + "  <textarea name='element1'></textarea>\n"
841             + "  <tt name='element1'></tt>\n"
842             + "  <time name='element1'></time>\n"
843             // + "  <title name='element1'></title>\n"
844             + "  <u name='element1'></u>\n"
845             + "  <ul name='element1'></ul>\n"
846             + "  <var name='element1'></var>\n"
847             + "  <video name='element1'></video>\n"
848             + "  <wbr name='element1'>\n"
849             + "  <xmp name='element1'></xmp>\n"
850             + "</body></html>";
851 
852         loadPageVerifyTitle2(html);
853     }
854 
855     /**
856      * @throws Exception if the test fails
857      */
858     @Test
859     @Alerts({"2-2", "3-3", "4-4", "5-5", "6-6", "7-7", "8-8", "9-9", "10-10", "11-11", "10-10"})
860     public void elementsByName_changedAfterGet() throws Exception {
861         final String html = DOCTYPE_HTML
862             + "<html><head>\n"
863             + "<script>\n"
864             + LOG_TITLE_FUNCTION
865             + "  function test() {\n"
866             // 2
867             + "    var collection1 = window.image1;\n"
868             + "    var collection2 = image1;\n"
869             + "    if (!collection1) {\n"
870             + "      collection1 = [];\n"
871             + "    }\n"
872             + "    if (!collection2) {\n"
873             + "      collection2 = [];\n"
874             + "    }\n"
875             + "    log(collection1.length + '-' + collection2.length);\n"
876 
877             // 3
878             + "    var newImage1 = document.createElement('img');\n"
879             + "    newImage1.name = 'image1';\n"
880             + "    document.getElementById('outer1').appendChild(newImage1);\n"
881             + "    log(collection1.length + '-' + collection2.length);\n"
882 
883             // 4
884             + "    var newImage2 = document.createElement('img');\n"
885             + "    newImage2.name = 'image1';\n"
886             + "    document.getElementById('outer2').insertBefore(newImage2, null);\n"
887             + "    log(collection1.length + '-' + collection2.length);\n"
888 
889             // 5
890             + "    var newImage3 = document.createElement('img');\n"
891             + "    newImage3.name = 'image1';\n"
892             + "    document.getElementById('outer3').replaceChild(newImage3, document.getElementById('inner3'));\n"
893             + "    log(collection1.length + '-' + collection2.length);\n"
894 
895             // 6
896             + "    document.getElementById('outer4').outerHTML = '<img name=\"image1\">';\n"
897             + "    log(collection1.length + '-' + collection2.length);\n"
898 
899             // 7
900             + "    document.getElementById('outer5').innerHTML = '<img name=\"image1\">';\n"
901             + "    log(collection1.length + '-' + collection2.length);\n"
902 
903             // 8
904             + "    document.getElementById('outer6').insertAdjacentHTML('beforeend', '<img name=\"image1\">');\n"
905             + "    log(collection1.length + '-' + collection2.length);\n"
906 
907             // 9
908             + "    document.getElementById('image3').setAttribute('name', 'image1');\n"
909             + "    log(collection1.length + '-' + collection2.length);\n"
910 
911             // 10
912             + "    var newAttr = document.createAttribute('name');\n"
913             + "    newAttr.nodeValue = 'image1';\n"
914             + "    document.getElementById('image4').setAttributeNode(newAttr);\n"
915             + "    log(collection1.length + '-' + collection2.length);\n"
916 
917             // 11
918             + "    document.getElementById('image5').setAttributeNS(null, 'name', 'image1');\n"
919             + "    log(collection1.length + '-' + collection2.length);\n"
920 
921             // 10
922             + "    document.getElementById('outer1').removeChild(newImage1);\n"
923             + "    log(collection1.length + '-' + collection2.length);\n"
924             + "  }\n"
925             + "</script></head><body onload='test()'>\n"
926             + "  <img name='image1'>\n"
927             + "  <img name='image1'>\n"
928             + "  <div id='outer1'></div>\n"
929             + "  <div id='outer2'></div>\n"
930             + "  <div id='outer3'><div id='inner3'></div></div>\n"
931             + "  <div id='outer4'></div>\n"
932             + "  <div id='outer5'></div>\n"
933             + "  <div id='outer6'></div>\n"
934             + "  <img id='image2'>\n"
935             + "  <img id='image3'>\n"
936             + "  <img id='image4'>\n"
937             + "  <img id='image5'>\n"
938             + "</body></html>";
939 
940         loadPageVerifyTitle2(html);
941     }
942 
943     /**
944      * @throws Exception if the test fails
945      */
946     @Test
947     @Alerts({"2-2", "3-3"})
948     public void elementsByName_changedAfterGet2() throws Exception {
949         final String html = DOCTYPE_HTML
950             + "<html><head>\n"
951             + "<script>\n"
952             + LOG_TITLE_FUNCTION
953             + "  function test() {\n"
954             // 2
955             + "    var collection1 = window.image1;\n"
956             + "    var collection2 = image1;\n"
957             + "    if (!collection1) {\n"
958             + "      collection1 = [];\n"
959             + "    }\n"
960             + "    if (!collection2) {\n"
961             + "      collection2 = [];\n"
962             + "    }\n"
963             + "    log(collection1.length + '-' + collection2.length);\n"
964 
965             // 3
966             + "    document.getElementById('image2').name = 'image1';\n"
967             + "    log(collection1.length + '-' + collection2.length);\n"
968             + "  }\n"
969             + "</script></head><body onload='test()'>\n"
970             + "  <img name='image1'>\n"
971             + "  <img name='image1'>\n"
972             + "  <img id='image2'>\n"
973             + "</body></html>";
974 
975         loadPageVerifyTitle2(html);
976     }
977 
978     /**
979      * @throws Exception if the test fails
980      */
981     @Test
982     @Alerts({"form1", "form1", "f1", "f1", "input1", "input1", "anchor1", "anchor1", "image1",
983                 "image1", "element1", "element1"})
984     public void elementsById() throws Exception {
985         final String html = DOCTYPE_HTML
986             + "<html><head>\n"
987             + "<script>\n"
988             + LOG_TITLE_FUNCTION
989             + "  function test() {\n"
990             + "    log(window.form1.id);\n"
991             + "    log(form1.id);\n"
992             + "    log(window.frame1.name);\n"
993             + "    log(frame1.name);\n"
994             + "    log(window.input1.id);\n"
995             + "    log(input1.id);\n"
996             + "    log(window.anchor1.id);\n"
997             + "    log(anchor1.id);\n"
998             + "    log(window.image1.id);\n"
999             + "    log(image1.id);\n"
1000             + "    log(window.element1.id);\n"
1001             + "    log(element1.id);\n"
1002             + "  }\n"
1003             + "</script></head><body onload='test()'>\n"
1004             + "  <form id='form1'></form>\n"
1005             + "  <iframe id='frame1' name='f1'></iframe>\n"
1006             + "  <input type='text' id='input1' value='1'/>\n"
1007             + "  <a id='anchor1'></a>\n"
1008             + "  <img id='image1'>\n"
1009             + "  <div id='element1'></table>\n"
1010             + "</body></html>";
1011 
1012         loadPageVerifyTitle2(html);
1013     }
1014 
1015     /**
1016      * @throws Exception if the test fails
1017      */
1018     @Test
1019     @Alerts({"f1", "f1"})
1020     public void frameById() throws Exception {
1021         final String html = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Frameset//EN\""
1022             + "\"http://www.w3.org/TR/html4/frameset.dtd\">\n"
1023             + "<html><head>\n"
1024             + "<script>\n"
1025             + LOG_TITLE_FUNCTION
1026             + "  function test() {\n"
1027             + "    log(window.frame1.name);\n"
1028             + "    log(frame1.name);\n"
1029             + "  }\n"
1030             + "</script></head>\n"
1031             + "<frameset onload='test()'>\n"
1032             + "  <frame src='" + URL_SECOND + "' id='frame1' name='f1'>\n"
1033             + "</frameset>\n"
1034             + "</html>";
1035 
1036         final String frame = DOCTYPE_HTML
1037                 + "<html><head><title>frame</title></head><body></body></html>";
1038         getMockWebConnection().setDefaultResponse(frame);
1039 
1040         loadPageVerifyTitle2(html);
1041     }
1042 
1043     /**
1044      * Test that Window.execScript method gets called correctly.
1045      * @throws Exception if the test fails
1046      */
1047     @Test
1048     @Alerts("TypeError")
1049     public void execScript() throws Exception {
1050         final String html = DOCTYPE_HTML
1051             + "<html>\n"
1052             + "<head>\n"
1053             + "<script>\n"
1054             + LOG_TITLE_FUNCTION
1055             + "  function test() {\n"
1056             + "    try {\n"
1057             + "      window.execScript('log(\"JavaScript\")', 'JavaScript');\n"
1058             + "      window.execScript('log(\"JScript\")',    'JScript');\n"
1059             + "      try {\n"
1060             + "        window.execScript('log(\"VBScript\")', 'VBScript');\n"
1061             + "      } catch(e) { log('exception1'); }\n"
1062             + "      try {\n"
1063             + "        window.execScript('log(\"BadLanguage\")', 'BadLanguage');\n"
1064             + "      } catch(e) {\n"
1065             + "        log('exception2: ' + e.message.substr(0, 20)); // msg now contains info on error location\n"
1066             + "      }\n"
1067             + "    } catch(e) { logEx(e); }\n"
1068             + "  }\n"
1069             + "</script>\n"
1070             + "</head>\n"
1071             + "<body onload='test()'>\n"
1072             + "  <div id='div1'>blah</div>\n"
1073             + "</body>\n"
1074             + "</html>";
1075 
1076         loadPageVerifyTitle2(html);
1077     }
1078 
1079     /**
1080      * @throws Exception if the test fails
1081      */
1082     @Test
1083     @Alerts({"test2", "test"})
1084     public void onLoadFunction() throws Exception {
1085         final String html = DOCTYPE_HTML
1086             + "<html>\n"
1087             + "<head>\n"
1088             + "<script>\n"
1089             + LOG_TITLE_FUNCTION
1090             + "  function test() {\n"
1091             + "    log('test');\n"
1092             + "  }\n"
1093             + "</script>\n"
1094             + "</head>\n"
1095             + "<body onload='test()'>\n"
1096             + "<script>\n"
1097             + "  var oldOnLoad = window.onload;\n"
1098             + "  window.onload = test2;\n"
1099             + "  function test2() {\n"
1100             + "    log('test2');\n"
1101             + "    oldOnLoad();\n"
1102             + "  }\n"
1103             + "</script>\n"
1104             + "</body>\n"
1105             + "</html>";
1106 
1107         loadPageVerifyTitle2(html);
1108     }
1109 
1110     /**
1111      * Verifies that you can set window.onload to something else than a function.
1112      *
1113      * @throws Exception if an error occurs
1114      */
1115     @Test
1116     @Alerts({"a", "null"})
1117     public void onloadNotAFunction() throws Exception {
1118         final String html = DOCTYPE_HTML
1119             + "<html><body>\n"
1120             + "<script>\n"
1121             + LOG_TITLE_FUNCTION
1122             + "window.onload = new function() {log('a')};\n"
1123             + "window.onload = undefined;\n"
1124             + "log(window.onload);\n"
1125             + "</script></body></html>";
1126 
1127         loadPageVerifyTitle2(html);
1128     }
1129 
1130     /**
1131      * @throws Exception if the test fails
1132      */
1133     @Test
1134     @Alerts({"false", "false", "test1", "test2", "onload"})
1135     public void addOnLoadEventListener() throws Exception {
1136         final String html = DOCTYPE_HTML
1137             + "<html>\n"
1138             + "<head>\n"
1139             + "<script>\n"
1140             + LOG_TITLE_FUNCTION
1141             + "  function test1() {log('test1');}\n"
1142             + "  function test2() {log('test2');}\n"
1143             + "  function test3() {log('test3');}\n"
1144             + "  log(window.addEventListener == null);\n"
1145             + "  log(window.removeEventListener == null);\n"
1146             + "  window.addEventListener('load', test1, true);\n"
1147             + "  window.addEventListener('load', test1, true);\n"
1148             + "  window.addEventListener('load', test2, true);\n"
1149             + "  window.addEventListener('load', test3, true);\n"
1150             + "  window.removeEventListener('load', test3, true);\n"
1151             + "</script></head>\n"
1152             + "<body onload='log(\"onload\")'></body></html>";
1153 
1154         loadPageVerifyTitle2(html);
1155     }
1156 
1157     /**
1158      * @throws Exception if the test fails
1159      */
1160     @Test
1161     @Alerts({"true", "true", "TypeError", "onload"})
1162     public void attachOnLoadEvent() throws Exception {
1163         final String html = DOCTYPE_HTML
1164             + "<html>\n"
1165             + "<head>\n"
1166             + "<script>\n"
1167             + LOG_TITLE_FUNCTION
1168             + "  function test1(_e) {log('test1, param null: ' + (_e == null));}\n"
1169             + "  function test2() {log('test2');}\n"
1170             + "  function test3() {log('test3');}\n"
1171             + "  log(window.attachEvent == null);\n"
1172             + "  log(window.detachEvent == null);\n"
1173             + "  try {\n"
1174             + "    window.attachEvent('onload', test1);\n"
1175             + "    window.attachEvent('onload', test1);\n"
1176             + "    window.attachEvent('onload', test2);\n"
1177             + "    window.attachEvent('onload', test3);\n"
1178             + "    window.detachEvent('onload', test3);\n"
1179             + "  } catch(e) { logEx(e); }\n"
1180             + "</script></head>\n"
1181             + "<body onload='log(\"onload\")'></body></html>";
1182 
1183         loadPageVerifyTitle2(html);
1184     }
1185 
1186     /**
1187      * @throws Exception if the test fails
1188      */
1189     @Test
1190     @Alerts("TypeError")
1191     public void detachEventInAttachEvent() throws Exception {
1192         final String html = DOCTYPE_HTML
1193             + "<html>\n"
1194             + "<head>\n"
1195             + "<script>\n"
1196             + LOG_TITLE_FUNCTION
1197             + "function test() {\n"
1198             + "  window.detachEvent('onload', test);\n"
1199             + "  log('detached');\n"
1200             + "}\n"
1201             + "try {\n"
1202             + "  window.attachEvent('onload', test);\n"
1203             + "} catch(e) { logEx(e); }\n"
1204             + "</script></head>\n"
1205             + "<body></body></html>";
1206 
1207         loadPageVerifyTitle2(html);
1208     }
1209 
1210     /**
1211      * Test <code>window.name</code>.
1212      *
1213      * @throws Exception if the test fails
1214      */
1215     @Test
1216     @Alerts({"window.name before: ", "window.name after: main"})
1217     public void windowName() throws Exception {
1218         shutDownAll();
1219 
1220         final String html = DOCTYPE_HTML
1221             + "<html>\n"
1222             + "<head></head>\n"
1223             + "<body>\n"
1224             + "<script>\n"
1225             + LOG_TITLE_FUNCTION
1226             + "  log('window.name before: ' + window.name);\n"
1227             + "  window.name = 'main';\n"
1228             + "  log('window.name after: ' + window.name);\n"
1229             + "</script>\n"
1230             + "</body>\n"
1231             + "</html>";
1232 
1233         loadPageVerifyTitle2(html);
1234     }
1235 
1236     /**
1237      * Tests viewport properties.
1238      * @throws Exception if the test fails
1239      */
1240     @Test
1241     @Alerts({"number", "number", "number", "number"})
1242     public void viewport() throws Exception {
1243         final String html = DOCTYPE_HTML
1244             + "<html>\n"
1245             + "<head></head>\n"
1246             + "<body>\n"
1247             + "<script>\n"
1248             + LOG_TITLE_FUNCTION
1249             + "  log(typeof window.innerWidth);\n"
1250             + "  log(typeof window.innerHeight);\n"
1251             + "  log(typeof window.outerWidth);\n"
1252             + "  log(typeof window.outerHeight);\n"
1253             + "</script>\n"
1254             + "</body>\n"
1255             + "</html>";
1256 
1257         loadPageVerifyTitle2(html);
1258     }
1259 
1260     /**
1261      * Test the <tt>Referer</tt> HTTP header by <tt>window.open</tt>.
1262      * @throws Exception if the test fails
1263      */
1264     @Test
1265     @Alerts("§§URL§§")
1266     public void openWindow_refererHeader() throws Exception {
1267         final String firstContent = DOCTYPE_HTML
1268             + "<html><head></head>\n"
1269             + "<body>\n"
1270             + "<button id='clickme' onClick='window.open(\"" + URL_SECOND + "\");'>Click me</a>\n"
1271             + "</body></html>";
1272 
1273         final String secondContent = DOCTYPE_HTML
1274             + "<html><head><title>Second</title></head><body></body></html>";
1275 
1276         getMockWebConnection().setResponse(URL_SECOND, secondContent);
1277 
1278         expandExpectedAlertsVariables(URL_FIRST);
1279         final String[] expectedAlerts = getExpectedAlerts();
1280         setExpectedAlerts();
1281 
1282         final WebDriver driver = loadPageVerifyTitle2(firstContent);
1283 
1284         driver.findElement(By.id("clickme")).click();
1285 
1286         final Map<String, String> lastAdditionalHeaders = getMockWebConnection().getLastAdditionalHeaders();
1287         if (expectedAlerts.length == 0) {
1288             assertNull(lastAdditionalHeaders.get(HttpHeader.REFERER));
1289         }
1290         else {
1291             assertEquals(expectedAlerts[0], lastAdditionalHeaders.get(HttpHeader.REFERER));
1292         }
1293     }
1294 
1295     /**
1296      * @throws Exception if the test fails
1297      */
1298     @Test
1299     @Alerts("1")
1300     public void evalScopeOtherWindow() throws Exception {
1301         final String html = DOCTYPE_HTML
1302             + "<html><body>\n"
1303             + "  <iframe src='iframe.html'></iframe>\n"
1304             + "</body></html>";
1305         final String iframe = DOCTYPE_HTML
1306             + "<html><body>\n"
1307             + "<script>\n"
1308             + LOG_WINDOW_NAME_FUNCTION
1309             + "  window.parent.eval('var foo = 1');\n"
1310             + "  log(window.parent.foo);\n"
1311             + "</script>\n"
1312             + "</body></html>";
1313 
1314         getMockWebConnection().setDefaultResponse(iframe);
1315         loadPage2(html);
1316         verifyWindowName2(getWebDriver(), getExpectedAlerts());
1317     }
1318 
1319     /**
1320      * Regression test for #408 JavaScript: window.eval does evaluate local scope.
1321      * See http://sourceforge.net/p/htmlunit/bugs/408/.
1322      * @throws Exception if the test fails
1323      */
1324     @Test
1325     @Alerts({"elementValue", "elementValue", "elementValue"})
1326     public void evalScopeLocal() throws Exception {
1327         final String html = DOCTYPE_HTML
1328             + "<html><body><form id='formtest'><input id='element' value='elementValue'/></form>\n"
1329             + "<script>\n"
1330             + LOG_TITLE_FUNCTION
1331             + "var docPatate = 'patate';\n"
1332             + "function test() {\n"
1333             + "  var f = document.forms['formtest'];\n"
1334             + "  log(eval(\"document.forms['formtest'].element.value\"));\n"
1335             + "  log(f.element.value);\n"
1336             + "  log(eval('f.element.value'));\n"
1337             + "}\n"
1338             + "test();\n"
1339             + "</script>\n"
1340             + "</body></html>";
1341 
1342         loadPageVerifyTitle2(html);
1343     }
1344 
1345     /**
1346      * Verifies that eval() works correctly when triggered from an event handler. Event handlers are
1347      * executed in a child scope of the global window scope, so variables set from inside eval()
1348      * should go to this child scope, and not to the window scope.
1349      * @throws Exception if the test fails
1350      */
1351     @Test
1352     @Alerts("string")
1353     public void evalScopeEvent() throws Exception {
1354         final String html = DOCTYPE_HTML
1355             + "<html><body onload='test()'><script>\n"
1356             + LOG_TITLE_FUNCTION
1357             + "   function test() {\n"
1358             + "     var s = 'string';\n"
1359             + "     var f = 'initial';\n"
1360             + "     eval('f = function() {log(s);}');\n"
1361             + "     invoke(f);\n"
1362             + "   }\n"
1363             + "   function invoke(fn) {\n"
1364             + "     fn();\n"
1365             + "   }\n"
1366             + "</script></body></html>";
1367 
1368         loadPageVerifyTitle2(html);
1369     }
1370 
1371     /**
1372      * @throws Exception if the test fails
1373      */
1374     @Test
1375     @Alerts("true")
1376     public void functionEquality() throws Exception {
1377         final String html = DOCTYPE_HTML
1378             + "<html><body>\n"
1379             + "<script>\n"
1380             + LOG_TITLE_FUNCTION
1381             + "  log(window.focus == window.focus);\n"
1382             + "</script>\n"
1383             + "</body></html>";
1384 
1385         loadPageVerifyTitle2(html);
1386     }
1387 
1388     /**
1389      * Test for Bug #283.
1390      *
1391      * @throws Exception if the test fails
1392      */
1393     @Test
1394     @Alerts({"123", "captured"})
1395     public void captureEvents() throws Exception {
1396         final String content = DOCTYPE_HTML
1397             + "<html><head>\n"
1398             + "<script>\n"
1399             + LOG_TITLE_FUNCTION
1400             + "  function t() { log('captured'); }\n"
1401             + "  window.captureEvents(Event.CLICK);\n"
1402             + "  window.onclick = t;\n"
1403             + "</script></head><body>\n"
1404             + "<div id='theDiv' onclick='log(123)'>foo</div>\n"
1405             + "</body></html>";
1406 
1407         final WebDriver driver = loadPage2(content);
1408 
1409         driver.findElement(By.id("theDiv")).click();
1410 
1411         verifyTitle2(driver, getExpectedAlerts());
1412     }
1413 
1414     /**
1415      * Verifies that the {@code onload} handler is executed with {@code this} referring to the window.
1416      *
1417      * @throws Exception if an error occurs
1418      */
1419     @Test
1420     @Alerts("true")
1421     public void onLoadContext() throws Exception {
1422         final String html = DOCTYPE_HTML
1423             + "<html><body>\n"
1424             + "<script>\n"
1425             + LOG_TITLE_FUNCTION
1426             + "var x = function() { log(this==window) };\n"
1427             + "window.onload = x;\n"
1428             + "</script></body></html>";
1429 
1430         loadPageVerifyTitle2(html);
1431     }
1432 
1433     /**
1434      * Added test for Bug #485.  Bad context in evaluation of the JavaScript.
1435      * @throws Exception if the test fails
1436      */
1437     @Test
1438     @Alerts("INPUT")
1439     public void eval() throws Exception {
1440         final String content = DOCTYPE_HTML
1441             + "<html><body>\n"
1442             + "<input type='button' id='myButton' value='Click Me' onclick='test(this)'>\n"
1443             + "<script>\n"
1444             + LOG_TITLE_FUNCTION
1445             + "function test(f) {\n"
1446             + "  log(eval('f.tagName'));\n"
1447             + "}\n"
1448             + "</script>\n"
1449             + "</body></html>";
1450 
1451         final WebDriver driver = loadPage2(content);
1452 
1453         driver.findElement(By.id("myButton")).click();
1454         verifyTitle2(driver, getExpectedAlerts());
1455     }
1456 
1457     /**
1458      * @throws Exception if the test fails
1459      */
1460     @Test
1461     @Alerts({"undefined", "undefined", "true"})
1462     public void undefinedProperty() throws Exception {
1463         final String html = DOCTYPE_HTML
1464             + "<html><head>\n"
1465             + "<script>\n"
1466             + LOG_TITLE_FUNCTION
1467             + "  function test() {\n"
1468             + "    log(window['something']);\n"
1469             + "    log(typeof window['something']);\n"
1470             + "    log(typeof window['something']=='undefined');\n"
1471             + "  }\n"
1472             + "</script></head><body onload='test()'>\n"
1473             + "</body></html>";
1474 
1475         loadPageVerifyTitle2(html);
1476     }
1477 
1478     /**
1479      * @throws Exception if an error occurs
1480      */
1481     @Test
1482     @Alerts("First")
1483     public void frames() throws Exception {
1484         final String html = DOCTYPE_HTML
1485             + "<html><head><title>First§</title></head>\n"
1486             + "<frameset id='fs' rows='20%,*'>\n"
1487             + "  <frame name='top' src='" + URL_SECOND + "' />\n"
1488             + "  <frame name='bottom' src='about:blank' />\n"
1489             + "</frameset>\n"
1490             + "</html>";
1491 
1492         final String frameContent = DOCTYPE_HTML
1493             + "<html><head><title>TopFrame</title>\n"
1494             + "<script>\n"
1495             + "function doTest() {\n"
1496             + "  var bottomFrame = window.top.frames['bottom'];\n"
1497             + "  bottomFrame.location = 'about:blank';\n"
1498             + "}</script>\n"
1499             + "</head>\n"
1500             + "<body onload='doTest()'></body></html>";
1501 
1502         getMockWebConnection().setResponse(URL_SECOND, frameContent);
1503 
1504         loadPageVerifyTitle2(html);
1505     }
1506 
1507     /**
1508      * @throws Exception if the test fails
1509      */
1510     @Test
1511     @Alerts("true")
1512     public void openWindow_numericName() throws Exception {
1513         final String html = DOCTYPE_HTML
1514             + "<html><head>\n"
1515             + "<script>\n"
1516             + LOG_TITLE_FUNCTION
1517             + "function test() {\n"
1518             + "  var w1 = window.open('about:blank', 1);\n"
1519             + "  log(w1 != null);\n"
1520             + "}\n"
1521             + "</script></head><body onload='test()'>\n"
1522             + "<iframe name='myFrame' id='myFrame'></iframe>\n"
1523             + "</body></html>";
1524 
1525         loadPageVerifyTitle2(html);
1526     }
1527 
1528     /**
1529      * @throws Exception if the test fails
1530      */
1531     @Test
1532     @Alerts("about:blank")
1533     public void openWindow_aboutblank_location() throws Exception {
1534         final String html = DOCTYPE_HTML
1535             + "<html><head><script>\n"
1536             + LOG_TITLE_FUNCTION
1537             + "function test() {\n"
1538             + "  var win = window.open('about:blank', 'test');\n"
1539             + "  log(win.location);\n"
1540             + "}\n"
1541             + "</script></head>\n"
1542             + "<body onload='test()'>\n"
1543             + "</body></html>";
1544 
1545         loadPageVerifyTitle2(html);
1546     }
1547 
1548     /**
1549      * @throws Exception if the test fails
1550      */
1551     @Test
1552     @Alerts("about:blank")
1553     public void openWindow_empty_location() throws Exception {
1554         final String html = DOCTYPE_HTML
1555             + "<html><head>\n"
1556             + "<script>\n"
1557             + LOG_TITLE_FUNCTION
1558             + "function test() {\n"
1559             + "  var win = window.open('', 'test');\n"
1560             + "  log(win.location);\n"
1561             + "}\n"
1562             + "</script></head>\n"
1563             + "<body onload='test()'>\n"
1564             + "</body></html>";
1565 
1566         loadPageVerifyTitle2(html);
1567     }
1568 
1569     /**
1570      * @throws Exception if the test fails
1571      */
1572     @Test
1573     @Alerts("§§URL§§img.gif")
1574     public void openWindow_aboutblank_img() throws Exception {
1575         final String html = DOCTYPE_HTML
1576             + "<html><head><script>\n"
1577             + LOG_TITLE_FUNCTION
1578             + "function test() {\n"
1579             + "  var win = window.open('about:blank', 'test', '');\n"
1580             + "  win.document.open();\n"
1581             + "  win.document.writeln('<img id=\"myImg\" src=\"img.gif\" />');\n"
1582             + "  win.document.close();\n"
1583             + "  log(win.document.getElementById('myImg').src);\n"
1584             + "}\n"
1585             + "</script></head>\n"
1586             + "<body onload='test()'>\n"
1587             + "</body></html>";
1588         getMockWebConnection().setDefaultResponse("Error: not found", 404, "Not Found",
1589                 org.htmlunit.util.MimeType.TEXT_HTML);
1590 
1591         expandExpectedAlertsVariables(URL_FIRST);
1592         loadPageVerifyTitle2(html);
1593     }
1594 
1595     /**
1596      * @throws Exception if the test fails
1597      */
1598     @Test
1599     @Alerts("§§URL§§img.gif")
1600     public void openWindow_aboutblank_document_img() throws Exception {
1601         final String html = DOCTYPE_HTML
1602             + "<html><head><script>\n"
1603             + LOG_TITLE_FUNCTION
1604             + "function test() {\n"
1605             + "  var win = window.open('about:blank', 'test');\n"
1606             + "  win.document.open();\n"
1607             + "  win.document.writeln('<html><head></head><body><img id=\"myImg\" src=\"img.gif\" /></body></html>');\n"
1608             + "  win.document.close();\n"
1609             + "  win.focus();\n"
1610             + "  log(win.document.getElementById('myImg').src);\n"
1611             + "}\n"
1612             + "</script></head>\n"
1613             + "<body onload='test()'>\n"
1614             + "</body></html>";
1615         getMockWebConnection().setDefaultResponse("Error: not found", 404, "Not Found",
1616                 org.htmlunit.util.MimeType.TEXT_HTML);
1617 
1618         expandExpectedAlertsVariables(URL_FIRST);
1619         loadPageVerifyTitle2(html);
1620     }
1621 
1622     /**
1623      * @throws Exception if the test fails
1624      */
1625     @Test
1626     @Alerts("§§URL§§img.gif")
1627     public void openWindow_empty_img() throws Exception {
1628         final String html = DOCTYPE_HTML
1629             + "<html><head>\n"
1630             + "<script>\n"
1631             + LOG_TITLE_FUNCTION
1632             + "function test() {\n"
1633             + "  var win = window.open('', 'test');\n"
1634             + "  win.document.open();\n"
1635             + "  win.document.writeln('<img id=\"myImg\" src=\"img.gif\" />');\n"
1636             + "  win.document.close();\n"
1637             + "  log(win.document.getElementById('myImg').src);\n"
1638             + "}\n"
1639             + "</script></head>\n"
1640             + "<body onload='test()'>\n"
1641             + "</body></html>";
1642         getMockWebConnection().setDefaultResponse("Error: not found", 404, "Not Found",
1643                 org.htmlunit.util.MimeType.TEXT_HTML);
1644 
1645         expandExpectedAlertsVariables(URL_FIRST);
1646         loadPageVerifyTitle2(html);
1647     }
1648 
1649     /**
1650      * @throws Exception if the test fails
1651      */
1652     @Test
1653     @Alerts("true")
1654     public void stop() throws Exception {
1655         final String html = DOCTYPE_HTML
1656             + "<html><head>\n"
1657             + "<script>\n"
1658             + LOG_TITLE_FUNCTION
1659             + "function test() {\n"
1660             + "  try {\n"
1661             + "    window.stop();\n"
1662             + "    log(true);\n"
1663             + "  } catch(e) { logEx(e); }\n"
1664             + "}\n"
1665             + "</script></head><body onload='test()'>\n"
1666             + "</body></html>";
1667 
1668         loadPageVerifyTitle2(html);
1669     }
1670 
1671     /**
1672      * @throws Exception if the test fails
1673      */
1674     @Test
1675     public void open() throws Exception {
1676         final String firstHtml = DOCTYPE_HTML
1677             + "<html><head></head>\n"
1678             + "<body>\n"
1679             + "<button id='clickme' onClick='window.open(new String(\"" + URL_SECOND + "\"));'>Click me</a>\n"
1680             + "</body></html>";
1681 
1682         final String secondHtml = DOCTYPE_HTML
1683             + "<html><head><title>Second</title></head><body></body></html>";
1684 
1685         getMockWebConnection().setResponse(URL_SECOND, secondHtml);
1686 
1687         final WebDriver driver = loadPageVerifyTitle2(firstHtml);
1688 
1689         driver.findElement(By.id("clickme")).click();
1690     }
1691 
1692     /**
1693      * @throws Exception if the test fails
1694      */
1695     @Test
1696     @Alerts("First")
1697     public void navigate() throws Exception {
1698         final String firstContent = DOCTYPE_HTML
1699             + "<html><head><title>First</title><script>\n"
1700             + "  function test() {\n"
1701             + "    if (window.navigate) {\n"
1702             + "      window.navigate('" + URL_SECOND + "');\n"
1703             + "    }\n"
1704             + "  }\n"
1705             + "</script></head><body onload='test()'>\n"
1706             + "</body></html>";
1707 
1708         final String secondContent = DOCTYPE_HTML
1709                 + "<html><head><title>Second</title></head><body></body></html>";
1710 
1711         getMockWebConnection().setResponse(URL_SECOND, secondContent);
1712 
1713         final WebDriver driver = loadPage2(firstContent, URL_FIRST);
1714         assertTitle(driver, getExpectedAlerts()[0]);
1715     }
1716 
1717     /**
1718      * @throws Exception if the test fails
1719      */
1720     @Test
1721     @Alerts("1")
1722     public void devicePixelRatio() throws Exception {
1723         final String html = DOCTYPE_HTML
1724             + "<html><head><script>\n"
1725             + LOG_TITLE_FUNCTION
1726             + "  function test() {\n"
1727             + "    log(window.devicePixelRatio);\n"
1728             + "  }\n"
1729             + "</script></head><body onload='test()'>\n"
1730             + "</body></html>";
1731 
1732         loadPageVerifyTitle2(html);
1733     }
1734 
1735     /**
1736      * @throws Exception if the test fails
1737      */
1738     @Test
1739     @Alerts(DEFAULT = "undefined",
1740             CHROME = "true",
1741             EDGE = "true")
1742     public void offscreenBuffering() throws Exception {
1743         final String html = DOCTYPE_HTML
1744             + "<html><head>\n"
1745             + "<script>\n"
1746             + LOG_TITLE_FUNCTION
1747             + "  function test() {\n"
1748             + "    log(window.offscreenBuffering);\n"
1749             + "  }\n"
1750             + "</script></head><body onload='test()'>\n"
1751             + "</body></html>";
1752 
1753         loadPageVerifyTitle2(html);
1754     }
1755 
1756     /**
1757      * @throws Exception if the test fails
1758      */
1759     @Test
1760     @Alerts("TypeError")
1761     public void getComputedStyle() throws Exception {
1762         final String html = DOCTYPE_HTML
1763             + "<html><head><script>\n"
1764             + LOG_TITLE_FUNCTION
1765             + "  function test() {\n"
1766             + "    try {\n"
1767             + "      getComputedStyle(void 0);\n"
1768             + "      log('no exception');\n"
1769             + "    } catch(e) { logEx(e) }\n"
1770             + "  }\n"
1771             + "</script></head><body onload='test()'>\n"
1772             + "</body></html>";
1773 
1774         loadPageVerifyTitle2(html);
1775     }
1776 
1777     /**
1778      * Tests the ordering of DOMContentLoaded for window and document
1779      * as well as how capturing / bubbling phases are handled.
1780      * Tests the ordering of load for window and document, and how they
1781      * relate to the onload property of 'body'.
1782      * Verifies handling of the at target phase.
1783      * Checks the state of event.eventPhase for a non-bubbling event after the bubbling phase.
1784      *
1785      * @throws Exception if the test fails
1786      */
1787     @Test
1788     @Alerts({"window DOMContentLoaded 1 capture",
1789              "window DOMContentLoaded 2 capture",
1790              "document DOMContentLoaded 1",
1791              "document DOMContentLoaded 1 capture",
1792              "document DOMContentLoaded 2",
1793              "document DOMContentLoaded 2 capture",
1794              "window DOMContentLoaded 1",
1795              "window DOMContentLoaded 2",
1796              "window at load 1",
1797              "window at load 1 capture",
1798              "window at load 2",
1799              "onload 2",
1800              "window at load 2 capture",
1801              "after"})
1802     public void onload() throws Exception {
1803         final String html = DOCTYPE_HTML
1804             + "<html><head>\n"
1805             + "<script>\n"
1806             + "  function log(msg) {\n"
1807             + "    window.parent.document.title += msg + ';';\n"
1808             + "  }\n"
1809 
1810             // These 'load' events and 'onload' property below target 'document' when fired
1811             // but path 'window' only. (Chrome/FF)
1812             // This is unlike other events where the path always includes the target and
1813             // all ancestors up to 'window'. Ascertaining this is possible by inspecting
1814             // the 'event' object which is a property of 'window' in Chrome, or
1815             // obtained via the first parameter of the event function in FF: e.g. function (event) { log('xyz', event) }
1816             + "  window.addEventListener('load', function () { log('window at load 1') })\n"
1817 
1818             // This 'onload' callback is called when the 'load' event is fired.
1819             // Ordering of the call is preserved with respect to other 'load' callbacks and is relative to
1820             // the position the property is set.  Subsequent overwriting of 'window.onload' with another
1821             // valid function does not move this position.  However, setting 'window.onload' to null or a
1822             // non-function value will reset the position and a new position us determined the next time
1823             // the property is set. The 'body' tag with an 'onload' property behaves synonymously as
1824             // writing 'window.onload = function () { ... }'
1825             // at the position the 'body' tag appears.
1826             //window.onload = function () { log('onload 1') }
1827 
1828             + "  window.addEventListener('load', function () { log('window at load 1 capture') }, true)\n"
1829             // This 'DOMContentLoaded' event targets 'document' and paths [window, document] as expected. (Chrome/FF)
1830             + "  window.addEventListener('DOMContentLoaded', function () { log('window DOMContentLoaded 1') })\n"
1831             + "  window.addEventListener('DOMContentLoaded', "
1832                     + "function () { log('window DOMContentLoaded 1 capture') }, true)\n"
1833 
1834             + "  document.addEventListener('load', function () { log('document at load 1') })\n"
1835             + "  document.addEventListener('load', function () { log('document at load 1 capture') }, true)\n"
1836             + "  document.addEventListener('DOMContentLoaded', function () { log('document DOMContentLoaded 1') })\n"
1837             + "  document.addEventListener('DOMContentLoaded', "
1838                     + "function () { log('document DOMContentLoaded 1 capture') }, true)\n"
1839             + "</script>\n"
1840             + "</head>\n"
1841             + "<body>\n"
1842             + "<script>\n"
1843             + "  window.addEventListener('load', function () { log('window at load 2') })\n"
1844             //window.onload = null
1845             //window.onload = 123
1846             + "  window.onload = function () { log('onload 2') }\n"
1847             + "  window.addEventListener('load', function () { log('window at load 2 capture') }, true)\n"
1848             + "  window.addEventListener('DOMContentLoaded', function () { log('window DOMContentLoaded 2') })\n"
1849             + "  window.addEventListener('DOMContentLoaded', "
1850                     + "function () { log('window DOMContentLoaded 2 capture') }, true)\n"
1851 
1852             + "  document.addEventListener('load', function () { log('document at load 2 capture') }, true)\n"
1853             + "  document.addEventListener('DOMContentLoaded', function () { log('document DOMContentLoaded 2') })\n"
1854             + "  document.addEventListener('DOMContentLoaded', "
1855                     + "function () { log('document DOMContentLoaded 2 capture') }, true)\n"
1856 
1857             // This is for testing the state of event.eventPhase afterwards
1858             + "  window.addEventListener('load', "
1859                     + "function (event) { var x = event; "
1860                         + "window.setTimeout(function () { log('after', x.eventPhase) }, 100) }, true)\n"
1861             + "</script>\n"
1862             + "</body></html>";
1863 
1864         final WebDriver driver = loadPage2(html);
1865         Thread.sleep(200);
1866         final String text = driver.getTitle().trim().replaceAll(";", "\n").trim();
1867         assertEquals(String.join("\n", getExpectedAlerts()), text);
1868     }
1869 
1870     /**
1871      * Tests load and error events of 'script' tags.
1872      * Checks that they should be using EventTarget.fireEvent()
1873      * rather than Event.executeEventLocally().
1874      *
1875      * @throws Exception if the test fails
1876      */
1877     @Test
1878     @Alerts({"document at load capture",
1879              "element 1 onload",
1880              "window at error capture",
1881              "document at error capture",
1882              "element 2 onerror",
1883              "document DOMContentLoaded",
1884              "window DOMContentLoaded",
1885              "window at load",
1886              "window at load capture",
1887              "body onload"})
1888     @HtmlUnitNYI(CHROME = {"element 1 onload",
1889                            "element 2 onerror",
1890                            "document DOMContentLoaded",
1891                            "window DOMContentLoaded",
1892                            "window at load",
1893                            "window at load capture",
1894                            "body onload"},
1895             EDGE = {"element 1 onload",
1896                     "element 2 onerror",
1897                     "document DOMContentLoaded",
1898                     "window DOMContentLoaded",
1899                     "window at load",
1900                     "window at load capture",
1901                     "body onload"},
1902             FF = {"element 1 onload",
1903                   "element 2 onerror",
1904                   "document DOMContentLoaded",
1905                   "window DOMContentLoaded",
1906                   "window at load",
1907                   "window at load capture",
1908                   "body onload"},
1909             FF_ESR = {"element 1 onload",
1910                       "element 2 onerror",
1911                       "document DOMContentLoaded",
1912                       "window DOMContentLoaded",
1913                       "window at load",
1914                       "window at load capture",
1915                       "body onload"})
1916     public void onloadScript() throws Exception {
1917         getMockWebConnection().setResponse(URL_SECOND, "");
1918 
1919         final String html = DOCTYPE_HTML
1920             + "<html><head>\n"
1921             + "<script>\n"
1922             + "  function log(msg) {\n"
1923             + "    window.parent.document.title += msg + ';';\n"
1924             + "  }\n"
1925 
1926             + "  window.addEventListener('load', function () { log('window at load') })\n"
1927             + "  window.addEventListener('load', function () { log('window at load capture') }, true)\n"
1928             + "  window.addEventListener('error', function () { log('window at error') })\n"
1929             + "  window.addEventListener('error', function () { log('window at error capture') }, true)\n"
1930             + "  window.addEventListener('DOMContentLoaded', function () { log('window DOMContentLoaded') })\n"
1931 
1932             + "  document.addEventListener('load', function () { log('document at load') })\n"
1933             + "  document.addEventListener('load', function () { log('document at load capture') }, true)\n"
1934             + "  document.addEventListener('error', function () { log('document at error') })\n"
1935             + "  document.addEventListener('error', function () { log('document at error capture') }, true)\n"
1936             + "  document.addEventListener('DOMContentLoaded', function () { log('document DOMContentLoaded') })\n"
1937 
1938             + "</script>\n"
1939             + "</head>\n"
1940             + "<body onload='log(\"body onload\")'>\n"
1941             + "  <script src='" + URL_SECOND + "' onload='log(\"element 1 onload\")' "
1942                                         + "onerror='log(\"element 1 onerror\")'></script>\n"
1943             + "  <script src='missing.txt' onload='log(\"element 2 onload\")' "
1944                                         + "onerror='log(\"element 2 onerror\")'></script>\n"
1945             + "</body></html>";
1946         getMockWebConnection().setDefaultResponse("Error: not found", 404, "Not Found",
1947                 org.htmlunit.util.MimeType.TEXT_HTML);
1948 
1949         final WebDriver driver = loadPage2(html);
1950         Thread.sleep(200);
1951         final String text = driver.getTitle().trim().replaceAll(";", "\n").trim();
1952         assertEquals(String.join("\n", getExpectedAlerts()), text);
1953     }
1954 
1955     /**
1956      * Tests load and error events of 'img' tags.
1957      * Checks that they should be using EventTarget.fireEvent()
1958      * rather than Event.executeEventLocally().
1959      *
1960      * @throws Exception if the test fails
1961      */
1962     @Test
1963     @Alerts(DEFAULT = {"img2: window at error capture",
1964                        "img2: document at error capture",
1965                        "img2: element 2 onerror",
1966                        "#document: document DOMContentLoaded",
1967                        "#document: window DOMContentLoaded",
1968                        "img1: document at load capture",
1969                        "img1: element 1 onload",
1970                        "#document: window at load",
1971                        "#document: window at load capture",
1972                        "#document: body onload"},
1973             CHROME = {"#document: document DOMContentLoaded",
1974                       "#document: window DOMContentLoaded",
1975                       "img2: window at error capture",
1976                       "img2: document at error capture",
1977                       "img2: element 2 onerror",
1978                       "img1: document at load capture",
1979                       "img1: element 1 onload",
1980                       "#document: window at load",
1981                       "#document: window at load capture",
1982                       "#document: body onload"})
1983     public void onloadImg() throws Exception {
1984         final URL urlImage = new URL(URL_FIRST, "img.jpg");
1985         try (InputStream is = getClass().getClassLoader().getResourceAsStream("testfiles/tiny-jpg.img")) {
1986             final byte[] directBytes = IOUtils.toByteArray(is);
1987             getMockWebConnection().setResponse(urlImage, directBytes, 200, "ok", "image/jpg", Collections.emptyList());
1988         }
1989 
1990         final String html = DOCTYPE_HTML
1991             + "<html><head>\n"
1992             + "<script>\n"
1993             + "  function log(msg, target) {\n"
1994             + "    if (target) msg = (target.id ? target.id : target.nodeName) + ': ' + msg\n"
1995             + "    window.parent.document.title += msg + ';';\n"
1996             + "  }\n"
1997 
1998             + "  window.addEventListener('load', function (event) { log('window at load', event.target) })\n"
1999             + "  window.addEventListener('load', function (event) { "
2000                                                     + "log('window at load capture', event.target) }, true)\n"
2001             + "  window.addEventListener('error', function (event) { log('window at error', event.target) })\n"
2002             + "  window.addEventListener('error', function (event) { "
2003                                                     + "log('window at error capture', event.target) }, true)\n"
2004             + "  window.addEventListener('DOMContentLoaded', function (event) { "
2005                                                     + "log('window DOMContentLoaded', event.target) })\n"
2006 
2007             + "  document.addEventListener('load', function (event) { log('document at load', event.target) })\n"
2008             + "  document.addEventListener('load', function (event) { "
2009                                                     + "log('document at load capture', event.target) }, true)\n"
2010             + "  document.addEventListener('error', function (event) { log('document at error', event.target) })\n"
2011             + "  document.addEventListener('error', function (event) { "
2012                                                     + "log('document at error capture', event.target) }, true)\n"
2013             + "  document.addEventListener('DOMContentLoaded', function (event) { "
2014                                                     + "log('document DOMContentLoaded', event.target) })\n"
2015 
2016             + "</script>\n"
2017             + "</head>\n"
2018             + "<body onload='log(\"body onload\", document)'>\n"
2019             + "  <img id='img1' src='" + urlImage + "' onload='log(\"element 1 onload\", this)' "
2020                                        + "onerror='log(\"element 1 onerror\", this)'>\n"
2021             + "  <img id='img2' src='' onload='log(\"element 2 onload\", this)' "
2022                                        + "onerror='log(\"element 2 onerror\", this)'>\n"
2023 
2024             + "</body></html>";
2025 
2026         // Image loads are usually asynchronous in browsers and ordering of these results are somewhat coincidental.
2027         //
2028         // Chrome/FF appears be synchronizing 'body.onload' so that it comes after all image loads, while Chrome
2029         // alone also seems to be synchronizing 'DOMContentLoaded' so that it fires before image loads.  IE11 is a mess
2030         // with no clear synchronization between 'body.onload' and image loads.
2031         //
2032         // To preserve a semblance of sanity, we're sorting the results because this test isn't concerned with the
2033         // ordering of img1 vs img2 vs #document (or even images vs 'body.onload'), and instead are only concerned
2034         // the events propagate in correct order once triggered.
2035         final Comparator<String> sorter = Comparator.comparing(s -> StringUtils.substringBefore(s, ":"));
2036 
2037         final WebDriver driver = loadPage2(html);
2038         Thread.sleep(200);
2039         final String text = Pattern.compile(";").splitAsStream(driver.getTitle())
2040                 .map(String::trim).sorted(sorter).collect(Collectors.joining("\n"));
2041         final String expected = Arrays.stream(getExpectedAlerts()).sorted(sorter).collect(Collectors.joining("\n"));
2042         assertEquals(expected, text);
2043     }
2044 
2045     /**
2046      * Same as {@link #onload()} but from frame.
2047      *
2048      * @throws Exception if the test fails
2049      */
2050     @Test
2051     @Alerts({"framing window DOMContentLoaded 1 capture",
2052              "framing document DOMContentLoaded 1",
2053              "framing document DOMContentLoaded 1 capture",
2054              "framing window DOMContentLoaded 1",
2055              "window DOMContentLoaded 1 capture",
2056              "window DOMContentLoaded 2 capture",
2057              "document DOMContentLoaded 1",
2058              "document DOMContentLoaded 1 capture",
2059              "document DOMContentLoaded 2",
2060              "document DOMContentLoaded 2 capture",
2061              "window DOMContentLoaded 1",
2062              "window DOMContentLoaded 2",
2063              "window at load 1",
2064              "window at load 1 capture",
2065              "window at load 2",
2066              "onload 2",
2067              "window at load 2 capture",
2068              "framing document at load 1 capture",
2069              "frame onload",
2070              "framing window at load 1",
2071              "framing window at load 1 capture",
2072              "frameset onload",
2073              "after"})
2074     public void onloadFrame() throws Exception {
2075         final String content = DOCTYPE_HTML
2076             + "<html><head>\n"
2077             + "<script>\n"
2078             + "  function log(msg) {\n"
2079             + "    window.parent.document.title += msg + ';';\n"
2080             + "  }\n"
2081 
2082             + "  window.addEventListener('load', function () { log('window at load 1') })\n"
2083 
2084             + "  window.addEventListener('load', function () { log('window at load 1 capture') }, true)\n"
2085             + "  window.addEventListener('DOMContentLoaded', function () { log('window DOMContentLoaded 1') })\n"
2086             + "  window.addEventListener('DOMContentLoaded', "
2087                     + "function () { log('window DOMContentLoaded 1 capture') }, true)\n"
2088 
2089             + "  document.addEventListener('load', function () { log('document at load 1') })\n"
2090             + "  document.addEventListener('load', function () { log('document at load 1 capture') }, true)\n"
2091             + "  document.addEventListener('DOMContentLoaded', function () { log('document DOMContentLoaded 1') })\n"
2092             + "  document.addEventListener('DOMContentLoaded', "
2093                     + "function () { log('document DOMContentLoaded 1 capture') }, true)\n"
2094             + "</script>\n"
2095             + "</head>\n"
2096             + "<body >\n"
2097             + "<script>\n"
2098             + "  window.addEventListener('load', function () { log('window at load 2') })\n"
2099             + "  window.onload = function () { log('onload 2') }\n"
2100             + "  window.addEventListener('load', function () { log('window at load 2 capture') }, true)\n"
2101             + "  window.addEventListener('DOMContentLoaded', function () { log('window DOMContentLoaded 2') })\n"
2102             + "  window.addEventListener('DOMContentLoaded', "
2103                     + "function () { log('window DOMContentLoaded 2 capture') }, true)\n"
2104 
2105             + "  document.addEventListener('load', function () { log('document at load 2 capture') }, true)\n"
2106             + "  document.addEventListener('DOMContentLoaded', function () { log('document DOMContentLoaded 2') })\n"
2107             + "  document.addEventListener('DOMContentLoaded', "
2108                     + "function () { log('document DOMContentLoaded 2 capture') }, true)\n"
2109 
2110             + "  window.addEventListener('load', "
2111                     + "function (event) { var x = event; "
2112                         + "window.setTimeout(function () { log('after', x.eventPhase) }, 100) }, true)\n"
2113             + "</script>\n"
2114             + "</body></html>";
2115 
2116         getMockWebConnection().setDefaultResponse(content);
2117 
2118         final String html = DOCTYPE_HTML
2119                 + "<html><head>\n"
2120                 + "<script>\n"
2121                 + "  function log(msg) {\n"
2122                 + "    window.document.title += msg + ';';\n"
2123                 + "  }\n"
2124 
2125                 + "  window.addEventListener('load', function () { log('framing window at load 1') })\n"
2126                 + "  window.addEventListener('load', function () { log('framing window at load 1 capture') }, true)\n"
2127                 + "  window.addEventListener('DOMContentLoaded', "
2128                             + "function () { log('framing window DOMContentLoaded 1') })\n"
2129                 + "  window.addEventListener('DOMContentLoaded', "
2130                             + "function () { log('framing window DOMContentLoaded 1 capture') }, true)\n"
2131 
2132                 // should not fire because bubbles = false
2133                 + "  document.addEventListener('load', "
2134                             + "function () { log('framing document at load 1') })\n"
2135                 + "  document.addEventListener('load', "
2136                             + "function () { log('framing document at load 1 capture') }, true)\n"
2137                 + "  document.addEventListener('DOMContentLoaded', "
2138                             + "function () { log('framing document DOMContentLoaded 1') })\n"
2139                 + "  document.addEventListener('DOMContentLoaded', "
2140                             + "function () { log('framing document DOMContentLoaded 1 capture') }, true)\n"
2141                 + "</script>\n"
2142                 + "</head>\n"
2143                 + "<frameset onload='log(\"frameset onload\")'>\n"
2144                 + "<frame src='test_onload.html' onload='log(\"frame onload\")'>\n"
2145                 + "</frameset>\n"
2146                 + "</html>";
2147 
2148         final WebDriver driver = loadPage2(html);
2149         Thread.sleep(200);
2150         final String text = driver.getTitle().trim().replaceAll(";", "\n").trim();
2151         assertEquals(String.join("\n", getExpectedAlerts()), text);
2152     }
2153 
2154     /**
2155      * @throws Exception if the test fails
2156      */
2157     @Test
2158     @Alerts({"function () { log(\"onload from body\") }",
2159              "function () { log(\"onload from body\") }",
2160              "function () { log(\"onload from window\") }",
2161              "function () { log(\"onload from window\") }",
2162              "null",
2163              "null",
2164              "function () { log(\"onload from body\") }",
2165              "function () { log(\"onload from body\") }",
2166              "onload from body"})
2167     public void onloadFromBody() throws Exception {
2168         final String html = DOCTYPE_HTML
2169             + "<html><head>\n"
2170             + "</head>\n"
2171             + "<body>\n"
2172             + "<script>\n"
2173             + "  function log(msg) {\n"
2174             + "    window.parent.document.title += ('' + msg).replace(';', '') + ';';\n"
2175             + "  }\n"
2176 
2177             + "  document.body.onload = function () { log(\"onload from body\") };\n"
2178             + "  log(document.body.onload);\n"
2179             + "  log(window.onload);\n"
2180 
2181             + "  window.onload = function () { log(\"onload from window\") };\n"
2182             + "  log(document.body.onload);\n"
2183             + "  log(window.onload);\n"
2184 
2185             + "  window.onload = undefined;\n"
2186             + "  log(document.body.onload);\n"
2187             + "  log(window.onload);\n"
2188 
2189             + "  document.body.onload = function () { log(\"onload from body\") };\n"
2190             + "  log(document.body.onload);\n"
2191             + "  log(window.onload);\n"
2192 
2193             + "</script>\n"
2194             + "</body></html>";
2195 
2196         final WebDriver driver = loadPage2(html);
2197         final String text = driver.getTitle().trim().replaceAll(";", "\n").trim();
2198         assertEquals(String.join("\n", getExpectedAlerts()), text);
2199     }
2200 
2201     /**
2202      * @throws Exception if the test fails
2203      */
2204     @Test
2205     @Alerts({})
2206     public void onloadListenerFromBody() throws Exception {
2207         final String html = DOCTYPE_HTML
2208             + "<html><head>\n"
2209             + "</head>\n"
2210             + "<body>\n"
2211             + "<script>\n"
2212             + "  function log(msg) {\n"
2213             + "    window.parent.document.title += msg + ';';\n"
2214             + "  }\n"
2215 
2216             + "  document.body.addEventListener(\"load\", function () { log(\"onload from body\") });\n"
2217             + "</script>\n"
2218             + "</body></html>";
2219 
2220         final WebDriver driver = loadPage2(html);
2221         final String text = driver.getTitle().trim().replaceAll(";", "\n").trim();
2222         assertEquals(String.join("\n", getExpectedAlerts()), text);
2223     }
2224 
2225     /**
2226      * @throws Exception if the test fails
2227      */
2228     @Test
2229     @Alerts("onload from window")
2230     public void onloadListenerFromBodyAndWindow() throws Exception {
2231         final String html = DOCTYPE_HTML
2232             + "<html><head>\n"
2233             + "</head>\n"
2234             + "<body>\n"
2235             + "<script>\n"
2236             + "  function log(msg) {\n"
2237             + "    window.parent.document.title += msg + ';';\n"
2238             + "  }\n"
2239 
2240             + "  document.body.addEventListener(\"load\", function () { log(\"onload from body\") });\n"
2241             + "  window.addEventListener(\"load\", function () { log(\"onload from window\") });\n"
2242 
2243             + "</script>\n"
2244             + "</body></html>";
2245 
2246         final WebDriver driver = loadPage2(html);
2247         final String text = driver.getTitle().trim().replaceAll(";", "\n").trim();
2248         assertEquals(String.join("\n", getExpectedAlerts()), text);
2249     }
2250 
2251     /**
2252      * @throws Exception if the test fails
2253      */
2254     @Test
2255     @Alerts({})
2256     public void onloadListenerFromBodyAndWindowRemoved() throws Exception {
2257         final String html = DOCTYPE_HTML
2258             + "<html><head>\n"
2259             + "</head>\n"
2260             + "<body>\n"
2261             + "<script>\n"
2262             + "  function log(msg) {\n"
2263             + "    window.parent.document.title += msg + ';';\n"
2264             + "  }\n"
2265 
2266             + "  document.body.addEventListener(\"load\", function () { log(\"onload from body\") });\n"
2267             + "  function evt() { log(\"onload from window\") }"
2268             + "  window.addEventListener(\"load\", evt);\n"
2269             + "  window.removeEventListener(\"load\", evt);\n"
2270 
2271             + "</script>\n"
2272             + "</body></html>";
2273 
2274         final WebDriver driver = loadPage2(html);
2275         final String text = driver.getTitle().trim().replaceAll(";", "\n").trim();
2276         assertEquals(String.join("\n", getExpectedAlerts()), text);
2277     }
2278 
2279     /**
2280      * Tests propagation of a more or less basic event (click event) with regards to
2281      * handling of the capturing / bubbling / at target phases.
2282      * Tests listener and property handler ordering.
2283      *
2284      * @throws Exception if the test fails
2285      */
2286     @Test
2287     @Alerts({"window at click 1 capture",
2288                 "window at click 2 capture",
2289                 "onclick 2",
2290                 "i1 at click 1",
2291                 "i1 at click 1 capture",
2292                 "i1 at click 2",
2293                 "i1 at click 2 capture",
2294                 "window at click 1",
2295                 "window at click 2"})
2296     public void propagation() throws Exception {
2297         final String html = DOCTYPE_HTML
2298             + "<html><head>\n"
2299             + "<script>\n"
2300             + "  function log(msg) {\n"
2301             + "    window.parent.document.title += msg + ';';\n"
2302             + "  }\n"
2303             + "</script>\n"
2304             + "</head>\n"
2305             + "<body>\n"
2306             + "  <input id='tester' type='button' value='test' onclick='log(\"onclick\")'>\n"
2307 
2308             + "<script>\n"
2309             + "  window.addEventListener('click', function () { log('window at click 1') })\n"
2310             + "  window.addEventListener('click', function () { log('window at click 1 capture') }, true)\n"
2311             + "  window.addEventListener('click', function () { log('window at click 2') })\n"
2312             + "  window.addEventListener('click', function () { log('window at click 2 capture') }, true)\n"
2313 
2314             + "  tester.addEventListener('click', function () { log('i1 at click 1') })\n"
2315             + "  tester.addEventListener('click', function () { log('i1 at click 1 capture') }, true)\n"
2316             + "  tester.addEventListener('click', function () { log('i1 at click 2') })\n"
2317             + "  tester.onclick = function () { log('onclick 2') }\n"
2318             + "  tester.addEventListener('click', function () { log('i1 at click 2 capture') }, true)\n"
2319             + "</script>\n"
2320             + "</body></html>";
2321 
2322         final WebDriver driver = loadPage2(html);
2323         driver.findElement(By.id("tester")).click();
2324 
2325         final String text = driver.getTitle().trim().replaceAll(";", "\n").trim();
2326         assertEquals(String.join("\n", getExpectedAlerts()), text);
2327     }
2328 
2329     /**
2330      * Similar as {@link #propagation()} except with a deeper propagation path.
2331      * Check bubbling propagation after modification of the DOM tree by an intermediate listener.
2332      *
2333      * @throws Exception if the test fails
2334      */
2335     @Test
2336     @Alerts({"window at click 1 capture",
2337              "window at click 2 capture",
2338              "d1 at click 1 capture",
2339              "d1 at click 2 capture",
2340              "d2 at click 1 capture",
2341              "d2 at click 2 capture",
2342              "d3 at click 1",
2343              "d3 onclick",
2344              "d3 at click 1 capture",
2345              "d3 at click 2",
2346              "d3 at click 2 capture",
2347              "d2 at click 1",
2348              "d2 onclick",
2349              "d2 at click 2",
2350              "d1 at click 1",
2351              "d1 onclick",
2352              "d1 at click 2",
2353              "window at click 1",
2354              "window at click 2"})
2355     public void propagationNested() throws Exception {
2356         final String html = DOCTYPE_HTML
2357             + "<html><head>\n"
2358             + "<script>\n"
2359             + "  function log(msg) {\n"
2360             + "    window.parent.document.title += msg + ';';\n"
2361             + "  }\n"
2362             + "</script>\n"
2363             + "</head>\n"
2364             + "<body>\n"
2365             + "  <div id='d1' style='width: 150px; height: 150px; background-color: blue'>\n"
2366             + "    <div id='d2' style='width: 100px; height: 100px; background-color: green'>\n"
2367             + "      <div id='d3' style='width: 50px; height: 50px; background-color: red'>\n"
2368             + "      </div>\n"
2369             + "    </div>\n"
2370             + "  </div>\n"
2371 
2372             + "<script>\n"
2373             + "  window.addEventListener('click', function () { log('window at click 1') })\n"
2374             + "  window.addEventListener('click', function () { log('window at click 1 capture') }, true)\n"
2375             + "  window.addEventListener('click', function () { log('window at click 2') })\n"
2376             + "  window.addEventListener('click', function () { log('window at click 2 capture') }, true)\n"
2377 
2378             + "  d1.addEventListener('click', function () { log('d1 at click 1') })\n"
2379             + "  d1.onclick = function () { log('d1 onclick') }\n"
2380             + "  d1.addEventListener('click', function () { log('d1 at click 1 capture') }, true)\n"
2381             + "  d1.addEventListener('click', function () { log('d1 at click 2') })\n"
2382             + "  d1.addEventListener('click', function () { log('d1 at click 2 capture') }, true)\n"
2383 
2384             + "  d2.addEventListener('click', function () { log('d2 at click 1') })\n"
2385             + "  d2.onclick = function () { log('d2 onclick'); d2.parentNode.removeChild(d2) }\n"
2386             + "  d2.addEventListener('click', function () { log('d2 at click 1 capture') }, true)\n"
2387             + "  d2.addEventListener('click', function () { log('d2 at click 2') })\n"
2388             + "  d2.addEventListener('click', function () { log('d2 at click 2 capture') }, true)\n"
2389 
2390             + "  d3.addEventListener('click', function () { log('d3 at click 1') })\n"
2391             + "  d3.onclick = function () { log('d3 onclick') }\n"
2392             + "  d3.addEventListener('click', function () { log('d3 at click 1 capture') }, true)\n"
2393             + "  d3.addEventListener('click', function () { log('d3 at click 2') })\n"
2394             + "  d3.addEventListener('click', function () { log('d3 at click 2 capture') }, true)\n"
2395             + "</script>\n"
2396             + "</body></html>";
2397 
2398         final WebDriver driver = loadPage2(html);
2399         driver.findElement(By.id("d3")).click();
2400 
2401         final String text = driver.getTitle().trim().replaceAll(";", "\n").trim();
2402         assertEquals(String.join("\n", getExpectedAlerts()), text);
2403     }
2404 
2405     /**
2406      * Similar as {@link #propagationNested()} but clicking a detached element.
2407      * Check bubbling propagation after modification of the DOM tree by an intermediate listener.
2408      *
2409      * @throws Exception if the test fails
2410      */
2411     @Test
2412     @Alerts({"window at click 1 capture",
2413                 "window at click 2 capture",
2414                 "begin detach click",
2415                 "d2 at click 1 capture",
2416                 "d2 at click 2 capture",
2417                 "d3 at click 1",
2418                 "d3 onclick",
2419                 "d3 at click 1 capture",
2420                 "d3 at click 2",
2421                 "d3 at click 2 capture",
2422                 "d2 at click 1",
2423                 "d2 onclick",
2424                 "d2 at click 2",
2425                 "end detach click",
2426                 "window at click 1",
2427                 "window at click 2"})
2428     public void propagationNestedDetached() throws Exception {
2429         final String html = DOCTYPE_HTML
2430             + "<html><head>\n"
2431             + "<script>\n"
2432             + "  function log(msg) {\n"
2433             + "    window.parent.document.title += msg + ';';\n"
2434             + "  }\n"
2435 
2436             + "  function detachAndClick() {\n"
2437             + "    log('begin detach click')\n"
2438             + "    var d2 = window.d2, d3 = window.d3\n"
2439             + "    d2.parentNode.removeChild(d2);\n"
2440             + "    d3.click();\n"
2441             + "    log('end detach click')\n"
2442             + "  }\n"
2443             + "</script>\n"
2444             + "</head>\n"
2445             + "<body>\n"
2446             + "  <div id='d1' style='width: 150px; height: 150px; background-color: blue'>\n"
2447             + "    <div id='d2' style='width: 100px; height: 100px; background-color: green'>\n"
2448             + "      <div id='d3' style='width: 50px; height: 50px; background-color: red'>\n"
2449             + "      </div>\n"
2450             + "    </div>\n"
2451             + "  </div>\n"
2452             + "  <input id='detach_click' type='button' value='Detach & click' onclick='detachAndClick()'>\n"
2453 
2454             + "<script>\n"
2455             + "  d2 = window.d2, d3 = window.d3\n" // Save because "Detach & click" removes them
2456             + "  window.addEventListener('click', function () { log('window at click 1') })\n"
2457             + "  window.addEventListener('click', function () { log('window at click 1 capture') }, true)\n"
2458             + "  window.addEventListener('click', function () { log('window at click 2') })\n"
2459             + "  window.addEventListener('click', function () { log('window at click 2 capture') }, true)\n"
2460 
2461             + "  d1.addEventListener('click', function () { log('d1 at click 1') })\n"
2462             + "  d1.onclick = function () { log('d1 onclick') }\n"
2463             + "  d1.addEventListener('click', function () { log('d1 at click 1 capture') }, true)\n"
2464             + "  d1.addEventListener('click', function () { log('d1 at click 2') })\n"
2465             + "  d1.addEventListener('click', function () { log('d1 at click 2 capture') }, true)\n"
2466 
2467             + "  d2.addEventListener('click', function () { log('d2 at click 1') })\n"
2468             + "  d2.onclick = function () { log('d2 onclick'); if (d2.parentNode) d2.parentNode.removeChild(d2) }\n"
2469             + "  d2.addEventListener('click', function () { log('d2 at click 1 capture') }, true)\n"
2470             + "  d2.addEventListener('click', function () { log('d2 at click 2') })\n"
2471             + "  d2.addEventListener('click', function () { log('d2 at click 2 capture') }, true)\n"
2472 
2473             + "  d3.addEventListener('click', function () { log('d3 at click 1') })\n"
2474             + "  d3.onclick = function () { log('d3 onclick') }\n"
2475             + "  d3.addEventListener('click', function () { log('d3 at click 1 capture') }, true)\n"
2476             + "  d3.addEventListener('click', function () { log('d3 at click 2') })\n"
2477             + "  d3.addEventListener('click', function () { log('d3 at click 2 capture') }, true)\n"
2478             + "</script>\n"
2479             + "</body></html>";
2480 
2481         final WebDriver driver = loadPage2(html);
2482         driver.findElement(By.id("detach_click")).click();
2483 
2484         final String text = driver.getTitle().trim().replaceAll(";", "\n").trim();
2485         assertEquals(String.join("\n", getExpectedAlerts()), text);
2486     }
2487 
2488     /**
2489      * This test determines that the return value of listeners are apparently
2490      * ignored and only that of the property handler is used.
2491      *
2492      * @throws Exception if the test fails
2493      */
2494     @Test
2495     @Alerts({"listener: stop propagation & return false",
2496              "FIRED a1",
2497              "listener: return true",
2498              "property: return false",
2499              "listener: return true",
2500              "listener: prevented=false returnValue: true -> false (false)",
2501              "listener: prevented=true returnValue: false -> true (false)",
2502              "listener: prevented=true returnValue: false -> preventDefault() (false)",
2503              "property: prevented=true returnValue: false -> return true",
2504              "listener: prevented=true returnValue: false -> x (false)",
2505              "listener: prevented=true returnValue: false -> null (false)"})
2506     public void stopPropagation() throws Exception {
2507         final String html = DOCTYPE_HTML
2508             + "<html><head>\n"
2509             + "<script>\n"
2510             + "  function log(msg) {\n"
2511             + "    window.parent.document.title += msg + ';';\n"
2512             + "  }\n"
2513             + "</script>\n"
2514             + "</head>\n"
2515             + "<body>\n"
2516             + "  <div><a id='a1' href='javascript:log(\"FIRED a1\")'>test: listener return false</a></div>\n"
2517             + "  <div><a id='a2' href='javascript:log(\"FIRED a2\")'>test: property return false</a></div>\n"
2518             + "  <div><a id='a3' href='javascript:log(\"FIRED a3\")'>test: listener returnValue = false</a></div>\n"
2519 
2520             + "  <textarea id='log' rows=40 cols=80></textarea>\n"
2521 
2522             + "<script>\n"
2523             // The event.stopPropagation() has no bearing on whether 'return false'
2524             // below is effective at preventing "href" processing.
2525             + "  a1.addEventListener('click', function (event) { "
2526                                                 + "log('listener: stop propagation & return false');"
2527                                                 + "event.stopPropagation(); return false })\n"
2528 
2529             // The only return value that matters is the value from the 'onclick' property.  The 'return false' below
2530             // prevents "href' being processed.
2531             + "  a2.addEventListener('click',"
2532             + "        function (event) { log('listener: return true'); event.stopPropagation(); return true })\n"
2533             + "  a2.onclick = function () { log('property: return false'); return false }\n"
2534             + "  a2.addEventListener('click', function (event) { log('listener: return true'); return true })\n"
2535 
2536             // Uncommenting this causes a2 to fire because propagation is
2537             // stopped before 'onclick' property is processed.
2538             // Again, the 'return false' here is ineffective.
2539             // The return values of non-property handlers are probably ignored. (tested in Chrome/FF)
2540             //window.addEventListener("click", function (event) {
2541             //                  log('window: stop propagation & return false');
2542             //                  event.stopPropagation(); return false }, true)
2543 
2544             // In Chrome, this sets event.returnValue to 'false'
2545             // which is synonymous with setting 'event.defaultPrevented'
2546             // In FF/IE11, event.returnValue is settable but does not appear to be used for anything
2547             + "  a3.addEventListener('click', function (event) {"
2548             + "      var a = event.returnValue, p = event.defaultPrevented, b = false; event.returnValue = b;"
2549             + "      log('listener: prevented=' + p + ' returnValue: ' + a "
2550                                     + "+ ' -> ' + b + ' (' + event.returnValue + ')') })\n"
2551              // This shows it's possible to set event.returnValue back to 'true' from 'false'
2552             + "  a3.addEventListener('click', function (event) {"
2553             + "      var a = event.returnValue, p = event.defaultPrevented, b = true; event.returnValue = b;"
2554             + "      log('listener: prevented=' + p + ' returnValue: ' + a "
2555                                     + "+ ' -> ' + b + ' (' + event.returnValue + ')') })\n"
2556             // The value of event.returnValue is consistent across multiple listener calls of the same event
2557             + "  a3.addEventListener('click', function (event) {"
2558             + "      var a = event.returnValue, p = event.defaultPrevented, "
2559                                     + "b = 'preventDefault()'; event.preventDefault();"
2560             + "      log('listener: prevented=' + p + ' returnValue: ' + a "
2561                                     + "+ ' -> ' + b + ' (' + event.returnValue + ')') })\n"
2562             // This shows a property handler returning 'true' will not change event.returnValue if it's already 'false'
2563             + "  a3.onclick = function (event) {"
2564             + "      var a = event.returnValue, p = event.defaultPrevented; b = true;"
2565             + "      log('property: prevented=' + p + ' returnValue: ' + a + ' -> return ' + b); return b }\n"
2566             // Instead of returning 'true', the property handler can directly set
2567             // event.returnValue to set it to 'true' from 'false'
2568             //+ "  a3.onclick = function (event) {"
2569             //+ "      var a = event.returnValue, p = event.defaultPrevented; b = true;"
2570             //+ "      log('property: prevented=' + p + ' returnValue: ' + a + ' -> true'); event.returnValue = b }\n"
2571             // These shows setting event.returnValue cannot be set to a non-boolean
2572             // value in Chrome but can in (FF/IE11)
2573             + "  a3.addEventListener('click', function (event) {"
2574             + "        var a = event.returnValue, p = event.defaultPrevented, b = 'x'; event.returnValue = b;"
2575             + "        log('listener: prevented=' + p + ' returnValue: ' + a "
2576                                     + "+ ' -> ' + b + ' (' + event.returnValue + ')') })\n"
2577             + "  a3.addEventListener('click', function (event) {"
2578             + "        var a = event.returnValue, p = event.defaultPrevented, b = null; event.returnValue = b;"
2579             + "        log('listener: prevented=' + p + ' returnValue: ' + a "
2580                                     + "+ ' -> ' + b + ' (' + event.returnValue + ')') })\n"
2581             + "</script>\n"
2582             + "</body></html>";
2583 
2584         final WebDriver driver = loadPage2(html);
2585         driver.findElement(By.id("a1")).click();
2586         driver.findElement(By.id("a2")).click();
2587         driver.findElement(By.id("a3")).click();
2588 
2589         final String text = driver.getTitle().trim().replaceAll(";", "\n").trim();
2590         assertEquals(String.join("\n", getExpectedAlerts()), text);
2591     }
2592 }