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