1 // Copyright 2018 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 #include "chrome/browser/resource_coordinator/discard_before_unload_helper.h"
6
7 #include "base/bind.h"
8 #include "base/run_loop.h"
9 #include "base/test/bind.h"
10 #include "chrome/browser/ui/browser.h"
11 #include "chrome/test/base/in_process_browser_test.h"
12 #include "chrome/test/base/ui_test_utils.h"
13 #include "components/javascript_dialogs/app_modal_dialog_controller.h"
14 #include "components/javascript_dialogs/app_modal_dialog_view.h"
15 #include "content/public/browser/notification_service.h"
16 #include "content/public/browser/notification_types.h"
17 #include "content/public/test/browser_test.h"
18 #include "content/public/test/browser_test_utils.h"
19 #include "content/public/test/test_utils.h"
20 #include "net/dns/mock_host_resolver.h"
21 #include "url/gurl.h"
22
23 namespace resource_coordinator {
24
25 namespace {
26
27 class HasBeforeUnloadHandlerTest : public InProcessBrowserTest {
28 protected:
SetUpOnMainThread()29 void SetUpOnMainThread() override {
30 InProcessBrowserTest::SetUpOnMainThread();
31 host_resolver()->AddRule("*", "127.0.0.1");
32 ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
33 embedded_test_server()->StartAcceptingConnections();
34 }
35
TestDiscardBeforeUnloadHelper(const char * url,bool has_beforeunload_helper)36 void TestDiscardBeforeUnloadHelper(const char* url,
37 bool has_beforeunload_helper) {
38 GURL gurl(embedded_test_server()->GetURL("a.com", url));
39 ui_test_utils::NavigateToURL(browser(), gurl);
40 auto* wc = browser()->tab_strip_model()->GetActiveWebContents();
41 content::PrepContentsForBeforeUnloadTest(wc);
42
43 base::RunLoop run_loop;
44 bool callback_invoked = false;
45 bool response = false;
46 HasBeforeUnloadHandlerCallback callback = base::BindLambdaForTesting(
47 [&run_loop, &callback_invoked, &response](bool response_arg) {
48 run_loop.Quit();
49 callback_invoked = true;
50 response = response_arg;
51 });
52
53 HasBeforeUnloadHandler(wc, std::move(callback));
54
55 // The callback should not be invoked synchronously. In a world where
56 // NeedToFireBeforeUnloadOrUnloadEvents works properly this expectation
57 // changes.
58 ASSERT_FALSE(callback_invoked);
59
60 // Run the loop until we process the callback.
61 run_loop.Run();
62
63 EXPECT_TRUE(callback_invoked);
64 EXPECT_EQ(has_beforeunload_helper, response);
65
66 // If we didn't expect to proceed, then that means there's an unload
67 // handler. Which means that when we try to exit the browser a dialog will
68 // be shown. Wait for it, and accept it to allow the browser to close and
69 // the test to complete.
70 browser()->tab_strip_model()->CloseAllTabs();
71 if (has_beforeunload_helper) {
72 javascript_dialogs::AppModalDialogController* alert =
73 ui_test_utils::WaitForAppModalDialog();
74 ASSERT_TRUE(alert);
75 EXPECT_TRUE(alert->is_before_unload_dialog());
76 alert->view()->AcceptAppModalDialog();
77 }
78 }
79 };
80
81 } // namespace
82
83 // TODO(https://crbug.com/889304): Re-enable this test.
IN_PROC_BROWSER_TEST_F(HasBeforeUnloadHandlerTest,DISABLED_NonEmptyBeforeUnloadDetected)84 IN_PROC_BROWSER_TEST_F(HasBeforeUnloadHandlerTest,
85 DISABLED_NonEmptyBeforeUnloadDetected) {
86 TestDiscardBeforeUnloadHelper("/beforeunload.html",
87 true /* has_beforeunload_helper */);
88 }
89
90 // TODO(https://crbug.com/902355): Re-enable this test.
IN_PROC_BROWSER_TEST_F(HasBeforeUnloadHandlerTest,DISABLED_EmptyBeforeUnloadDetected)91 IN_PROC_BROWSER_TEST_F(HasBeforeUnloadHandlerTest,
92 DISABLED_EmptyBeforeUnloadDetected) {
93 TestDiscardBeforeUnloadHelper("/emptybeforeunload.html",
94 false /* has_beforeunload_helper */);
95 }
96
IN_PROC_BROWSER_TEST_F(HasBeforeUnloadHandlerTest,NoBeforeUnloadDetected)97 IN_PROC_BROWSER_TEST_F(HasBeforeUnloadHandlerTest, NoBeforeUnloadDetected) {
98 TestDiscardBeforeUnloadHelper("/empty.html",
99 false /* has_beforeunload_helper */);
100 }
101
102 } // namespace resource_coordinator
103