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