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 static org.junit.jupiter.api.Assertions.fail;
18  
19  import java.net.URL;
20  import java.util.ArrayList;
21  import java.util.Arrays;
22  import java.util.Collections;
23  import java.util.LinkedList;
24  import java.util.List;
25  
26  import org.htmlunit.CollectingAlertHandler;
27  import org.htmlunit.ConfirmHandler;
28  import org.htmlunit.DialogWindow;
29  import org.htmlunit.MockWebConnection;
30  import org.htmlunit.OnbeforeunloadHandler;
31  import org.htmlunit.Page;
32  import org.htmlunit.PrintHandler;
33  import org.htmlunit.SimpleWebTestCase;
34  import org.htmlunit.StatusHandler;
35  import org.htmlunit.WebClient;
36  import org.htmlunit.WebConsole;
37  import org.htmlunit.WebConsole.Logger;
38  import org.htmlunit.WebWindow;
39  import org.htmlunit.WebWindowEvent;
40  import org.htmlunit.WebWindowListener;
41  import org.htmlunit.WebWindowNotFoundException;
42  import org.htmlunit.html.HtmlAnchor;
43  import org.htmlunit.html.HtmlButton;
44  import org.htmlunit.html.HtmlButtonInput;
45  import org.htmlunit.html.HtmlElement;
46  import org.htmlunit.html.HtmlInlineFrame;
47  import org.htmlunit.html.HtmlInput;
48  import org.htmlunit.html.HtmlPage;
49  import org.htmlunit.junit.annotation.Alerts;
50  import org.htmlunit.junit.annotation.HtmlUnitNYI;
51  import org.htmlunit.util.MimeType;
52  import org.junit.jupiter.api.Test;
53  
54  /**
55   * Tests for {@link Window}.
56   *
57   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
58   * @author <a href="mailto:chen_jun@users.sourceforge.net">Chen Jun</a>
59   * @author David K. Taylor
60   * @author Darrell DeBoer
61   * @author Marc Guillemot
62   * @author Dierk Koenig
63   * @author Chris Erskine
64   * @author David D. Kilzer
65   * @author Ahmed Ashour
66   * @author Daniel Gredler
67   * @author Frank Danek
68   * @author Ronald Brill
69   */
70  public class WindowTest extends SimpleWebTestCase {
71  
72      /**
73       * @throws Exception if the test fails
74       */
75      @Test
76      public void openWindow() throws Exception {
77          final WebClient webClient = getWebClient();
78          final MockWebConnection webConnection = new MockWebConnection();
79  
80          final List<String> collectedAlerts = new ArrayList<>();
81          webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
82  
83          final String firstContent = DOCTYPE_HTML
84              + "<html><head><title>First</title></head><body>\n"
85              + "<form name='form1'>\n"
86              + "  <a id='link' onClick='window.open(\"" + URL_SECOND + "\", \"MyNewWindow\").focus(); "
87              + "return false;'>Click me</a>\n"
88              + "</form>\n"
89              + "</body></html>";
90          final String secondContent = DOCTYPE_HTML
91              + "<html><head><title>Second</title></head><body>\n"
92              + "<script>alert(self.name)</script>\n"
93              + "</body></html>";
94  
95          final List<WebWindowEvent> events = new LinkedList<>();
96          webClient.addWebWindowListener(new WebWindowListener() {
97              @Override
98              public void webWindowOpened(final WebWindowEvent event) {
99                  events.add(event);
100             }
101 
102             @Override
103             public void webWindowContentChanged(final WebWindowEvent event) {
104                 events.add(event);
105             }
106 
107             @Override
108             public void webWindowClosed(final WebWindowEvent event) {
109                 events.add(event);
110             }
111         });
112 
113         webConnection.setResponse(URL_FIRST, firstContent);
114         webConnection.setResponse(URL_SECOND, secondContent);
115         webClient.setWebConnection(webConnection);
116 
117         final HtmlPage firstPage = webClient.getPage(URL_FIRST);
118         assertEquals("First", firstPage.getTitleText());
119 
120         final HtmlAnchor anchor = firstPage.getHtmlElementById("link");
121         final HtmlPage secondPage = anchor.click();
122         assertNotSame(firstPage, secondPage);
123 
124         // Expecting contentChanged, opened, contentChanged
125         assertEquals(3, events.size());
126 
127         final WebWindow firstWebWindow = (WebWindow) events.get(0).getSource();
128         final WebWindow secondWebWindow = (WebWindow) events.get(2).getSource();
129         assertSame(webClient.getCurrentWindow(), secondWebWindow);
130         assertEquals("MyNewWindow", secondWebWindow.getName());
131 
132         assertEquals("First", ((HtmlPage) firstWebWindow.getEnclosedPage()).getTitleText());
133         assertEquals("Second", ((HtmlPage) secondWebWindow.getEnclosedPage()).getTitleText());
134 
135         final WebWindowEvent changedEvent = events.get(2);
136         assertNull(changedEvent.getOldPage());
137         assertEquals("Second", ((HtmlPage) changedEvent.getNewPage()).getTitleText());
138 
139         assertEquals(new String[] {"MyNewWindow"}, collectedAlerts);
140     }
141 
142     /**
143      * @throws Exception if the test fails
144      */
145     @Test
146     public void openWindow_base() throws Exception {
147         final WebClient webClient = getWebClient();
148         final MockWebConnection webConnection = new MockWebConnection();
149 
150         final List<String> collectedAlerts = new ArrayList<>();
151         webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
152 
153         final String firstContent = DOCTYPE_HTML
154             + "<html><head><title>First</title><base target='MyNewWindow'></head><body>\n"
155             + "<form name='form1'>\n"
156             + "  <a id='link' href='" + URL_SECOND + "'>Click me</a>\n"
157             + "</form>\n"
158             + "</body></html>";
159         final String secondContent = DOCTYPE_HTML
160             + "<html><head><title>Second</title></head><body>\n"
161             + "<script>alert(self.name)</script>\n"
162             + "</body></html>";
163 
164         webConnection.setResponse(URL_FIRST, firstContent);
165         webConnection.setResponse(URL_SECOND, secondContent);
166         webClient.setWebConnection(webConnection);
167 
168         final HtmlPage firstPage = webClient.getPage(URL_FIRST);
169         assertEquals("First", firstPage.getTitleText());
170         final WebWindow firstWebWindow = firstPage.getEnclosingWindow();
171         assertEquals(firstWebWindow, firstWebWindow.getTopWindow());
172 
173         final HtmlAnchor anchor = firstPage.getHtmlElementById("link");
174         final HtmlPage secondPage = anchor.click();
175         assertEquals("Second", secondPage.getTitleText());
176         assertNotSame(firstPage, secondPage);
177 
178         final WebWindow secondWebWindow = secondPage.getEnclosingWindow();
179         assertNotSame(firstWebWindow, secondWebWindow);
180         assertEquals("MyNewWindow", secondWebWindow.getName());
181         assertEquals(secondWebWindow, secondWebWindow.getTopWindow());
182 
183         assertEquals(new String[] {"MyNewWindow"}, collectedAlerts);
184     }
185 
186     /**
187      * _blank is a magic name. If we call open(url, '_blank') then a new
188      * window must be loaded.
189      * @throws Exception if the test fails
190      */
191     @Test
192     public void openWindow_blank() throws Exception {
193         final WebClient webClient = getWebClient();
194         final MockWebConnection webConnection = new MockWebConnection();
195 
196         final List<String> collectedAlerts = new ArrayList<>();
197         webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
198 
199         final String firstContent = DOCTYPE_HTML
200             + "<html><head><title>First</title></head><body>\n"
201             + "  <iframe name='secondFrame' id='secondFrame' src='" + URL_SECOND + "'></iframe>\n"
202             + "</body></html>";
203         final String secondContent = DOCTYPE_HTML
204             + "<html><head><title>Second</title></head><body>\n"
205             + "  <a id='link' "
206             + "onClick='window.open(\"" + URL_THIRD + "\", \"_blank\").focus(); '>\n"
207             + "Click me</a>\n"
208             + "</body></html>";
209         final String thirdContent = DOCTYPE_HTML
210             + "<html><head><title>Third</title></head><body>\n"
211             + "</body></html>";
212 
213         webConnection.setResponse(URL_FIRST, firstContent);
214         webConnection.setResponse(URL_SECOND, secondContent);
215         webConnection.setResponse(URL_THIRD, thirdContent);
216         webClient.setWebConnection(webConnection);
217 
218         final HtmlPage firstPage = webClient.getPage(URL_FIRST);
219         assertEquals("First", firstPage.getTitleText());
220         final WebWindow firstWindow = firstPage.getEnclosingWindow();
221 
222         final HtmlInlineFrame secondFrame = firstPage.getHtmlElementById("secondFrame");
223         final HtmlPage secondPage = (HtmlPage) secondFrame.getEnclosedPage();
224         assertEquals("Second", secondPage.getTitleText());
225         try {
226             assertEquals(secondFrame.getEnclosedWindow(), webClient.getWebWindowByName("secondFrame"));
227             // Expected path
228         }
229         catch (final WebWindowNotFoundException e) {
230             fail("Expected secondFrame would be found before click.");
231         }
232         final HtmlAnchor anchor = secondPage.getHtmlElementById("link");
233         final HtmlPage thirdPage = anchor.click();
234         assertEquals("Third", thirdPage.getTitleText());
235         final WebWindow thirdWindow = thirdPage.getEnclosingWindow();
236         assertNotSame(firstWindow, thirdWindow);
237 
238         assertEquals("", thirdWindow.getName());
239 
240         assertEquals(thirdWindow, thirdWindow.getTopWindow());
241         try {
242             assertEquals(secondFrame.getEnclosedWindow(), webClient.getWebWindowByName("secondFrame"));
243             // Expected path
244         }
245         catch (final WebWindowNotFoundException e) {
246             fail("Expected secondFrame would be found after click.");
247         }
248 
249         assertEquals(Collections.EMPTY_LIST, collectedAlerts);
250     }
251 
252     /**
253      * _self is a magic name. If we call open(url, '_self') then the current window must be
254      * reloaded.
255      * @throws Exception if the test fails
256      */
257     @Test
258     public void openWindow_self() throws Exception {
259         final WebClient webClient = getWebClient();
260         final MockWebConnection webConnection = new MockWebConnection();
261 
262         final String firstContent = DOCTYPE_HTML
263             + "<html><head><title>First</title></head><body>\n"
264             + "<form name='form1'>\n"
265             + "  <a id='link' onClick='window.open(\"" + URL_SECOND + "\", \"_self\"); "
266             + "return false;'>Click me</a>\n"
267             + "</form>\n"
268             + "</body></html>";
269         final String secondContent = DOCTYPE_HTML
270                 + "<html><head><title>Second</title></head><body></body></html>";
271 
272         webConnection.setResponse(URL_FIRST, firstContent);
273         webConnection.setResponse(URL_SECOND, secondContent);
274         webClient.setWebConnection(webConnection);
275 
276         final HtmlPage firstPage = webClient.getPage(URL_FIRST);
277         assertEquals("First", firstPage.getTitleText());
278 
279         final List<WebWindowEvent> events = new LinkedList<>();
280         webClient.addWebWindowListener(new WebWindowListener() {
281             @Override
282             public void webWindowOpened(final WebWindowEvent event) {
283                 events.add(event);
284             }
285 
286             @Override
287             public void webWindowContentChanged(final WebWindowEvent event) {
288                 events.add(event);
289             }
290 
291             @Override
292             public void webWindowClosed(final WebWindowEvent event) {
293                 events.add(event);
294             }
295         });
296 
297         final WebWindow firstWebWindow = firstPage.getEnclosingWindow();
298 
299         final HtmlAnchor anchor = firstPage.getHtmlElementById("link");
300         final HtmlPage secondPage = anchor.click();
301         assertEquals("First", firstPage.getTitleText());
302         assertEquals("Second", secondPage.getTitleText());
303 
304         assertEquals(1, events.size());
305 
306         final WebWindow secondWebWindow = (WebWindow) events.get(0).getSource();
307         assertSame(webClient.getCurrentWindow(), firstWebWindow);
308         assertSame(firstWebWindow, secondWebWindow);
309     }
310 
311     /**
312      * _top is a magic name. If we call open(url, '_top') then the top level
313      * window must be reloaded.
314      * @throws Exception if the test fails
315      */
316     @Test
317     public void openWindow_top() throws Exception {
318         final WebClient webClient = getWebClient();
319         final MockWebConnection webConnection = new MockWebConnection();
320 
321         final String firstContent = DOCTYPE_HTML
322             + "<html><head><title>First</title></head><body>\n"
323             + "  <iframe name='secondFrame' id='secondFrame' src='" + URL_SECOND + "'></iframe>\n"
324             + "</body></html>";
325         final String secondContent = DOCTYPE_HTML
326             + "<html><head><title>Second</title></head><body>\n"
327             + "  <iframe name='thirdFrame' id='thirdFrame' src='" + URL_THIRD + "'></iframe>\n"
328             + "</body></html>";
329         final String thirdContent = DOCTYPE_HTML
330             + "<html><head><title>Third</title></head><body>\n"
331             + "  <a id='link' onClick='window.open(\"http://fourth\", \"_top\"); "
332             + "return false;'>Click me</a>\n"
333             + "</body></html>";
334         final String fourthContent = DOCTYPE_HTML
335             + "<html><head><title>Fourth</title></head><body></body></html>";
336 
337         webConnection.setResponse(URL_FIRST, firstContent);
338         webConnection.setResponse(URL_SECOND, secondContent);
339         webConnection.setResponse(URL_THIRD, thirdContent);
340         webConnection.setResponse(new URL("http://fourth/"), fourthContent);
341         webClient.setWebConnection(webConnection);
342 
343         final HtmlPage firstPage = webClient.getPage(URL_FIRST);
344         assertEquals("First", firstPage.getTitleText());
345 
346         final WebWindow firstWebWindow = firstPage.getEnclosingWindow();
347         assertEquals("First", firstPage.getTitleText());
348         final HtmlInlineFrame secondFrame = firstPage.getHtmlElementById("secondFrame");
349         final HtmlPage secondPage = (HtmlPage) secondFrame.getEnclosedPage();
350         assertEquals("Second", secondPage.getTitleText());
351         final HtmlInlineFrame thirdFrame = secondPage.getHtmlElementById("thirdFrame");
352         final HtmlPage thirdPage = (HtmlPage) thirdFrame.getEnclosedPage();
353         assertEquals("Third", thirdPage.getTitleText());
354 
355         assertSame(webClient.getCurrentWindow(), firstWebWindow);
356         assertNotSame(firstWebWindow, secondPage);
357 
358         final HtmlAnchor anchor = thirdPage.getHtmlElementById("link");
359         final HtmlPage fourthPage = anchor.click();
360         final WebWindow fourthWebWindow = fourthPage.getEnclosingWindow();
361         assertSame(firstWebWindow, fourthWebWindow);
362         assertSame(fourthWebWindow, fourthWebWindow.getTopWindow());
363         try {
364             webClient.getWebWindowByName("secondFrame");
365             fail("Did not expect secondFrame to still exist after click.");
366         }
367         catch (final WebWindowNotFoundException e) {
368             // Expected path
369         }
370         try {
371             webClient.getWebWindowByName("thirdFrame");
372             fail("Did not expect thirdFrame to still exist after click.");
373         }
374         catch (final WebWindowNotFoundException e) {
375             // Expected path
376         }
377     }
378 
379     /**
380      * {@code _parent} is a magic name. If we call open(url, '_parent') then the parent window must be reloaded.
381      *
382      * @throws Exception if the test fails
383      */
384     @Test
385     public void openWindow_parent() throws Exception {
386         final WebClient webClient = getWebClient();
387         final MockWebConnection webConnection = new MockWebConnection();
388 
389         final String firstContent = DOCTYPE_HTML
390             + "<html><head><title>First</title></head><body>\n"
391             + "  <iframe name='secondFrame' id='secondFrame' src='" + URL_SECOND + "'></iframe>\n"
392             + "</body></html>";
393         final String secondContent = DOCTYPE_HTML
394             + "<html><head><title>Second</title></head><body>\n"
395             + "  <iframe name='thirdFrame' id='thirdFrame' src='" + URL_THIRD + "'></iframe>\n"
396             + "</body></html>";
397         final String thirdContent = DOCTYPE_HTML
398             + "<html><head><title>Third</title></head><body>\n"
399             + "  <a id='link' onClick='window.open(\"http://fourth\", \"_parent\"); "
400             + "return false;'>Click me</a>\n"
401             + "</body></html>";
402         final String fourthContent = DOCTYPE_HTML
403             + "<html><head><title>Fourth</title></head><body></body></html>";
404 
405         webConnection.setResponse(URL_FIRST, firstContent);
406         webConnection.setResponse(URL_SECOND, secondContent);
407         webConnection.setResponse(URL_THIRD, thirdContent);
408         webConnection.setResponse(new URL("http://fourth/"), fourthContent);
409         webClient.setWebConnection(webConnection);
410 
411         final HtmlPage firstPage = webClient.getPage(URL_FIRST);
412         assertEquals("First", firstPage.getTitleText());
413 
414         final WebWindow firstWebWindow = firstPage.getEnclosingWindow();
415         assertEquals("First", firstPage.getTitleText());
416         final HtmlInlineFrame secondFrame = firstPage.getHtmlElementById("secondFrame");
417         final HtmlPage secondPage = (HtmlPage) secondFrame.getEnclosedPage();
418         assertEquals("Second", secondPage.getTitleText());
419         final HtmlInlineFrame thirdFrame = secondPage.getHtmlElementById("thirdFrame");
420         final HtmlPage thirdPage = (HtmlPage) thirdFrame.getEnclosedPage();
421         assertEquals("Third", thirdPage.getTitleText());
422 
423         assertSame(webClient.getCurrentWindow(), firstWebWindow);
424         assertNotSame(firstWebWindow, secondFrame);
425 
426         final HtmlAnchor anchor = thirdPage.getHtmlElementById("link");
427         final HtmlPage fourthPage = anchor.click();
428         final WebWindow fourthWebWindow = fourthPage.getEnclosingWindow();
429         assertSame(secondFrame.getEnclosedWindow(), fourthWebWindow);
430         try {
431             final WebWindow namedWindow = webClient.getWebWindowByName("secondFrame");
432             assertSame(namedWindow.getEnclosedPage(), fourthPage);
433             // Expected path
434         }
435         catch (final WebWindowNotFoundException e) {
436             fail("Expected secondFrame would be found after click.");
437         }
438         try {
439             webClient.getWebWindowByName("thirdFrame");
440             fail("Did not expect thirdFrame to still exist after click.");
441         }
442         catch (final WebWindowNotFoundException e) {
443             // Expected path
444         }
445     }
446 
447     /**
448      * Regression test for 1592723: window.open('', 'someName') should
449      * retrieve existing window named 'someName' rather than opening a new window
450      * if such a window exists.
451      * @throws Exception if the test fails
452      */
453     @Test
454     @Alerts({"true", "true", "true"})
455     public void openWindow_existingWindow() throws Exception {
456         final String html = DOCTYPE_HTML
457             + "<html><head><script>\n"
458             + "function test() {\n"
459             + "  var w1 = window.open('about:blank', 'foo');\n"
460             + "  alert(w1 != null);\n"
461             + "  var w2 = window.open('', 'foo');\n"
462             + "  alert(w1 == w2);\n"
463             + "  var w3 = window.open('', 'myFrame');\n"
464             + "  alert(w3 == window.frames.myFrame);\n"
465             + "}\n"
466             + "</script></head><body onload='test()'>\n"
467             + "<iframe name='myFrame' id='myFrame'></iframe>\n"
468             + "</body></html>";
469 
470         loadPageWithAlerts(html);
471     }
472 
473     /**
474      * Verifies that <tt>window.open</tt> behaves correctly when popups are blocked.
475      * @throws Exception if an error occurs
476      */
477     @Test
478     public void openWindow_blocked() throws Exception {
479         final String html = DOCTYPE_HTML
480             + "<html>\n"
481             + "<head>\n"
482             + "<script>\n"
483             + "  var w;\n"
484             + "  function test() {\n"
485             + "    w = window.open('', 'foo');\n"
486             + "  }\n"
487             + "</script>\n"
488             + "</head>\n"
489             + "<body onload='test()'>\n"
490             + "<div id='d' onclick='alert(w)'>test</div>\n"
491             + "</body></html>";
492 
493         final List<String> actual = new ArrayList<>();
494         final WebClient client = getWebClient();
495         client.getOptions().setPopupBlockerEnabled(true);
496         client.setAlertHandler(new CollectingAlertHandler(actual));
497 
498         final MockWebConnection webConnection = new MockWebConnection();
499         webConnection.setDefaultResponse(html);
500         client.setWebConnection(webConnection);
501 
502         final HtmlPage page = client.getPage("http://foo");
503         page.getHtmlElementById("d").click();
504         final String[] expected = {"null"};
505         assertEquals(expected, actual);
506     }
507 
508     /**
509      * @throws Exception if the test fails
510      */
511     @Test
512     public void alert_NoAlertHandler() throws Exception {
513         final String firstContent = DOCTYPE_HTML
514             + "<html><head><title>First</title><script>function doTest() {alert('foo')}</script></head>\n"
515             + "<body onload='doTest()'></body></html>";
516 
517         final HtmlPage firstPage = loadPage(firstContent);
518         assertEquals("First", firstPage.getTitleText());
519     }
520 
521     /**
522      * @throws Exception if the test fails
523      */
524     @Test
525     public void parentAndTop() throws Exception {
526         final String firstContent = DOCTYPE_HTML
527             + "<html><head><title>First</title></head><body>\n"
528             + "  <iframe name='left' src='" + URL_SECOND + "'></iframe>\n"
529             + "</body></html>";
530         final String secondContent = DOCTYPE_HTML
531             + "<html><head><title>Second</title></head><body>\n"
532             + "  <iframe name='innermost' src='" + URL_THIRD + "'></iframe>\n"
533             + "</body></html>";
534         final String thirdContent = DOCTYPE_HTML
535             + "<html><head><title>Third</title><script>\n"
536             + "function doAlert() {\n"
537             + "  alert(parent != this);\n"
538             + "  alert(top != this);\n"
539             + "  alert(parent != top);\n"
540             + "  alert(parent.parent == top);\n"
541             + "  alert(parent.frames[0] == this);\n"
542             + "  alert(top.frames[0] == parent);\n"
543             + "}\n"
544             + "</script></head>\n"
545             + "<body><a id='clickme' onClick='doAlert()'>foo</a></body></html>";
546 
547         final WebClient webClient = getWebClient();
548         final List<String> collectedAlerts = new ArrayList<>();
549         webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
550 
551         final MockWebConnection webConnection = new MockWebConnection();
552         webConnection.setResponse(URL_FIRST, firstContent);
553         webConnection.setResponse(URL_SECOND, secondContent);
554         webConnection.setResponse(URL_THIRD, thirdContent);
555 
556         webClient.setWebConnection(webConnection);
557 
558         final HtmlPage firstPage = webClient.getPage(URL_FIRST);
559         assertEquals("First", firstPage.getTitleText());
560 
561         final WebWindow innermostWebWindow = webClient.getWebWindowByName("innermost");
562         final HtmlPage innermostPage = (HtmlPage) innermostWebWindow.getEnclosedPage();
563         innermostPage.getHtmlElementById("clickme").click();
564 
565         assertNotSame(innermostWebWindow.getParentWindow(), innermostWebWindow);
566         assertNotSame(innermostWebWindow.getTopWindow(), innermostWebWindow);
567         assertNotSame(innermostWebWindow.getParentWindow(), innermostWebWindow.getTopWindow());
568         assertSame(innermostWebWindow.getParentWindow().getParentWindow(), innermostWebWindow.getTopWindow());
569 
570         assertEquals(new String[] {"true", "true", "true", "true", "true", "true"}, collectedAlerts);
571     }
572 
573     /**
574      * @throws Exception if the test fails
575      */
576     @Test
577     public void confirm() throws Exception {
578         final WebClient webClient = getWebClient();
579         final MockWebConnection webConnection = new MockWebConnection();
580         final List<String> collectedAlerts = new ArrayList<>();
581         final List<String> collectedConfirms = new ArrayList<>();
582 
583         webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
584         webClient.setConfirmHandler(new ConfirmHandler() {
585             @Override
586             public boolean handleConfirm(final Page page, final String message) {
587                 collectedConfirms.add(message);
588                 return true;
589             }
590         });
591 
592         final String firstContent
593             = "<html><head><title>First</title><script>function doTest() {alert(confirm('foo'))}</script>\n"
594             + "</head><body onload='doTest()'></body></html>";
595 
596         webConnection.setResponse(URL_FIRST, firstContent);
597         webClient.setWebConnection(webConnection);
598 
599         final HtmlPage firstPage = webClient.getPage(URL_FIRST);
600         assertEquals("First", firstPage.getTitleText());
601 
602         assertEquals(new String[] {"foo"}, collectedConfirms);
603         assertEquals(new String[] {"true"}, collectedAlerts);
604     }
605 
606     /**
607      * @throws Exception if the test fails
608      */
609     @Test
610     public void confirm_noConfirmHandler() throws Exception {
611         final String html = DOCTYPE_HTML
612             + "<html><head><title>First</title><script>function doTest() {alert(confirm('foo'))}</script>\n"
613             + "</head><body onload='doTest()'></body></html>";
614 
615         final List<String> collectedAlerts = new ArrayList<>();
616         loadPage(html, collectedAlerts);
617 
618         assertEquals(new String[] {"true"}, collectedAlerts);
619     }
620 
621     /**
622      * @throws Exception if the test fails
623      */
624     @Test
625     public void prompt() throws Exception {
626         try (WebClient webClient = getWebClient()) {
627             try (MockWebConnection webConnection = new MockWebConnection()) {
628                 final List<String> collectedAlerts = new ArrayList<>();
629                 final List<String> collectedPrompts = new ArrayList<>();
630 
631                 webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
632                 webClient.setPromptHandler((page, message, defaultValue) -> {
633                     collectedPrompts.add(message);
634                     return "Flintstone";
635                 });
636 
637                 final String html = DOCTYPE_HTML
638                         + "<html><head><title>First</title>\n"
639                         + "<script>function doTest() {alert(prompt('foo'))}</script>\n"
640                         + "</head><body onload='doTest()'></body></html>";
641 
642                 webConnection.setResponse(URL_FIRST, html);
643                 webClient.setWebConnection(webConnection);
644 
645                 final HtmlPage firstPage = webClient.getPage(URL_FIRST);
646                 assertEquals("First", firstPage.getTitleText());
647 
648                 assertEquals(new String[] {"foo"}, collectedPrompts);
649                 assertEquals(new String[] {"Flintstone"}, collectedAlerts);
650             }
651         }
652     }
653 
654     /**
655      * @throws Exception if the test fails
656      */
657     @Test
658     public void promptWithDefault() throws Exception {
659         try (WebClient webClient = getWebClient()) {
660             try (MockWebConnection webConnection = new MockWebConnection()) {
661                 final List<String> collectedAlerts = new ArrayList<>();
662                 final List<String> collectedPrompts = new ArrayList<>();
663 
664                 webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
665                 webClient.setPromptHandler((page, message, defaultValue) -> {
666                     collectedPrompts.add(message);
667                     collectedPrompts.add(defaultValue);
668                     return defaultValue;
669                 });
670 
671                 final String html = DOCTYPE_HTML
672                         + "<html><head><title>First</title>\n"
673                         + "<script>function doTest() {alert(prompt('foo', 'some default'))}</script>\n"
674                         + "</head><body onload='doTest()'></body></html>";
675 
676                 webConnection.setResponse(URL_FIRST, html);
677                 webClient.setWebConnection(webConnection);
678 
679                 final HtmlPage firstPage = webClient.getPage(URL_FIRST);
680                 assertEquals("First", firstPage.getTitleText());
681 
682                 assertEquals(new String[] {"foo", "some default"}, collectedPrompts);
683                 assertEquals(new String[] {"some default"}, collectedAlerts);
684             }
685         }
686     }
687 
688     /**
689      * @throws Exception if the test fails
690      */
691     @Test
692     public void prompt_noPromptHandler() throws Exception {
693         final WebClient webClient = getWebClient();
694         final MockWebConnection webConnection = new MockWebConnection();
695         final List<String> collectedAlerts = new ArrayList<>();
696         final List<String> collectedPrompts = new ArrayList<>();
697 
698         webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
699 
700         final String firstContent = DOCTYPE_HTML
701             + "<html><head><title>First</title><script>function doTest() {alert(prompt('foo'))}</script>\n"
702             + "</head><body onload='doTest()'></body></html>";
703 
704         webConnection.setResponse(URL_FIRST, firstContent);
705         webClient.setWebConnection(webConnection);
706 
707         final HtmlPage firstPage = webClient.getPage(URL_FIRST);
708         assertEquals("First", firstPage.getTitleText());
709 
710         assertEquals(Collections.EMPTY_LIST, collectedPrompts);
711         assertEquals(new String[] {"null"}, collectedAlerts);
712     }
713 
714     /**
715      * @throws Exception if the test fails
716      */
717     @Test
718     public void setOpenerLocationHrefRelative() throws Exception {
719         final WebClient webClient = getWebClient();
720         final MockWebConnection webConnection = new MockWebConnection();
721 
722         final String aContent = DOCTYPE_HTML
723             + "<html><head><title>A</title></head><body>\n"
724             + "<button id='clickme' onClick='window.open(\"b/b.html\");'>Click me</a>\n"
725             + "</body></html>";
726         final String bContent = DOCTYPE_HTML
727             + "<html><head><title>B</title></head><body>\n"
728             + "<button id='clickme' onClick='opener.location.href=\"../c.html\";'>Click me</a>\n"
729             + "</body></html>";
730         final String cContent = DOCTYPE_HTML
731             + "<html><head><title>C</title></head><body></body></html>";
732         final String failContent = DOCTYPE_HTML
733             + "<html><head><title>FAILURE!!!</title></head><body></body></html>";
734 
735         webConnection.setResponse(new URL("http://opener/test/a.html"), aContent);
736         webConnection.setResponse(new URL("http://opener/test/b/b.html"), bContent);
737         webConnection.setResponse(new URL("http://opener/test/c.html"), cContent);
738         webConnection.setResponse(new URL("http://opener/c.html"), failContent);
739 
740         webClient.setWebConnection(webConnection);
741 
742         final HtmlPage firstPage = webClient.getPage("http://opener/test/a.html");
743         assertEquals("A", firstPage.getTitleText());
744 
745         final HtmlButton buttonA = firstPage.getHtmlElementById("clickme");
746         final HtmlPage pageB = buttonA.click();
747         assertNotNull("B", pageB);
748         assertEquals("B", pageB.getTitleText());
749 
750         final HtmlButton buttonB = pageB.getHtmlElementById("clickme");
751         final HtmlPage thirdPage = buttonB.click();
752         assertSame("Page B has lost focus", pageB, thirdPage);
753         assertEquals("C", ((HtmlPage) firstPage.getEnclosingWindow().getEnclosedPage()).getTitleText());
754     }
755 
756     /**
757      * Test closing using JavaScript.
758      * @throws Exception if the test fails
759      */
760     @Test
761     public void close() throws Exception {
762         final WebClient webClient = getWebClient();
763         final MockWebConnection webConnection = new MockWebConnection();
764 
765         final List<String> collectedAlerts = new ArrayList<>();
766         webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
767 
768         final String firstContent = DOCTYPE_HTML
769             + "<html><head><title>First</title></head><body>\n"
770             + "<a href='" + URL_SECOND + "' id='link' target='_blank'>Link</a>\n"
771             + "</body></html>";
772         final String secondContent = DOCTYPE_HTML
773             + "<html><head><title>Second</title></head><body>\n"
774             + "<h1>Second</h1><form>\n"
775             + "<input type='submit' name='action' value='Close' id='button' "
776             + "onclick='window.close(); return false;'>\n"
777             + "</form></body></html>";
778 
779         webConnection.setResponse(URL_FIRST, firstContent);
780         webConnection.setResponse(URL_SECOND, secondContent);
781         webClient.setWebConnection(webConnection);
782 
783         final HtmlPage firstPage = webClient.getPage(URL_FIRST);
784         assertEquals("First", firstPage.getTitleText());
785         assertEquals(1, webClient.getWebWindows().size());
786         final WebWindow firstWindow = firstPage.getEnclosingWindow();
787 
788         final HtmlPage secondPage = firstPage.getHtmlElementById("link").click();
789         assertEquals("Second", secondPage.getTitleText());
790         assertEquals(2, webClient.getWebWindows().size());
791         final WebWindow secondWindow = secondPage.getEnclosingWindow();
792 
793         assertNotSame(firstWindow, secondWindow);
794 
795         final List<WebWindowEvent> events = new LinkedList<>();
796         webClient.addWebWindowListener(new WebWindowListener() {
797             @Override
798             public void webWindowOpened(final WebWindowEvent event) {
799                 events.add(event);
800             }
801 
802             @Override
803             public void webWindowContentChanged(final WebWindowEvent event) {
804                 events.add(event);
805             }
806 
807             @Override
808             public void webWindowClosed(final WebWindowEvent event) {
809                 events.add(event);
810             }
811         });
812 
813         secondPage.getHtmlElementById("button").click();
814 
815         final List<WebWindowEvent> expectedEvents = Arrays.asList(new WebWindowEvent[]{
816             new WebWindowEvent(secondWindow, WebWindowEvent.CLOSE, secondPage, null)
817         });
818         assertEquals(expectedEvents, events);
819 
820         assertEquals(1, webClient.getWebWindows().size());
821         assertEquals(firstWindow, webClient.getCurrentWindow());
822 
823         assertEquals(Collections.EMPTY_LIST, collectedAlerts);
824     }
825 
826     /**
827      * @throws Exception if the test fails
828      */
829     @Test
830     public void status() throws Exception {
831         final WebClient webClient = getWebClient();
832         final MockWebConnection webConnection = new MockWebConnection();
833 
834         final String firstContent = DOCTYPE_HTML
835             +  "<html><head><title>First</title><script>\n"
836             + "function doTest() {\n"
837             + "  alert(window.status);\n"
838             + "  window.status = 'newStatus';\n"
839             + "  alert(window.status);\n"
840             + "}\n"
841             + "</script></head><body onload='doTest()'>\n"
842             + "</body></html>";
843 
844         final URL url = URL_FIRST;
845         webConnection.setResponse(url, firstContent);
846         webClient.setWebConnection(webConnection);
847 
848         final List<String> collectedAlerts = new ArrayList<>();
849         webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
850 
851         final List<String> collectedStatus = new ArrayList<>();
852         webClient.setStatusHandler(new StatusHandler() {
853             @Override
854             public void statusMessageChanged(final Page page, final String message) {
855                 collectedStatus.add(message);
856             }
857         });
858         final HtmlPage firstPage = webClient.getPage(URL_FIRST);
859         assertEquals("First", firstPage.getTitleText());
860 
861         final String[] expectedAlerts = {"", "newStatus"};
862         assertEquals("alerts", expectedAlerts, collectedAlerts);
863 
864         final String[] expectedStatus = {"newStatus"};
865         assertEquals("status", expectedStatus, collectedStatus);
866     }
867 
868     /**
869      * @throws Exception if the test fails
870      */
871     @Test
872     public void print() throws Exception {
873         final String html = DOCTYPE_HTML
874             + "<html>\n"
875             + "<head></head>\n"
876             + "<body>\n"
877             + "<script>\n"
878             + "  window.print();\n"
879             + "</script>\n"
880             + "</body>\n"
881             + "</html>";
882 
883         loadPageWithAlerts(html);
884     }
885 
886     /**
887      * Open a window with only an image for content, then try to set focus to it.
888      *
889      * @throws Exception if the test fails
890      */
891     @Test
892     public void openWindow_image() throws Exception {
893         final WebClient webClient = getWebClient();
894         final MockWebConnection webConnection = new MockWebConnection();
895 
896         final String firstContent = DOCTYPE_HTML
897             + "<html><head><title>First</title></head><body>\n"
898             + "<form name='form1'>\n"
899             + "  <a id='link' onClick='window.open(\"" + URL_SECOND + "\", \"_blank\").focus(); return false;'"
900             + "return false;'>Click me</a>\n"
901             + "</form>\n"
902             + "</body></html>";
903         final String secondContent = new String(new char[]{
904             'G', 'I', 'F', '8', '9', 'a', 0x01, 0x00,
905             0x01, 0x00, 0x80, 0x00, 0x00, 0xfe, 0xd4, 0xaf,
906             0x00, 0x00, 0x00, 0x21, 0xf9, 0x04, 0x00, 0x00,
907             0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00,
908             0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x44,
909             0x01, 0x00, 0x3b});
910 
911         webConnection.setResponse(URL_FIRST, firstContent, 200, "OK", MimeType.TEXT_HTML, Collections.emptyList());
912         webConnection.setResponse(URL_SECOND, secondContent, 200, "OK", MimeType.IMAGE_GIF, Collections.emptyList());
913         webClient.setWebConnection(webConnection);
914 
915         final HtmlPage firstPage = webClient.getPage(URL_FIRST);
916         assertEquals("First", firstPage.getTitleText());
917 
918         final List<WebWindowEvent> events = new LinkedList<>();
919         webClient.addWebWindowListener(new WebWindowListener() {
920             @Override
921             public void webWindowOpened(final WebWindowEvent event) {
922                 events.add(event);
923             }
924 
925             @Override
926             public void webWindowContentChanged(final WebWindowEvent event) {
927                 events.add(event);
928             }
929 
930             @Override
931             public void webWindowClosed(final WebWindowEvent event) {
932                 events.add(event);
933             }
934         });
935 
936         final WebWindow firstWebWindow = firstPage.getEnclosingWindow();
937 
938         final HtmlAnchor anchor = firstPage.getHtmlElementById("link");
939         final Page secondPage = anchor.click();
940         assertEquals("First", firstPage.getTitleText());
941         assertEquals(MimeType.IMAGE_GIF, secondPage.getWebResponse().getContentType());
942 
943         assertEquals(2, events.size());
944 
945         final WebWindow secondWebWindow = (WebWindow) events.get(0).getSource();
946 
947         assertSame(webClient.getCurrentWindow(), secondWebWindow);
948         assertNotSame(firstWebWindow, secondWebWindow);
949     }
950 
951     /**
952      * Open a window with only text for content, then try to set focus to it.
953      *
954      * @throws Exception if the test fails
955      */
956     @Test
957     public void openWindow_text() throws Exception {
958         final WebClient webClient = getWebClient();
959         final MockWebConnection webConnection = new MockWebConnection();
960 
961         final String firstContent = DOCTYPE_HTML
962             + "<html><head><title>First</title></head><body>\n"
963             + "<form name='form1'>\n"
964             + "  <a id='link' onClick='window.open(\"" + URL_SECOND + "\", \"_blank\").focus(); return false;'"
965             + "return false;'>Click me</a>\n"
966             + "</form>\n"
967             + "</body></html>";
968         final String secondContent = "Hello World";
969 
970         webConnection.setResponse(URL_FIRST, firstContent, 200, "OK", MimeType.TEXT_HTML, Collections.emptyList());
971         webConnection.setResponse(URL_SECOND, secondContent, 200, "OK", MimeType.TEXT_PLAIN, Collections.emptyList());
972         webClient.setWebConnection(webConnection);
973 
974         final HtmlPage firstPage = webClient.getPage(URL_FIRST);
975         assertEquals("First", firstPage.getTitleText());
976 
977         final List<WebWindowEvent> events = new LinkedList<>();
978         webClient.addWebWindowListener(new WebWindowListener() {
979             @Override
980             public void webWindowOpened(final WebWindowEvent event) {
981                 events.add(event);
982             }
983 
984             @Override
985             public void webWindowContentChanged(final WebWindowEvent event) {
986                 events.add(event);
987             }
988 
989             @Override
990             public void webWindowClosed(final WebWindowEvent event) {
991                 events.add(event);
992             }
993         });
994 
995         final WebWindow firstWebWindow = firstPage.getEnclosingWindow();
996 
997         final HtmlAnchor anchor = firstPage.getHtmlElementById("link");
998         final Page secondPage = anchor.click();
999         assertEquals("First", firstPage.getTitleText());
1000         assertEquals(MimeType.TEXT_PLAIN, secondPage.getWebResponse().getContentType());
1001 
1002         assertEquals(2, events.size());
1003 
1004         final WebWindow secondWebWindow = (WebWindow) events.get(0).getSource();
1005 
1006         assertSame(webClient.getCurrentWindow(), secondWebWindow);
1007         assertNotSame(firstWebWindow, secondWebWindow);
1008     }
1009 
1010     /**
1011      * Open a window with only XML for content, then try to set focus to it.
1012      *
1013      * @throws Exception if the test fails
1014      */
1015     @Test
1016     public void openWindow_xml() throws Exception {
1017         final WebClient webClient = getWebClient();
1018         final MockWebConnection webConnection = new MockWebConnection();
1019 
1020         final String firstContent = DOCTYPE_HTML
1021             + "<html><head><title>First</title></head><body>\n"
1022             + "<form name='form1'>\n"
1023             + "  <a id='link' onClick='window.open(\"" + URL_SECOND + "\", \"_blank\").focus(); return false;'"
1024             + "return false;'>Click me</a>\n"
1025             + "</form>\n"
1026             + "</body></html>";
1027         final String secondContent = "<junk></junk>\n";
1028 
1029         webConnection.setResponse(URL_FIRST, firstContent, 200, "OK", MimeType.TEXT_HTML, Collections.emptyList());
1030         webConnection.setResponse(URL_SECOND, secondContent, 200, "OK", MimeType.TEXT_XML, Collections.emptyList());
1031         webClient.setWebConnection(webConnection);
1032 
1033         final HtmlPage firstPage = webClient.getPage(URL_FIRST);
1034         assertEquals("First", firstPage.getTitleText());
1035 
1036         final List<WebWindowEvent> events = new LinkedList<>();
1037         webClient.addWebWindowListener(new WebWindowListener() {
1038             @Override
1039             public void webWindowOpened(final WebWindowEvent event) {
1040                 events.add(event);
1041             }
1042 
1043             @Override
1044             public void webWindowContentChanged(final WebWindowEvent event) {
1045                 events.add(event);
1046             }
1047 
1048             @Override
1049             public void webWindowClosed(final WebWindowEvent event) {
1050                 events.add(event);
1051             }
1052         });
1053 
1054         final WebWindow firstWebWindow = firstPage.getEnclosingWindow();
1055 
1056         final HtmlAnchor anchor = firstPage.getHtmlElementById("link");
1057         final Page secondPage = anchor.click();
1058         assertEquals("First", firstPage.getTitleText());
1059         assertEquals(MimeType.TEXT_XML, secondPage.getWebResponse().getContentType());
1060 
1061         assertEquals(2, events.size());
1062 
1063         final WebWindow secondWebWindow = (WebWindow) events.get(0).getSource();
1064 
1065         assertSame(webClient.getCurrentWindow(), secondWebWindow);
1066         assertNotSame(firstWebWindow, secondWebWindow);
1067     }
1068 
1069     /**
1070      * Open a window with only JavaScript for content, then try to set focus to it.
1071      *
1072      * @throws Exception if the test fails
1073      */
1074     @Test
1075     public void openWindow_javascript() throws Exception {
1076         final WebClient webClient = getWebClient();
1077         final MockWebConnection webConnection = new MockWebConnection();
1078 
1079         final String firstContent = DOCTYPE_HTML
1080             + "<html><head><title>First</title></head><body>\n"
1081             + "<form name='form1'>\n"
1082             + "  <a id='link' onClick='window.open(\"" + URL_SECOND + "\", \"_blank\").focus(); return false;'"
1083             + "return false;'>Click me</a>\n"
1084             + "</form>\n"
1085             + "</body></html>";
1086         final String secondContent = "var x=1;\n";
1087 
1088         webConnection.setResponse(URL_FIRST, firstContent, 200, "OK", MimeType.TEXT_HTML, Collections.emptyList());
1089         webConnection.setResponse(URL_SECOND, secondContent, 200, "OK", "text/javascript", Collections.emptyList());
1090         webClient.setWebConnection(webConnection);
1091 
1092         final HtmlPage firstPage = webClient.getPage(URL_FIRST);
1093         assertEquals("First", firstPage.getTitleText());
1094 
1095         final List<WebWindowEvent> events = new LinkedList<>();
1096         webClient.addWebWindowListener(new WebWindowListener() {
1097             @Override
1098             public void webWindowOpened(final WebWindowEvent event) {
1099                 events.add(event);
1100             }
1101 
1102             @Override
1103             public void webWindowContentChanged(final WebWindowEvent event) {
1104                 events.add(event);
1105             }
1106 
1107             @Override
1108             public void webWindowClosed(final WebWindowEvent event) {
1109                 events.add(event);
1110             }
1111         });
1112 
1113         final WebWindow firstWebWindow = firstPage.getEnclosingWindow();
1114 
1115         final HtmlAnchor anchor = firstPage.getHtmlElementById("link");
1116         final Page secondPage = anchor.click();
1117         assertEquals("First", firstPage.getTitleText());
1118         assertEquals("text/javascript", secondPage.getWebResponse().getContentType());
1119 
1120         assertEquals(2, events.size());
1121 
1122         final WebWindow secondWebWindow = (WebWindow) events.get(0).getSource();
1123 
1124         assertSame(webClient.getCurrentWindow(), secondWebWindow);
1125         assertNotSame(firstWebWindow, secondWebWindow);
1126     }
1127 
1128     /**
1129      * Open a window with only text for content, then try to set focus to it.
1130      *
1131      * @throws Exception if the test fails
1132      */
1133     @Test
1134     public void openWindow_html() throws Exception {
1135         final WebClient webClient = getWebClient();
1136         final MockWebConnection webConnection = new MockWebConnection();
1137 
1138         final String firstContent = DOCTYPE_HTML
1139             + "<html><head><title>First</title></head><body>\n"
1140             + "<form name='form1'>\n"
1141             + "  <a id='link' onClick='window.open(\"" + URL_SECOND + "\", \"_blank\").focus(); return false;'"
1142             + "return false;'>Click me</a>\n"
1143             + "</form>\n"
1144             + "</body></html>";
1145         final String secondContent = DOCTYPE_HTML
1146             + "<html><head><title>Second</title></head><body>\n"
1147             + "<p>Hello World</p>\n"
1148             + "</body></html>";
1149 
1150         webConnection.setResponse(URL_FIRST, firstContent);
1151         webConnection.setResponse(URL_SECOND, secondContent);
1152         webClient.setWebConnection(webConnection);
1153 
1154         final HtmlPage firstPage = webClient.getPage(URL_FIRST);
1155         assertEquals("First", firstPage.getTitleText());
1156 
1157         final List<WebWindowEvent> events = new LinkedList<>();
1158         webClient.addWebWindowListener(new WebWindowListener() {
1159             @Override
1160             public void webWindowOpened(final WebWindowEvent event) {
1161                 events.add(event);
1162             }
1163 
1164             @Override
1165             public void webWindowContentChanged(final WebWindowEvent event) {
1166                 events.add(event);
1167             }
1168 
1169             @Override
1170             public void webWindowClosed(final WebWindowEvent event) {
1171                 events.add(event);
1172             }
1173         });
1174 
1175         final WebWindow firstWebWindow = firstPage.getEnclosingWindow();
1176 
1177         final HtmlAnchor anchor = firstPage.getHtmlElementById("link");
1178         final Page secondPage = anchor.click();
1179         assertEquals("First", firstPage.getTitleText());
1180         assertEquals(MimeType.TEXT_HTML, secondPage.getWebResponse().getContentType());
1181 
1182         assertEquals(2, events.size());
1183 
1184         final WebWindow secondWebWindow = (WebWindow) events.get(0).getSource();
1185 
1186         assertSame(webClient.getCurrentWindow(), secondWebWindow);
1187         assertNotSame(firstWebWindow, secondWebWindow);
1188     }
1189 
1190     /**
1191      * Basic test for the <tt>showModalDialog</tt> method. See bug #703.
1192      * @throws Exception if an error occurs
1193      */
1194     @Test
1195     @Alerts("not available")
1196     public void showModalDialog() throws Exception {
1197         final String html1 = DOCTYPE_HTML
1198             + "<html><head><script>\n"
1199             + "  function test() {\n"
1200             + "    if (!window.showModalDialog) {alert('not available'); return; }\n"
1201             + "    alert(window.returnValue);\n"
1202             + "    var o = new Object();\n"
1203             + "    o.firstName = 'Jane';\n"
1204             + "    o.lastName = 'Smith';\n"
1205             + "    var ret = showModalDialog('myDialog.html', o, 'dialogHeight:300px; dialogLeft:200px;');\n"
1206             + "    alert(ret);\n"
1207             + "    alert('finished');\n"
1208             + "  }\n"
1209             + "</script></head><body>\n"
1210             + "  <button onclick='test()' id='b'>Test</button>\n"
1211             + "</body></html>";
1212 
1213         final String html2 = DOCTYPE_HTML
1214             + "<html><head><script>\n"
1215             + "  var o = window.dialogArguments;\n"
1216             + "  alert(o.firstName);\n"
1217             + "  alert(o.lastName);\n"
1218             + "  window.returnValue = 'sdg';\n"
1219             + "</script></head>\n"
1220             + "<body>foo</body></html>";
1221 
1222         final WebClient client = getWebClient();
1223         final List<String> actual = new ArrayList<>();
1224         client.setAlertHandler(new CollectingAlertHandler(actual));
1225 
1226         final MockWebConnection conn = new MockWebConnection();
1227         conn.setResponse(URL_FIRST, html1);
1228         conn.setResponse(new URL(URL_FIRST, "myDialog.html"), html2);
1229         client.setWebConnection(conn);
1230 
1231         final HtmlPage page = client.getPage(URL_FIRST);
1232         final HtmlElement button = page.getHtmlElementById("b");
1233         final HtmlPage dialogPage = button.click();
1234 
1235         if (getExpectedAlerts().length > 1) {
1236             final DialogWindow dialog = (DialogWindow) dialogPage.getEnclosingWindow();
1237             dialog.close();
1238         }
1239 
1240         assertEquals(getExpectedAlerts(), actual);
1241     }
1242 
1243     /**
1244      * Test for the <tt>showModalDialog</tt> method.
1245      * This tests blocking until the window gets closed.
1246      * Can not currently be tested with WebDriver
1247      * https://github.com/seleniumhq/selenium-google-code-issue-archive/issues/284
1248      *
1249      * To fix this, we need to allow user to interact with the opened dialog before showModalDialog() returns
1250      * @throws Exception if an error occurs
1251      */
1252     @Test
1253     @Alerts({"undefined", "not available"})
1254     public void showModalDialogWithButton() throws Exception {
1255         final String html1 = DOCTYPE_HTML
1256             + "<html><head>\n"
1257             + "  <script>\n"
1258             + "    function test() {\n"
1259             + "      alert(window.returnValue);\n"
1260             + "      if (!window.showModalDialog) {alert('not available'); return; }\n"
1261             + "      var res = showModalDialog('myDialog.html', null, 'dialogHeight:300px; dialogLeft:200px;');\n"
1262             + "      alert(res);\n"
1263             + "      alert('finished');\n"
1264             + "    }\n"
1265             + "  </script>\n"
1266             + "</head>\n"
1267             + "<body>\n"
1268             + "  <button onclick='test()' id='openDlg'>Test</button>\n"
1269             + "</body></html>";
1270 
1271         final String html2 = DOCTYPE_HTML
1272             + "<html><head>\n"
1273             + "</head>\n"
1274             + "<body>\n"
1275             + "  <button id='closeDlg' onclick='window.returnValue = \"result\"; window.close();'></button>\n"
1276             + "</body>\n"
1277             + "</html>";
1278 
1279         final WebClient client = getWebClient();
1280         final List<String> actual = new ArrayList<>();
1281         client.setAlertHandler(new CollectingAlertHandler(actual));
1282 
1283         final MockWebConnection conn = new MockWebConnection();
1284         conn.setResponse(URL_FIRST, html1);
1285         conn.setResponse(new URL(URL_FIRST, "myDialog.html"), html2);
1286         client.setWebConnection(conn);
1287 
1288         final HtmlPage page = getWebClient().getPage(URL_FIRST);
1289         final HtmlElement button = page.getHtmlElementById("openDlg");
1290         button.click();
1291 
1292         // TODO: <button id='closeDlg'> should be clicked
1293         assertEquals(getExpectedAlerts(), actual);
1294     }
1295 
1296     /**
1297      * Basic test for the <tt>showModelessDialog</tt> method. See bug #703.
1298      * @throws Exception if an error occurs
1299      */
1300     @Test
1301     @Alerts("")
1302     public void showModelessDialog() throws Exception {
1303         final String html1 = DOCTYPE_HTML
1304             + "<html><head><script>\n"
1305             + "  var userName = '';\n"
1306             + "  function test() {\n"
1307             + "    if (window.showModelessDialog) {\n"
1308             + "      var newWindow = showModelessDialog('myDialog.html', window, 'status:false');\n"
1309             + "      alert(newWindow);\n"
1310             + "    }\n"
1311             + "  }\n"
1312             + "  function update() { alert(userName); }\n"
1313             + "</script></head><body>\n"
1314             + "  <input type='button' id='b' value='Test' onclick='test()'>\n"
1315             + "</body></html>";
1316 
1317         final String html2 = DOCTYPE_HTML
1318             + "<html><head><script>\n"
1319             + "function update() {\n"
1320             + "  var w = dialogArguments;\n"
1321             + "  w.userName = document.getElementById('name').value;\n"
1322             + "  w.update();\n"
1323             + "}\n"
1324             + "</script></head><body>\n"
1325             + "  Name: <input id='name'><input value='OK' id='b' type='button' onclick='update()'>\n"
1326             + "</body></html>";
1327 
1328         final WebClient client = getWebClient();
1329         final List<String> actual = new ArrayList<>();
1330         client.setAlertHandler(new CollectingAlertHandler(actual));
1331 
1332         final MockWebConnection conn = new MockWebConnection();
1333         conn.setResponse(URL_FIRST, html1);
1334         conn.setResponse(new URL(URL_FIRST, "myDialog.html"), html2);
1335         client.setWebConnection(conn);
1336 
1337         final HtmlPage page = client.getPage(URL_FIRST);
1338         final HtmlElement button = page.getHtmlElementById("b");
1339         final HtmlPage dialogPage = button.click();
1340 
1341         if (!dialogPage.getUrl().equals(URL_FIRST)) {
1342             final HtmlInput input = dialogPage.getHtmlElementById("name");
1343             input.setValue("a");
1344 
1345             final HtmlButtonInput button2 = (HtmlButtonInput) dialogPage.getHtmlElementById("b");
1346             button2.click();
1347 
1348             assertEquals(getExpectedAlerts(), actual);
1349         }
1350     }
1351 
1352     /**
1353      * @throws Exception if an error occurs
1354      */
1355     @Test
1356     @Alerts({"true", "[object Window]", "[object Window]"})
1357     public void overwriteProperty_top() throws Exception {
1358         final String html = DOCTYPE_HTML
1359             + "<html><body><script>\n"
1360             + "  alert(window.top == this);\n"
1361             + "  var top = 123;\n"
1362             + "  alert(top);\n"
1363             + "  alert(window.top);\n"
1364             + "</script></body></html>";
1365         // this can't be tested using WebDriver currently (i.e. using loadPageWithAlerts2)
1366         // because the hack currently used to capture alerts needs reference to property "top".
1367         loadPageWithAlerts(html);
1368     }
1369 
1370     /**
1371      * @throws Exception if an error occurs
1372      */
1373     @Test
1374     @Alerts({"true", "[object Window]", "[object Window]"})
1375     public void overwriteProperty_top2() throws Exception {
1376         final String html = DOCTYPE_HTML
1377             + "<html><body><script>\n"
1378             + "  alert(window.top == this);\n"
1379             + "  window.top = 123;\n"
1380             + "  alert(top);\n"
1381             + "  alert(window.top);\n"
1382             + "</script></body></html>";
1383         // this can't be tested using WebDriver currently (i.e. using loadPageWithAlerts2)
1384         // because the hack currently used to capture alerts needs reference to property "top".
1385         loadPageWithAlerts(html);
1386     }
1387 
1388     /**
1389      * Download of next page is done first after onbeforeunload is done.
1390      * @throws Exception if an error occurs
1391      */
1392     @Test
1393     @Alerts("x")
1394     public void onbeforeunload_calledBeforeDownload() throws Exception {
1395         final String html = DOCTYPE_HTML
1396             + "<html><body><script>\n"
1397             + "  window.onbeforeunload = function() { alert('x'); return 'hello'; };\n"
1398             + "  window.location = 'foo.html';\n"
1399             + "</script></body></html>";
1400 
1401         final WebClient webClient = getWebClientWithMockWebConnection();
1402         getMockWebConnection().setDefaultResponse("");
1403 
1404         final OnbeforeunloadHandler handler = new OnbeforeunloadHandler() {
1405             @Override
1406             public boolean handleEvent(final Page page, final String returnValue) {
1407                 final String[] expectedRequests = {""};
1408                 assertEquals(expectedRequests, getMockWebConnection().getRequestedUrls(URL_FIRST));
1409                 return true;
1410             }
1411         };
1412         webClient.setOnbeforeunloadHandler(handler);
1413         loadPageWithAlerts(html);
1414 
1415         final String[] expectedRequests = {"", "foo.html"};
1416         assertEquals(expectedRequests, getMockWebConnection().getRequestedUrls(URL_FIRST));
1417     }
1418 
1419     /**
1420      * @throws Exception if an error occurs
1421      */
1422     @Test
1423     public void serialization() throws Exception {
1424         final String html = DOCTYPE_HTML
1425             + "<html><head></head><body><iframe></iframe><script>window.frames</script></body></html>";
1426         final HtmlPage page = loadPageWithAlerts(html);
1427         clone(page.getEnclosingWindow());
1428     }
1429 
1430     /**
1431      * Regression test for bug #844.
1432      * @throws Exception if an error occurs
1433      */
1434     @Test
1435     @Alerts("x")
1436     public void onbeforeunload_setToFunction() throws Exception {
1437         final String html = DOCTYPE_HTML
1438             + "<html><body><script>\n"
1439             + "  window.onbeforeunload = function() { alert('x'); return 'x'; };\n"
1440             + "  window.location = 'about:blank';\n"
1441             + "</script></body></html>";
1442         loadPageWithAlerts(html);
1443     }
1444 
1445     /**
1446      * @throws Exception if an error occurs
1447      */
1448     @Test
1449     @Alerts({"10", "20", "30", "40"})
1450     public void viewportSetters() throws Exception {
1451         final String html = DOCTYPE_HTML
1452                 + "<html>\n"
1453                 + "<head></head>\n"
1454                 + "<body>\n"
1455                 + "<script>\n"
1456                 + "alert(window.innerWidth);\n"
1457                 + "alert(window.innerHeight);\n"
1458                 + "alert(window.outerWidth);\n"
1459                 + "alert(window.outerHeight);\n"
1460                 + "</script>\n"
1461                 + "</body>\n"
1462                 + "</html>";
1463 
1464         final List<String> collectedAlerts = new ArrayList<>();
1465         final WebClient client = getWebClient();
1466         client.setAlertHandler(new CollectingAlertHandler(collectedAlerts));
1467 
1468         final MockWebConnection webConnection = new MockWebConnection();
1469         webConnection.setDefaultResponse(html);
1470         client.setWebConnection(webConnection);
1471 
1472         final WebWindow topLevelWindow = client.getTopLevelWindows().get(0);
1473         topLevelWindow.setInnerWidth(10);
1474         topLevelWindow.setInnerHeight(20);
1475         topLevelWindow.setOuterWidth(30);
1476         topLevelWindow.setOuterHeight(40);
1477         client.getPage(URL_FIRST);
1478         assertEquals(getExpectedAlerts(), collectedAlerts);
1479     }
1480 
1481     /**
1482      * @throws Exception if the test fails
1483      */
1484     @Test
1485     @Alerts(DEFAULT = "",
1486             FF = "info: Dumper",
1487             FF_ESR = "info: Dumper")
1488     public void dump() throws Exception {
1489         final WebConsole console = getWebClient().getWebConsole();
1490         final List<String> messages = new ArrayList<>();
1491         console.setLogger(new Logger() {
1492 
1493             @Override
1494             public void warn(final Object message) {
1495             }
1496 
1497             @Override
1498             public void trace(final Object message) {
1499             }
1500 
1501             @Override
1502             public void info(final Object message) {
1503                 messages.add("info: " + message);
1504             }
1505 
1506             @Override
1507             public void error(final Object message) {
1508             }
1509 
1510             @Override
1511             public void debug(final Object message) {
1512             }
1513 
1514             @Override
1515             public boolean isTraceEnabled() {
1516                 return false;
1517             }
1518 
1519             @Override
1520             public boolean isDebugEnabled() {
1521                 return false;
1522             }
1523 
1524             @Override
1525             public boolean isInfoEnabled() {
1526                 return true;
1527             }
1528 
1529             @Override
1530             public boolean isWarnEnabled() {
1531                 return true;
1532             }
1533 
1534             @Override
1535             public boolean isErrorEnabled() {
1536                 return true;
1537             }
1538         });
1539 
1540         final String html = DOCTYPE_HTML
1541             + "<html><head><title>foo</title><script>\n"
1542             + "function test() {\n"
1543             + "  if (window.dump) {\n"
1544             + "    window.dump('Dumper');\n"
1545             + "  }\n"
1546             + "}\n"
1547             + "</script></head><body onload='test()'></body></html>";
1548 
1549         loadPage(html);
1550         assertEquals(getExpectedAlerts(), messages);
1551     }
1552 
1553     /**
1554      * Regression test for http://sourceforge.net/p/htmlunit/bugs/234/
1555      * and https://bugzilla.mozilla.org/show_bug.cgi?id=443491.
1556      * @throws Exception if the test fails
1557      */
1558     @Test
1559     public void overwriteFunctions_alert() throws Exception {
1560         final String html = DOCTYPE_HTML
1561             + "<html>\n"
1562             + "<head>\n"
1563             + "  <script language='JavaScript'>\n"
1564             + "    function alert(x) {\n"
1565             + "      document.title = x;\n"
1566             + "    }\n"
1567             + "    alert('hello');\n"
1568             + "  </script>\n"
1569             + "</head>\n"
1570             + "<body>\n"
1571             + "</body>\n"
1572             + "</html>";
1573 
1574         final HtmlPage page = loadPageWithAlerts(html);
1575         assertEquals("hello", page.getTitleText());
1576     }
1577 
1578     /**
1579      * @throws Exception if the test fails
1580      */
1581     @Test
1582     @Alerts({"before print§printed§from timeout§", "before print§print handled§printed§from timeout§"})
1583     public void printHandler() throws Exception {
1584         // we have to test this manually
1585 
1586         final WebClient webClient = getWebClient();
1587         final MockWebConnection webConnection = new MockWebConnection();
1588 
1589         final String firstContent = DOCTYPE_HTML
1590             + "<html><head>\n"
1591             + "<script>\n"
1592             + "  function log(msg) { window.document.title += msg + '§'; }\n"
1593 
1594             + "  function doTest() {\n"
1595             + "    setTimeout(() => { log('from timeout'); }, 100)\n"
1596             + "    log('before print');\n"
1597             + "    window.print();\n"
1598             + "    log('printed');\n"
1599             + "  }\n"
1600             + "</script>\n"
1601             + "</head>\n"
1602             + "<body>\n"
1603             + "  <button id='click' onclick='doTest()'>Print</button>\n"
1604             + "</body></html>";
1605 
1606         final URL url = URL_FIRST;
1607         webConnection.setResponse(url, firstContent);
1608         webClient.setWebConnection(webConnection);
1609 
1610         HtmlPage page = webClient.getPage(URL_FIRST);
1611         page.getElementById("click").click();
1612         webClient.waitForBackgroundJavaScript(DEFAULT_WAIT_TIME.toMillis());
1613 
1614         assertEquals(getExpectedAlerts()[0], page.getTitleText());
1615 
1616         webClient.setPrintHandler(new PrintHandler() {
1617             @Override
1618             public void handlePrint(final HtmlPage pageToPrint) {
1619                 try {
1620                     Thread.sleep(DEFAULT_WAIT_TIME.toMillis());
1621                 }
1622                 catch (final InterruptedException e) {
1623                     pageToPrint.executeJavaScript("log('" + e.getMessage() + "');");
1624                 }
1625                 pageToPrint.executeJavaScript("log('print handled');");
1626             }
1627         });
1628 
1629         page = webClient.getPage(URL_FIRST);
1630         page.getElementById("click").click();
1631         webClient.waitForBackgroundJavaScript(200000 * DEFAULT_WAIT_TIME.toMillis());
1632 
1633         assertEquals(getExpectedAlerts()[1], page.getTitleText());
1634     }
1635 
1636     /**
1637      * @throws Exception if the test fails
1638      */
1639     @Test
1640     @Alerts("before print"
1641                     + "§event beforeprint"
1642                     + "§[object Event]beforeprint-false-false-false-[object Window]"
1643                         + "-false-2-true-true-[object Window]-[object Window]-beforeprint"
1644                     + "§event afterprint"
1645                     + "§[object Event]afterprint-false-false-false-[object Window]"
1646                         + "-false-2-true-true-[object Window]-[object Window]-afterprint"
1647                     + "§printed§")
1648     @HtmlUnitNYI(CHROME = "before print"
1649                     + "§event beforeprint"
1650                     + "§[object Event]beforeprint-false-false-false-[object Window]"
1651                         + "-false-2-undefined-true-[object Window]-[object Window]-beforeprint"
1652                     + "§event afterprint"
1653                     + "§[object Event]afterprint-false-false-false-[object Window]"
1654                         + "-false-2-undefined-true-[object Window]-[object Window]-afterprint"
1655                     + "§printed§",
1656             EDGE = "before print"
1657                     + "§event beforeprint"
1658                     + "§[object Event]beforeprint-false-false-false-[object Window]"
1659                         + "-false-2-undefined-true-[object Window]-[object Window]-beforeprint"
1660                     + "§event afterprint"
1661                     + "§[object Event]afterprint-false-false-false-[object Window]"
1662                         + "-false-2-undefined-true-[object Window]-[object Window]-afterprint"
1663                     + "§printed§",
1664             FF = "before print"
1665                     + "§event beforeprint"
1666                     + "§[object Event]beforeprint-false-false-false-[object Window]"
1667                         + "-false-2-undefined-true-[object Window]-[object Window]-beforeprint"
1668                     + "§event afterprint"
1669                     + "§[object Event]afterprint-false-false-false-[object Window]"
1670                         + "-false-2-undefined-true-[object Window]-[object Window]-afterprint"
1671                     + "§printed§",
1672             FF_ESR = "before print"
1673                     + "§event beforeprint"
1674                     + "§[object Event]beforeprint-false-false-false-[object Window]"
1675                         + "-false-2-undefined-true-[object Window]-[object Window]-beforeprint"
1676                     + "§event afterprint"
1677                     + "§[object Event]afterprint-false-false-false-[object Window]"
1678                         + "-false-2-undefined-true-[object Window]-[object Window]-afterprint"
1679                     + "§printed§")
1680     public void printEvent() throws Exception {
1681         // we have to test this manually
1682 
1683         final WebClient webClient = getWebClient();
1684         final MockWebConnection webConnection = new MockWebConnection();
1685 
1686         // without an print handler set the print method is a noop
1687         webClient.setPrintHandler(new PrintHandler() {
1688             @Override
1689             public void handlePrint(final HtmlPage page) {
1690             }
1691         });
1692 
1693 
1694         final String firstContent = DOCTYPE_HTML
1695             + "<html><head>\n"
1696             + "<script>\n"
1697             + "  function log(msg) { window.document.title += msg + '§'; }\n"
1698 
1699             + "  function dumpEvent(event) {\n"
1700             + "    var msg = event;\n"
1701             + "    msg = msg + event.type;\n"
1702             + "    msg = msg + '-' + event.bubbles;\n"
1703             + "    msg = msg + '-' + event.cancelable;\n"
1704             + "    msg = msg + '-' + event.composed;\n"
1705             + "    msg = msg + '-' + event.currentTarget;\n"
1706             + "    msg = msg + '-' + event.defaultPrevented;\n"
1707             + "    msg = msg + '-' + event.eventPhase;\n"
1708             + "    msg = msg + '-' + event.isTrusted;\n"
1709             + "    msg = msg + '-' + event.returnValue;\n"
1710             + "    msg = msg + '-' + event.srcElement;\n"
1711             + "    msg = msg + '-' + event.target;\n"
1712             // + "    msg = msg + '-' + event.timeStamp;\n"
1713             + "    msg = msg + '-' + event.type;\n"
1714             + "    log(msg);\n"
1715             + "  }\n"
1716 
1717             + "  function doTest() {\n"
1718             + "    addEventListener('beforeprint', function(e) { log('event beforeprint'); dumpEvent(e); })\n"
1719             + "    addEventListener('afterprint', function(e) { log('event afterprint'); dumpEvent(e); })\n"
1720 
1721             + "    log('before print');\n"
1722             + "    window.print();\n"
1723             + "    log('printed');\n"
1724             + "  }\n"
1725             + "</script>\n"
1726             + "</head>\n"
1727             + "<body>\n"
1728             + "  <button id='click' onclick='doTest()'>Print</button>\n"
1729             + "</body></html>";
1730 
1731         final URL url = URL_FIRST;
1732         webConnection.setResponse(url, firstContent);
1733         webClient.setWebConnection(webConnection);
1734 
1735         final HtmlPage page = webClient.getPage(URL_FIRST);
1736         page.getElementById("click").click();
1737         webClient.waitForBackgroundJavaScript(DEFAULT_WAIT_TIME.toMillis());
1738 
1739         assertEquals(getExpectedAlerts()[0], page.getTitleText());
1740     }
1741 
1742     /**
1743      * @throws Exception if the test fails
1744      */
1745     @Test
1746     @Alerts("block§none§block§")
1747     public void printCssMediaRule() throws Exception {
1748         // we have to test this manually
1749 
1750         final WebClient webClient = getWebClient();
1751         final MockWebConnection webConnection = new MockWebConnection();
1752 
1753         // without an print handler set the print method is a noop
1754         webClient.setPrintHandler(new PrintHandler() {
1755             @Override
1756             public void handlePrint(final HtmlPage page) {
1757                 page.executeJavaScript(
1758                         "log(window.getComputedStyle(document.getElementById('tester') ,null)"
1759                                 + ".getPropertyValue('display'))");
1760             }
1761         });
1762 
1763 
1764         final String firstContent = DOCTYPE_HTML
1765             + "<html><head>\n"
1766             + "<script>\n"
1767             + "  function log(msg) { window.document.title += msg + '§'; }\n"
1768 
1769             + "  function doTest() {\n"
1770             + "    log(window.getComputedStyle(document.getElementById('tester') ,null)"
1771                         + ".getPropertyValue('display'));\n"
1772             + "    window.print();\n"
1773             + "    log(window.getComputedStyle(document.getElementById('tester') ,null)"
1774                         + ".getPropertyValue('display'));\n"
1775             + "  }\n"
1776             + "</script>\n"
1777             + "<style type='text/css'>\n"
1778             + "  @media print { p { display: none }}\n"
1779             + "</style>"
1780             + "</head>\n"
1781             + "<body>\n"
1782             + "  <p id='tester'>HtmlUnit</p>\n"
1783             + "  <button id='click' onclick='doTest()'>Print</button>\n"
1784             + "</body></html>";
1785 
1786         final URL url = URL_FIRST;
1787         webConnection.setResponse(url, firstContent);
1788         webClient.setWebConnection(webConnection);
1789 
1790         final HtmlPage page = webClient.getPage(URL_FIRST);
1791         page.getElementById("click").click();
1792         webClient.waitForBackgroundJavaScript(DEFAULT_WAIT_TIME.toMillis());
1793 
1794         assertEquals(getExpectedAlerts()[0], page.getTitleText());
1795     }
1796 }