[M85 Dev][EFL] Fix errors to generate ninja files
[platform/framework/web/chromium-efl.git] / chrome / browser / unload_browsertest.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #if defined(OS_POSIX)
6 #include <signal.h>
7 #endif
8
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/run_loop.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/task/post_task.h"
14 #include "build/build_config.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/browser_commands.h"
18 #include "chrome/browser/ui/browser_list.h"
19 #include "chrome/browser/ui/tabs/tab_strip_model.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/test/base/in_process_browser_test.h"
22 #include "chrome/test/base/ui_test_utils.h"
23 #include "components/embedder_support/switches.h"
24 #include "components/javascript_dialogs/app_modal_dialog_controller.h"
25 #include "components/javascript_dialogs/app_modal_dialog_view.h"
26 #include "content/public/browser/browser_task_traits.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/render_frame_host.h"
29 #include "content/public/browser/web_contents.h"
30 #include "content/public/common/content_switches.h"
31 #include "content/public/test/browser_test.h"
32 #include "content/public/test/browser_test_utils.h"
33 #include "net/dns/mock_host_resolver.h"
34 #include "net/test/embedded_test_server/embedded_test_server.h"
35
36 using base::TimeDelta;
37 using content::BrowserThread;
38
39 const char NOLISTENERS_HTML[] =
40     "<html><head><title>nolisteners</title></head><body></body></html>";
41
42 const char UNLOAD_HTML[] =
43     "<html><head><title>unload</title></head><body>"
44     "<script>window.onunload=function(e){}</script></body></html>";
45
46 const char BEFORE_UNLOAD_HTML[] =
47     "<html><head><title>beforeunload</title></head><body>"
48     "<script>window.onbeforeunload=function(e){"
49     "setTimeout('document.title=\"cancelled\"', 0);return 'foo'}</script>"
50     "</body></html>";
51
52 const char INNER_FRAME_WITH_FOCUS_HTML[] =
53     "<html><head><title>innerframewithfocus</title></head><body>"
54     "<script>window.onbeforeunload=function(e){return 'foo'}</script>"
55     "<iframe src=\"data:text/html,<html><head><script>window.onload="
56     "function(){document.getElementById('box').focus()}</script>"
57     "<body><input id='box'></input></body></html>\"></iframe>"
58     "</body></html>";
59
60 const char INFINITE_UNLOAD_HTML[] =
61     "<html><head><title>infiniteunload</title></head><body>"
62     "<script>window.onunload=function(e){while(true){}}</script>"
63     "</body></html>";
64
65 const char INFINITE_BEFORE_UNLOAD_HTML[] =
66     "<html><head><title>infinitebeforeunload</title></head><body>"
67     "<script>window.onbeforeunload=function(e){while(true){}}</script>"
68     "</body></html>";
69
70 const char INFINITE_UNLOAD_ALERT_HTML[] =
71     "<html><head><title>infiniteunloadalert</title></head><body>"
72     "<script>window.onunload=function(e){"
73     "while(true){}"
74     "alert('foo');"
75     "}</script></body></html>";
76
77 const char INFINITE_BEFORE_UNLOAD_ALERT_HTML[] =
78     "<html><head><title>infinitebeforeunloadalert</title></head><body>"
79     "<script>window.onbeforeunload=function(e){"
80     "while(true){}"
81     "alert('foo');"
82     "}</script></body></html>";
83
84 const char TWO_SECOND_UNLOAD_ALERT_HTML[] =
85     "<html><head><title>twosecondunloadalert</title></head><body>"
86     "<script>window.onunload=function(e){"
87     "var start = new Date().getTime();"
88     "while(new Date().getTime() - start < 2000){}"
89     "alert('foo');"
90     "}</script></body></html>";
91
92 const char TWO_SECOND_BEFORE_UNLOAD_ALERT_HTML[] =
93     "<html><head><title>twosecondbeforeunloadalert</title></head><body>"
94     "<script>window.onbeforeunload=function(e){"
95     "var start = new Date().getTime();"
96     "while(new Date().getTime() - start < 2000){}"
97     "alert('foo');"
98     "}</script></body></html>";
99
100 const char CLOSE_TAB_WHEN_OTHER_TAB_HAS_LISTENER[] =
101     "<html><head><title>only_one_unload</title></head>"
102     "<script>"
103     "function openPopup() {"
104     "  var w = window.open('about:blank');"
105     "  w.document.write('<html><head><title>popup</title></head></body>');"
106     "}"
107     "</script>"
108     "<body onclick='openPopup()' onbeforeunload='return;'>"
109     "</body></html>";
110
111 class UnloadResults {
112  public:
113   UnloadResults() : successes_(0), aborts_(0) {}
114
115   void AddSuccess(const base::FilePath&) { successes_++; }
116   void AddAbort(const base::FilePath&) { aborts_++; }
117   void AddError(const base::FilePath&) {
118     ADD_FAILURE() << "AddError should not be called.";
119   }
120
121   int get_successes() { return successes_; }
122   int get_aborts() { return aborts_; }
123
124  private:
125   int successes_;
126   int aborts_;
127 };
128
129 class UnloadTest : public InProcessBrowserTest {
130  public:
131   void SetUpCommandLine(base::CommandLine* command_line) override {
132     const testing::TestInfo* const test_info =
133         testing::UnitTest::GetInstance()->current_test_info();
134     if (strstr(test_info->name(), "BrowserCloseTabWhenOtherTabHasListener") !=
135         nullptr) {
136       command_line->AppendSwitch(embedder_support::kDisablePopupBlocking);
137     } else if (strstr(test_info->name(), "BrowserTerminateBeforeUnload") !=
138                nullptr) {
139 #if defined(OS_POSIX)
140       DisableSIGTERMHandling();
141 #endif
142     }
143   }
144
145   void SetUpOnMainThread() override {
146     host_resolver()->AddRule("*", "127.0.0.1");
147   }
148
149   void CheckTitle(const char* expected_title, bool wait = false) {
150     auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents();
151     base::string16 expected = base::ASCIIToUTF16(expected_title);
152     base::string16 actual;
153     if (wait)
154       actual = content::TitleWatcher(web_contents, expected).WaitAndGetTitle();
155     else
156       actual = web_contents->GetTitle();
157     EXPECT_EQ(expected, actual);
158   }
159
160   void NavigateToDataURL(const char* html_content, const char* expected_title) {
161     ui_test_utils::NavigateToURL(
162         browser(), GURL(std::string("data:text/html,") + html_content));
163     CheckTitle(expected_title);
164   }
165
166   void NavigateToNolistenersFileTwice() {
167     ASSERT_TRUE(embedded_test_server()->Start());
168     GURL url(embedded_test_server()->GetURL("/title2.html"));
169     ui_test_utils::NavigateToURL(browser(), url);
170     CheckTitle("Title Of Awesomeness");
171     ui_test_utils::NavigateToURL(browser(), url);
172     CheckTitle("Title Of Awesomeness");
173   }
174
175   // Navigates to a URL asynchronously, then again synchronously. The first
176   // load is purposely async to test the case where the user loads another
177   // page without waiting for the first load to complete.
178   void NavigateToNolistenersFileTwiceAsync() {
179     ASSERT_TRUE(embedded_test_server()->Start());
180     GURL url(embedded_test_server()->GetURL("/title2.html"));
181     ui_test_utils::NavigateToURLWithDisposition(
182         browser(), url, WindowOpenDisposition::CURRENT_TAB, 0);
183     ui_test_utils::NavigateToURL(browser(), url);
184     CheckTitle("Title Of Awesomeness");
185   }
186
187   void LoadUrlAndQuitBrowser(const char* html_content,
188                              const char* expected_title) {
189     NavigateToDataURL(html_content, expected_title);
190     CloseBrowserSynchronously(browser());
191   }
192
193   // If |accept| is true, simulates user clicking OK, otherwise simulates
194   // clicking Cancel.
195   void ClickModalDialogButton(bool accept) {
196     javascript_dialogs::AppModalDialogController* dialog =
197         ui_test_utils::WaitForAppModalDialog();
198     if (accept)
199       dialog->view()->AcceptAppModalDialog();
200     else
201       dialog->view()->CancelAppModalDialog();
202   }
203
204   void PrepareForDialog(Browser* browser) {
205     for (int i = 0; i < browser->tab_strip_model()->count(); i++) {
206       content::PrepContentsForBeforeUnloadTest(
207           browser->tab_strip_model()->GetWebContentsAt(i));
208     }
209   }
210
211   void CloseBrowsersVerifyUnloadSuccess(bool force) {
212     UnloadResults unload_results;
213     BrowserList::CloseAllBrowsersWithProfile(
214         browser()->profile(),
215         base::Bind(&UnloadResults::AddSuccess,
216                    base::Unretained(&unload_results)),
217         base::Bind(&UnloadResults::AddAbort, base::Unretained(&unload_results)),
218         force);
219     ui_test_utils::WaitForBrowserToClose();
220     EXPECT_EQ(1, unload_results.get_successes());
221     EXPECT_EQ(0, unload_results.get_aborts());
222   }
223
224   // The test harness cannot close the window automatically, because it requires
225   // confirmation. We close the window manually instead.
226   void ManuallyCloseWindow() {
227     chrome::CloseWindow(browser());
228     ClickModalDialogButton(true);
229     ui_test_utils::WaitForBrowserToClose();
230   }
231 };
232
233 // Navigate to a page with an infinite unload handler.
234 // Then two async crosssite requests to ensure
235 // we don't get confused and think we're closing the tab.
236 //
237 // This test is flaky on the valgrind UI bots. http://crbug.com/39057
238 IN_PROC_BROWSER_TEST_F(UnloadTest, CrossSiteInfiniteUnloadAsync) {
239   // Tests makes no sense in single-process mode since the renderer is hung.
240   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
241           switches::kSingleProcess))
242     return;
243
244   NavigateToDataURL(INFINITE_UNLOAD_HTML, "infiniteunload");
245   // Must navigate to a non-data URL to trigger cross-site codepath.
246   NavigateToNolistenersFileTwiceAsync();
247 }
248
249 // Navigate to a page with an infinite unload handler.
250 // Then two sync crosssite requests to ensure
251 // we correctly nav to each one.
252 IN_PROC_BROWSER_TEST_F(UnloadTest, CrossSiteInfiniteUnloadSync) {
253   // Tests makes no sense in single-process mode since the renderer is hung.
254   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
255           switches::kSingleProcess))
256     return;
257
258   NavigateToDataURL(INFINITE_UNLOAD_HTML, "infiniteunload");
259   // Must navigate to a non-data URL to trigger cross-site codepath.
260   NavigateToNolistenersFileTwice();
261 }
262
263 // Navigate to a page with an infinite beforeunload handler.
264 // Then two two async crosssite requests to ensure
265 // we don't get confused and think we're closing the tab.
266 // This test is flaky on the valgrind UI bots. http://crbug.com/39057 and
267 // http://crbug.com/86469
268 IN_PROC_BROWSER_TEST_F(UnloadTest, CrossSiteInfiniteBeforeUnloadAsync) {
269   // Tests makes no sense in single-process mode since the renderer is hung.
270   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
271           switches::kSingleProcess))
272     return;
273
274   NavigateToDataURL(INFINITE_BEFORE_UNLOAD_HTML, "infinitebeforeunload");
275   // Must navigate to a non-data URL to trigger cross-site codepath.
276   NavigateToNolistenersFileTwiceAsync();
277 }
278
279 // Navigate to a page with an infinite beforeunload handler.
280 // Then two two sync crosssite requests to ensure
281 // we correctly nav to each one.
282 // Flaky on Win, Linux, and Mac; http://crbug.com/462671.
283 IN_PROC_BROWSER_TEST_F(UnloadTest, DISABLED_CrossSiteInfiniteBeforeUnloadSync) {
284   // Tests makes no sense in single-process mode since the renderer is hung.
285   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
286           switches::kSingleProcess))
287     return;
288
289   NavigateToDataURL(INFINITE_BEFORE_UNLOAD_HTML, "infinitebeforeunload");
290   // Must navigate to a non-data URL to trigger cross-site codepath.
291   NavigateToNolistenersFileTwice();
292 }
293
294 // Tests closing the browser on a page with no unload listeners registered.
295 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseNoUnloadListeners) {
296   LoadUrlAndQuitBrowser(NOLISTENERS_HTML, "nolisteners");
297 }
298
299 // Tests closing the browser on a page with an unload listener registered.
300 // Test marked as flaky in http://crbug.com/51698
301 IN_PROC_BROWSER_TEST_F(UnloadTest, DISABLED_BrowserCloseUnload) {
302   LoadUrlAndQuitBrowser(UNLOAD_HTML, "unload");
303 }
304
305 // Tests closing the browser with a beforeunload handler and clicking
306 // OK in the beforeunload confirm dialog.
307 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseBeforeUnloadOK) {
308   NavigateToDataURL(BEFORE_UNLOAD_HTML, "beforeunload");
309   PrepareForDialog(browser());
310
311   chrome::CloseWindow(browser());
312   ClickModalDialogButton(true);
313   ui_test_utils::WaitForBrowserToClose();
314 }
315
316 // Tests closing the browser with a beforeunload handler and clicking
317 // CANCEL in the beforeunload confirm dialog.
318 // If this test flakes, reopen http://crbug.com/123110
319 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseBeforeUnloadCancel) {
320   NavigateToDataURL(BEFORE_UNLOAD_HTML, "beforeunload");
321   PrepareForDialog(browser());
322   chrome::CloseWindow(browser());
323
324   // We wait for the title to change after cancelling the closure of browser
325   // window, to ensure that in-flight IPCs from the renderer reach the browser.
326   // Otherwise the browser won't put up the beforeunload dialog because it's
327   // waiting for an ack from the renderer.
328   base::string16 expected_title = base::ASCIIToUTF16("cancelled");
329   content::TitleWatcher title_watcher(
330       browser()->tab_strip_model()->GetActiveWebContents(), expected_title);
331   ClickModalDialogButton(false);
332   ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
333
334   ManuallyCloseWindow();
335 }
336
337 // Tests closing the browser by BrowserList::CloseAllBrowsersWithProfile,
338 // on a page with no unload listeners registered.
339 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserListCloseNoUnloadListeners) {
340   NavigateToDataURL(NOLISTENERS_HTML, "nolisteners");
341
342   CloseBrowsersVerifyUnloadSuccess(false);
343 }
344
345 // Tests closing the browser by BrowserList::CloseAllBrowsersWithProfile, with a
346 // beforeunload handler and clicking Leave in the beforeunload confirm dialog.
347 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserListCloseBeforeUnloadOK) {
348   NavigateToDataURL(BEFORE_UNLOAD_HTML, "beforeunload");
349   PrepareForDialog(browser());
350
351   UnloadResults unload_results;
352   BrowserList::CloseAllBrowsersWithProfile(
353       browser()->profile(),
354       base::Bind(&UnloadResults::AddSuccess, base::Unretained(&unload_results)),
355       base::Bind(&UnloadResults::AddAbort, base::Unretained(&unload_results)),
356       false);
357   ClickModalDialogButton(true);
358   ui_test_utils::WaitForBrowserToClose();
359   EXPECT_EQ(1, unload_results.get_successes());
360   EXPECT_EQ(0, unload_results.get_aborts());
361 }
362
363 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserListForceCloseNoUnloadListeners) {
364   NavigateToDataURL(NOLISTENERS_HTML, "nolisteners");
365
366   CloseBrowsersVerifyUnloadSuccess(true);
367 }
368
369 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserListForceCloseWithBeforeUnload) {
370   NavigateToDataURL(BEFORE_UNLOAD_HTML, "beforeunload");
371
372   CloseBrowsersVerifyUnloadSuccess(true);
373 }
374
375 // Tests closing the browser by BrowserList::CloseAllBrowsersWithProfile, with a
376 // beforeunload handler and clicking Stay in the beforeunload confirm dialog.
377 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserListCloseBeforeUnloadCancel) {
378   NavigateToDataURL(BEFORE_UNLOAD_HTML, "beforeunload");
379   PrepareForDialog(browser());
380
381   UnloadResults unload_results;
382   BrowserList::CloseAllBrowsersWithProfile(
383       browser()->profile(),
384       base::Bind(&UnloadResults::AddSuccess, base::Unretained(&unload_results)),
385       base::Bind(&UnloadResults::AddAbort, base::Unretained(&unload_results)),
386       false);
387
388   // We wait for the title to change after cancelling the closure of browser
389   // window, to ensure that in-flight IPCs from the renderer reach the browser.
390   // Otherwise the browser won't put up the beforeunload dialog because it's
391   // waiting for an ack from the renderer.
392   base::string16 expected_title = base::ASCIIToUTF16("cancelled");
393   content::TitleWatcher title_watcher(
394       browser()->tab_strip_model()->GetActiveWebContents(), expected_title);
395   ClickModalDialogButton(false);
396   ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
397
398   EXPECT_EQ(0, unload_results.get_successes());
399   EXPECT_EQ(1, unload_results.get_aborts());
400
401   ManuallyCloseWindow();
402 }
403
404 // Tests double calls to BrowserList::CloseAllBrowsersWithProfile, with a
405 // beforeunload handler and clicking Leave in the beforeunload confirm dialog.
406 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserListDoubleCloseBeforeUnloadOK) {
407   NavigateToDataURL(BEFORE_UNLOAD_HTML, "beforeunload");
408   PrepareForDialog(browser());
409
410   UnloadResults unload_results;
411   BrowserList::CloseAllBrowsersWithProfile(
412       browser()->profile(),
413       base::Bind(&UnloadResults::AddSuccess, base::Unretained(&unload_results)),
414       base::Bind(&UnloadResults::AddAbort, base::Unretained(&unload_results)),
415       false);
416   BrowserList::CloseAllBrowsersWithProfile(
417       browser()->profile(),
418       base::Bind(&UnloadResults::AddSuccess, base::Unretained(&unload_results)),
419       base::Bind(&UnloadResults::AddAbort, base::Unretained(&unload_results)),
420       false);
421   ClickModalDialogButton(true);
422   ui_test_utils::WaitForBrowserToClose();
423   EXPECT_EQ(1, unload_results.get_successes());
424   EXPECT_EQ(0, unload_results.get_aborts());
425 }
426
427 // Tests double calls to BrowserList::CloseAllBrowsersWithProfile, with a
428 // beforeunload handler and clicking Stay in the beforeunload confirm dialog.
429 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserListDoubleCloseBeforeUnloadCancel) {
430   NavigateToDataURL(BEFORE_UNLOAD_HTML, "beforeunload");
431   PrepareForDialog(browser());
432
433   UnloadResults unload_results;
434   BrowserList::CloseAllBrowsersWithProfile(
435       browser()->profile(),
436       base::Bind(&UnloadResults::AddSuccess, base::Unretained(&unload_results)),
437       base::Bind(&UnloadResults::AddAbort, base::Unretained(&unload_results)),
438       false);
439   BrowserList::CloseAllBrowsersWithProfile(
440       browser()->profile(),
441       base::Bind(&UnloadResults::AddSuccess, base::Unretained(&unload_results)),
442       base::Bind(&UnloadResults::AddAbort, base::Unretained(&unload_results)),
443       false);
444
445   // We wait for the title to change after cancelling the closure of browser
446   // window, to ensure that in-flight IPCs from the renderer reach the browser.
447   // Otherwise the browser won't put up the beforeunload dialog because it's
448   // waiting for an ack from the renderer.
449   base::string16 expected_title = base::ASCIIToUTF16("cancelled");
450   content::TitleWatcher title_watcher(
451       browser()->tab_strip_model()->GetActiveWebContents(), expected_title);
452   ClickModalDialogButton(false);
453   ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
454
455   EXPECT_EQ(0, unload_results.get_successes());
456   EXPECT_EQ(1, unload_results.get_aborts());
457
458   ManuallyCloseWindow();
459 }
460
461 // Tests closing the browser by BrowserList::CloseAllBrowsersWithProfile, with
462 // a null success callback, a beforeunload handler and clicking Leave in the
463 // beforeunload confirm dialog. The test succeed if no crash happens.
464 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserListCloseBeforeUnloadNullCallbackOk) {
465   NavigateToDataURL(BEFORE_UNLOAD_HTML, "beforeunload");
466   PrepareForDialog(browser());
467
468   UnloadResults unload_results;
469   BrowserList::CloseAllBrowsersWithProfile(browser()->profile(),
470                                            BrowserList::CloseCallback(),
471                                            BrowserList::CloseCallback(), false);
472   ClickModalDialogButton(true);
473   ui_test_utils::WaitForBrowserToClose();
474 }
475
476 // Tests closing the browser by BrowserList::CloseAllBrowsersWithProfile, with
477 // a null failure callback, a beforeunload handler and clicking Stay in the
478 // beforeunload confirm dialog. The test succeed if no crash happens.
479 IN_PROC_BROWSER_TEST_F(UnloadTest,
480                        BrowserListCloseBeforeUnloadNullCallbackCancel) {
481   NavigateToDataURL(BEFORE_UNLOAD_HTML, "beforeunload");
482   PrepareForDialog(browser());
483
484   UnloadResults unload_results;
485   BrowserList::CloseAllBrowsersWithProfile(browser()->profile(),
486                                            BrowserList::CloseCallback(),
487                                            BrowserList::CloseCallback(), false);
488
489   // We wait for the title to change after cancelling the closure of browser
490   // window, to ensure that in-flight IPCs from the renderer reach the browser.
491   // Otherwise the browser won't put up the beforeunload dialog because it's
492   // waiting for an ack from the renderer.
493   base::string16 expected_title = base::ASCIIToUTF16("cancelled");
494   content::TitleWatcher title_watcher(
495       browser()->tab_strip_model()->GetActiveWebContents(), expected_title);
496   ClickModalDialogButton(false);
497   ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
498
499   ManuallyCloseWindow();
500 }
501
502 // Tests terminating the browser with a beforeunload handler.
503 // Currently only ChromeOS shuts down gracefully.
504 #if defined(OS_CHROMEOS)
505 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserTerminateBeforeUnload) {
506   NavigateToDataURL(BEFORE_UNLOAD_HTML, "beforeunload");
507   EXPECT_EQ(kill(base::GetCurrentProcessHandle(), SIGTERM), 0);
508 }
509 #endif
510
511 // Tests closing the browser and clicking OK in the beforeunload confirm dialog
512 // if an inner frame has the focus.
513 // If this flakes, use http://crbug.com/32615 and http://crbug.com/45675
514 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseWithInnerFocusedFrame) {
515   NavigateToDataURL(INNER_FRAME_WITH_FOCUS_HTML, "innerframewithfocus");
516   PrepareForDialog(browser());
517
518   ManuallyCloseWindow();
519 }
520
521 // Tests closing the browser with a beforeunload handler that takes forever
522 // by running an infinite loop.
523 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseInfiniteBeforeUnload) {
524   LoadUrlAndQuitBrowser(INFINITE_BEFORE_UNLOAD_HTML,
525                         "infinitebeforeunload");
526 }
527
528 // Tests closing the browser on a page with an unload listener registered where
529 // the unload handler has an infinite loop.
530 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseInfiniteUnload) {
531   // Tests makes no sense in single-process mode since the renderer is hung.
532   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
533           switches::kSingleProcess))
534     return;
535
536   LoadUrlAndQuitBrowser(INFINITE_UNLOAD_HTML, "infiniteunload");
537 }
538
539 // Tests closing the browser on a page with an unload listener registered where
540 // the unload handler has an infinite loop followed by an alert.
541 // If this flakes, use http://crbug.com/86469
542 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseInfiniteUnloadAlert) {
543   // Tests makes no sense in single-process mode since the renderer is hung.
544   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
545           switches::kSingleProcess))
546     return;
547
548   LoadUrlAndQuitBrowser(INFINITE_UNLOAD_ALERT_HTML, "infiniteunloadalert");
549 }
550
551 // Tests closing the browser with a beforeunload handler that hangs then
552 // pops up an alert.
553 // If this flakes, use http://crbug.com/78803 and http://crbug.com/86469.
554 IN_PROC_BROWSER_TEST_F(UnloadTest,
555                        DISABLED_BrowserCloseInfiniteBeforeUnloadAlert) {
556   // Tests makes no sense in single-process mode since the renderer is hung.
557   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
558           switches::kSingleProcess))
559     return;
560
561   LoadUrlAndQuitBrowser(INFINITE_BEFORE_UNLOAD_ALERT_HTML,
562                         "infinitebeforeunloadalert");
563 }
564
565 // Tests closing the browser on a page with an unload listener registered where
566 // the unload handler has an 2 second long loop followed by an alert.
567 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseTwoSecondUnloadAlert) {
568   LoadUrlAndQuitBrowser(TWO_SECOND_UNLOAD_ALERT_HTML, "twosecondunloadalert");
569 }
570
571 // Tests closing the browser with a beforeunload handler that takes
572 // two seconds to run then pops up an alert.
573 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseTwoSecondBeforeUnloadAlert) {
574   LoadUrlAndQuitBrowser(TWO_SECOND_BEFORE_UNLOAD_ALERT_HTML,
575                         "twosecondbeforeunloadalert");
576 }
577
578 // Tests that if there's a renderer process with two tabs, one of which has an
579 // unload handler, and the other doesn't, the tab that doesn't have an unload
580 // handler can be closed.
581 // If this flakes, see http://crbug.com/45162, http://crbug.com/45281 and
582 // http://crbug.com/86769.
583 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseTabWhenOtherTabHasListener) {
584   NavigateToDataURL(CLOSE_TAB_WHEN_OTHER_TAB_HAS_LISTENER, "only_one_unload");
585
586   // Simulate a click to force user_gesture to true; if we don't, the resulting
587   // popup will be constrained, which isn't what we want to test.
588
589   ui_test_utils::TabAddedWaiter tab_add(browser());
590   content::SimulateMouseClick(
591       browser()->tab_strip_model()->GetActiveWebContents(), 0,
592       blink::WebMouseEvent::Button::kLeft);
593   tab_add.Wait();
594   // Need to wait for the title, because the initial page (about:blank) can stop
595   // loading before the click handler calls document.write.
596   CheckTitle("popup", true);
597
598   content::WebContentsDestroyedWatcher destroyed_watcher(
599       browser()->tab_strip_model()->GetActiveWebContents());
600   chrome::CloseTab(browser());
601   destroyed_watcher.Wait();
602
603   CheckTitle("only_one_unload");
604 }
605
606 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserListForceCloseAfterNormalClose) {
607   NavigateToDataURL(BEFORE_UNLOAD_HTML, "beforeunload");
608
609   UnloadResults unload_results;
610   BrowserList::CloseAllBrowsersWithProfile(
611       browser()->profile(),
612       base::Bind(&UnloadResults::AddSuccess, base::Unretained(&unload_results)),
613       base::Bind(&UnloadResults::AddAbort, base::Unretained(&unload_results)),
614       false);
615   BrowserList::CloseAllBrowsersWithProfile(
616       browser()->profile(),
617       base::Bind(&UnloadResults::AddSuccess, base::Unretained(&unload_results)),
618       base::Bind(&UnloadResults::AddAbort, base::Unretained(&unload_results)),
619       true);
620   ui_test_utils::WaitForBrowserToClose();
621   EXPECT_EQ(1, unload_results.get_successes());
622   EXPECT_EQ(0, unload_results.get_aborts());
623 }
624
625 // Tests that a cross-site iframe runs its beforeunload handler when closing
626 // the browser.  See https://crbug.com/853021.
627 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseWithCrossSiteIframe) {
628   ASSERT_TRUE(embedded_test_server()->Start());
629
630   // Navigate to a page with an iframe.
631   GURL main_url(embedded_test_server()->GetURL("a.com", "/iframe.html"));
632   ui_test_utils::NavigateToURL(browser(), main_url);
633
634   // Navigate iframe cross-site.
635   GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
636   content::WebContents* web_contents =
637       browser()->tab_strip_model()->GetActiveWebContents();
638   EXPECT_TRUE(NavigateIframeToURL(web_contents, "test", frame_url));
639
640   // Install a dialog-showing beforeunload handler in the iframe.
641   content::RenderFrameHost* child =
642       ChildFrameAt(web_contents->GetMainFrame(), 0);
643   EXPECT_TRUE(
644       ExecuteScript(child, "window.onbeforeunload = () => { return 'x' };"));
645
646   // Close the browser and make sure the beforeunload dialog is shown and can
647   // be clicked.
648   PrepareForDialog(browser());
649   ManuallyCloseWindow();
650 }
651
652 // Tests that a same-site iframe runs its beforeunload handler when closing the
653 // browser.  See https://crbug.com/1010456.
654 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserCloseWithSameSiteIframe) {
655   ASSERT_TRUE(embedded_test_server()->Start());
656
657   // Navigate to a page with a same-site iframe.
658   GURL main_url(embedded_test_server()->GetURL("a.com", "/iframe.html"));
659   ui_test_utils::NavigateToURL(browser(), main_url);
660   content::WebContents* web_contents =
661       browser()->tab_strip_model()->GetActiveWebContents();
662   content::RenderFrameHost* child =
663       ChildFrameAt(web_contents->GetMainFrame(), 0);
664   EXPECT_EQ(child->GetSiteInstance(),
665             web_contents->GetMainFrame()->GetSiteInstance());
666
667   // Install a dialog-showing beforeunload handler in the iframe.
668   EXPECT_TRUE(
669       ExecuteScript(child, "window.onbeforeunload = () => { return 'x' };"));
670
671   // Close the browser and make sure the beforeunload dialog is shown and can
672   // be clicked.
673   PrepareForDialog(browser());
674   ManuallyCloseWindow();
675 }
676
677 // TODO(ojan): Add tests for unload/beforeunload that have multiple tabs
678 // and multiple windows.