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.
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"
36 using base::TimeDelta;
37 using content::BrowserThread;
39 const char NOLISTENERS_HTML[] =
40 "<html><head><title>nolisteners</title></head><body></body></html>";
42 const char UNLOAD_HTML[] =
43 "<html><head><title>unload</title></head><body>"
44 "<script>window.onunload=function(e){}</script></body></html>";
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>"
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>"
60 const char INFINITE_UNLOAD_HTML[] =
61 "<html><head><title>infiniteunload</title></head><body>"
62 "<script>window.onunload=function(e){while(true){}}</script>"
65 const char INFINITE_BEFORE_UNLOAD_HTML[] =
66 "<html><head><title>infinitebeforeunload</title></head><body>"
67 "<script>window.onbeforeunload=function(e){while(true){}}</script>"
70 const char INFINITE_UNLOAD_ALERT_HTML[] =
71 "<html><head><title>infiniteunloadalert</title></head><body>"
72 "<script>window.onunload=function(e){"
75 "}</script></body></html>";
77 const char INFINITE_BEFORE_UNLOAD_ALERT_HTML[] =
78 "<html><head><title>infinitebeforeunloadalert</title></head><body>"
79 "<script>window.onbeforeunload=function(e){"
82 "}</script></body></html>";
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){}"
90 "}</script></body></html>";
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){}"
98 "}</script></body></html>";
100 const char CLOSE_TAB_WHEN_OTHER_TAB_HAS_LISTENER[] =
101 "<html><head><title>only_one_unload</title></head>"
103 "function openPopup() {"
104 " var w = window.open('about:blank');"
105 " w.document.write('<html><head><title>popup</title></head></body>');"
108 "<body onclick='openPopup()' onbeforeunload='return;'>"
111 class UnloadResults {
113 UnloadResults() : successes_(0), aborts_(0) {}
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.";
121 int get_successes() { return successes_; }
122 int get_aborts() { return aborts_; }
129 class UnloadTest : public InProcessBrowserTest {
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") !=
136 command_line->AppendSwitch(embedder_support::kDisablePopupBlocking);
137 } else if (strstr(test_info->name(), "BrowserTerminateBeforeUnload") !=
139 #if defined(OS_POSIX)
140 DisableSIGTERMHandling();
145 void SetUpOnMainThread() override {
146 host_resolver()->AddRule("*", "127.0.0.1");
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;
154 actual = content::TitleWatcher(web_contents, expected).WaitAndGetTitle();
156 actual = web_contents->GetTitle();
157 EXPECT_EQ(expected, actual);
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);
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");
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");
187 void LoadUrlAndQuitBrowser(const char* html_content,
188 const char* expected_title) {
189 NavigateToDataURL(html_content, expected_title);
190 CloseBrowserSynchronously(browser());
193 // If |accept| is true, simulates user clicking OK, otherwise simulates
195 void ClickModalDialogButton(bool accept) {
196 javascript_dialogs::AppModalDialogController* dialog =
197 ui_test_utils::WaitForAppModalDialog();
199 dialog->view()->AcceptAppModalDialog();
201 dialog->view()->CancelAppModalDialog();
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));
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)),
219 ui_test_utils::WaitForBrowserToClose();
220 EXPECT_EQ(1, unload_results.get_successes());
221 EXPECT_EQ(0, unload_results.get_aborts());
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();
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.
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))
244 NavigateToDataURL(INFINITE_UNLOAD_HTML, "infiniteunload");
245 // Must navigate to a non-data URL to trigger cross-site codepath.
246 NavigateToNolistenersFileTwiceAsync();
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))
258 NavigateToDataURL(INFINITE_UNLOAD_HTML, "infiniteunload");
259 // Must navigate to a non-data URL to trigger cross-site codepath.
260 NavigateToNolistenersFileTwice();
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))
274 NavigateToDataURL(INFINITE_BEFORE_UNLOAD_HTML, "infinitebeforeunload");
275 // Must navigate to a non-data URL to trigger cross-site codepath.
276 NavigateToNolistenersFileTwiceAsync();
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))
289 NavigateToDataURL(INFINITE_BEFORE_UNLOAD_HTML, "infinitebeforeunload");
290 // Must navigate to a non-data URL to trigger cross-site codepath.
291 NavigateToNolistenersFileTwice();
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");
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");
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());
311 chrome::CloseWindow(browser());
312 ClickModalDialogButton(true);
313 ui_test_utils::WaitForBrowserToClose();
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());
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());
334 ManuallyCloseWindow();
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");
342 CloseBrowsersVerifyUnloadSuccess(false);
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());
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)),
357 ClickModalDialogButton(true);
358 ui_test_utils::WaitForBrowserToClose();
359 EXPECT_EQ(1, unload_results.get_successes());
360 EXPECT_EQ(0, unload_results.get_aborts());
363 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserListForceCloseNoUnloadListeners) {
364 NavigateToDataURL(NOLISTENERS_HTML, "nolisteners");
366 CloseBrowsersVerifyUnloadSuccess(true);
369 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserListForceCloseWithBeforeUnload) {
370 NavigateToDataURL(BEFORE_UNLOAD_HTML, "beforeunload");
372 CloseBrowsersVerifyUnloadSuccess(true);
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());
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)),
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());
398 EXPECT_EQ(0, unload_results.get_successes());
399 EXPECT_EQ(1, unload_results.get_aborts());
401 ManuallyCloseWindow();
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());
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)),
416 BrowserList::CloseAllBrowsersWithProfile(
417 browser()->profile(),
418 base::Bind(&UnloadResults::AddSuccess, base::Unretained(&unload_results)),
419 base::Bind(&UnloadResults::AddAbort, base::Unretained(&unload_results)),
421 ClickModalDialogButton(true);
422 ui_test_utils::WaitForBrowserToClose();
423 EXPECT_EQ(1, unload_results.get_successes());
424 EXPECT_EQ(0, unload_results.get_aborts());
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());
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)),
439 BrowserList::CloseAllBrowsersWithProfile(
440 browser()->profile(),
441 base::Bind(&UnloadResults::AddSuccess, base::Unretained(&unload_results)),
442 base::Bind(&UnloadResults::AddAbort, base::Unretained(&unload_results)),
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());
455 EXPECT_EQ(0, unload_results.get_successes());
456 EXPECT_EQ(1, unload_results.get_aborts());
458 ManuallyCloseWindow();
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());
468 UnloadResults unload_results;
469 BrowserList::CloseAllBrowsersWithProfile(browser()->profile(),
470 BrowserList::CloseCallback(),
471 BrowserList::CloseCallback(), false);
472 ClickModalDialogButton(true);
473 ui_test_utils::WaitForBrowserToClose();
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());
484 UnloadResults unload_results;
485 BrowserList::CloseAllBrowsersWithProfile(browser()->profile(),
486 BrowserList::CloseCallback(),
487 BrowserList::CloseCallback(), false);
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());
499 ManuallyCloseWindow();
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);
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());
518 ManuallyCloseWindow();
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");
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))
536 LoadUrlAndQuitBrowser(INFINITE_UNLOAD_HTML, "infiniteunload");
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))
548 LoadUrlAndQuitBrowser(INFINITE_UNLOAD_ALERT_HTML, "infiniteunloadalert");
551 // Tests closing the browser with a beforeunload handler that hangs then
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))
561 LoadUrlAndQuitBrowser(INFINITE_BEFORE_UNLOAD_ALERT_HTML,
562 "infinitebeforeunloadalert");
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");
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");
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");
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.
589 ui_test_utils::TabAddedWaiter tab_add(browser());
590 content::SimulateMouseClick(
591 browser()->tab_strip_model()->GetActiveWebContents(), 0,
592 blink::WebMouseEvent::Button::kLeft);
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);
598 content::WebContentsDestroyedWatcher destroyed_watcher(
599 browser()->tab_strip_model()->GetActiveWebContents());
600 chrome::CloseTab(browser());
601 destroyed_watcher.Wait();
603 CheckTitle("only_one_unload");
606 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserListForceCloseAfterNormalClose) {
607 NavigateToDataURL(BEFORE_UNLOAD_HTML, "beforeunload");
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)),
615 BrowserList::CloseAllBrowsersWithProfile(
616 browser()->profile(),
617 base::Bind(&UnloadResults::AddSuccess, base::Unretained(&unload_results)),
618 base::Bind(&UnloadResults::AddAbort, base::Unretained(&unload_results)),
620 ui_test_utils::WaitForBrowserToClose();
621 EXPECT_EQ(1, unload_results.get_successes());
622 EXPECT_EQ(0, unload_results.get_aborts());
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());
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);
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));
640 // Install a dialog-showing beforeunload handler in the iframe.
641 content::RenderFrameHost* child =
642 ChildFrameAt(web_contents->GetMainFrame(), 0);
644 ExecuteScript(child, "window.onbeforeunload = () => { return 'x' };"));
646 // Close the browser and make sure the beforeunload dialog is shown and can
648 PrepareForDialog(browser());
649 ManuallyCloseWindow();
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());
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());
667 // Install a dialog-showing beforeunload handler in the iframe.
669 ExecuteScript(child, "window.onbeforeunload = () => { return 'x' };"));
671 // Close the browser and make sure the beforeunload dialog is shown and can
673 PrepareForDialog(browser());
674 ManuallyCloseWindow();
677 // TODO(ojan): Add tests for unload/beforeunload that have multiple tabs
678 // and multiple windows.