1 // Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4
5 #include "include/base/cef_callback.h"
6 #include "include/test/cef_test_helpers.h"
7 #include "include/wrapper/cef_closure_task.h"
8 #include "tests/ceftests/routing_test_handler.h"
9 #include "tests/gtest/include/gtest/gtest.h"
10
11 namespace {
12
13 const char kLifeSpanUrl[] = "http://tests-life-span/test.html";
14 const char kUnloadDialogText[] = "Are you sure?";
15 const char kUnloadMsg[] = "LifeSpanTestHandler.Unload";
16
17 // Browser side.
18 class LifeSpanTestHandler : public RoutingTestHandler {
19 public:
20 struct Settings {
Settings__anonbd5efbf60111::LifeSpanTestHandler::Settings21 Settings()
22 : force_close(false),
23 add_onunload_handler(false),
24 allow_do_close(true),
25 accept_before_unload_dialog(true) {}
26
27 bool force_close;
28 bool add_onunload_handler;
29 bool allow_do_close;
30 bool accept_before_unload_dialog;
31 };
32
LifeSpanTestHandler(const Settings & settings)33 explicit LifeSpanTestHandler(const Settings& settings)
34 : settings_(settings), executing_delay_close_(false) {
35 // By default no LifeSpan tests call DestroyTest().
36 SetDestroyTestExpected(false);
37 }
38
RunTest()39 void RunTest() override {
40 // Add the resources that we will navigate to/from.
41 std::string page = "<html><script>";
42
43 page += "window.onunload = function() { window.testQuery({request:'" +
44 std::string(kUnloadMsg) + "'}); };";
45
46 if (settings_.add_onunload_handler) {
47 page += "window.onbeforeunload = function() { return '" +
48 std::string(kUnloadDialogText) + "'; };";
49 }
50
51 page += "</script><body>Page</body></html>";
52 AddResource(kLifeSpanUrl, page, "text/html");
53
54 // Create the browser.
55 CreateBrowser(kLifeSpanUrl);
56
57 // Intentionally don't call SetTestTimeout() for these tests.
58 }
59
OnAfterCreated(CefRefPtr<CefBrowser> browser)60 void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
61 got_after_created_.yes();
62 RoutingTestHandler::OnAfterCreated(browser);
63 }
64
DoClose(CefRefPtr<CefBrowser> browser)65 bool DoClose(CefRefPtr<CefBrowser> browser) override {
66 if (executing_delay_close_)
67 return false;
68
69 EXPECT_TRUE(browser->IsSame(GetBrowser()));
70
71 got_do_close_.yes();
72
73 if (!settings_.allow_do_close) {
74 // The close will be canceled.
75 ScheduleDelayClose();
76 }
77
78 return !settings_.allow_do_close;
79 }
80
OnBeforeClose(CefRefPtr<CefBrowser> browser)81 void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
82 if (!executing_delay_close_) {
83 got_before_close_.yes();
84 EXPECT_TRUE(browser->IsSame(GetBrowser()));
85 }
86
87 RoutingTestHandler::OnBeforeClose(browser);
88 }
89
OnBeforeUnloadDialog(CefRefPtr<CefBrowser> browser,const CefString & message_text,bool is_reload,CefRefPtr<CefJSDialogCallback> callback)90 bool OnBeforeUnloadDialog(CefRefPtr<CefBrowser> browser,
91 const CefString& message_text,
92 bool is_reload,
93 CefRefPtr<CefJSDialogCallback> callback) override {
94 if (executing_delay_close_) {
95 callback->Continue(true, CefString());
96 return true;
97 }
98
99 EXPECT_TRUE(browser->IsSame(GetBrowser()));
100
101 // The message is no longer configurable via JavaScript.
102 // See http://crbug.com/587940.
103 EXPECT_STREQ("Is it OK to leave/reload this page?",
104 message_text.ToString().c_str());
105
106 EXPECT_FALSE(is_reload);
107 EXPECT_TRUE(callback.get());
108
109 if (!settings_.accept_before_unload_dialog) {
110 // The close will be canceled.
111 ScheduleDelayClose();
112 }
113
114 got_before_unload_dialog_.yes();
115 callback->Continue(settings_.accept_before_unload_dialog, CefString());
116 return true;
117 }
118
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)119 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
120 CefRefPtr<CefFrame> frame,
121 int httpStatusCode) override {
122 got_load_end_.yes();
123 EXPECT_TRUE(browser->IsSame(GetBrowser()));
124
125 if (settings_.add_onunload_handler) {
126 // Send the page a user gesture to enable firing of the onbefureunload
127 // handler. See https://crbug.com/707007.
128 CefExecuteJavaScriptWithUserGestureForTests(frame, CefString());
129 }
130
131 // Attempt to close the browser.
132 CloseBrowser(browser, settings_.force_close);
133 }
134
OnQuery(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int64 query_id,const CefString & request,bool persistent,CefRefPtr<Callback> callback)135 bool OnQuery(CefRefPtr<CefBrowser> browser,
136 CefRefPtr<CefFrame> frame,
137 int64 query_id,
138 const CefString& request,
139 bool persistent,
140 CefRefPtr<Callback> callback) override {
141 if (request.ToString() == kUnloadMsg) {
142 if (!executing_delay_close_)
143 got_unload_message_.yes();
144 }
145 callback->Success("");
146 return true;
147 }
148
149 TrackCallback got_after_created_;
150 TrackCallback got_do_close_;
151 TrackCallback got_before_close_;
152 TrackCallback got_before_unload_dialog_;
153 TrackCallback got_unload_message_;
154 TrackCallback got_load_end_;
155 TrackCallback got_delay_close_;
156
157 private:
158 // Wait a bit to make sure no additional events are received and then close
159 // the window.
ScheduleDelayClose()160 void ScheduleDelayClose() {
161 // This test will call DestroyTest().
162 SetDestroyTestExpected(true);
163
164 CefPostDelayedTask(
165 TID_UI, base::BindOnce(&LifeSpanTestHandler::DelayClose, this), 100);
166 }
167
DelayClose()168 void DelayClose() {
169 got_delay_close_.yes();
170 executing_delay_close_ = true;
171 DestroyTest();
172 }
173
174 Settings settings_;
175
176 // Forces the window to close (bypasses test conditions).
177 bool executing_delay_close_;
178
179 IMPLEMENT_REFCOUNTING(LifeSpanTestHandler);
180 };
181
182 } // namespace
183
TEST(LifeSpanTest,DoCloseAllow)184 TEST(LifeSpanTest, DoCloseAllow) {
185 LifeSpanTestHandler::Settings settings;
186 settings.allow_do_close = true;
187 CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
188 handler->ExecuteTest();
189
190 EXPECT_TRUE(handler->got_after_created_);
191 EXPECT_TRUE(handler->got_do_close_);
192 EXPECT_TRUE(handler->got_before_close_);
193 EXPECT_FALSE(handler->got_before_unload_dialog_);
194 EXPECT_TRUE(handler->got_unload_message_);
195 EXPECT_TRUE(handler->got_load_end_);
196 EXPECT_FALSE(handler->got_delay_close_);
197
198 ReleaseAndWaitForDestructor(handler);
199 }
200
TEST(LifeSpanTest,DoCloseAllowForce)201 TEST(LifeSpanTest, DoCloseAllowForce) {
202 LifeSpanTestHandler::Settings settings;
203 settings.allow_do_close = true;
204 settings.force_close = true;
205 CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
206 handler->ExecuteTest();
207
208 EXPECT_TRUE(handler->got_after_created_);
209 EXPECT_TRUE(handler->got_do_close_);
210 EXPECT_TRUE(handler->got_before_close_);
211 EXPECT_FALSE(handler->got_before_unload_dialog_);
212 EXPECT_TRUE(handler->got_unload_message_);
213 EXPECT_TRUE(handler->got_load_end_);
214 EXPECT_FALSE(handler->got_delay_close_);
215
216 ReleaseAndWaitForDestructor(handler);
217 }
218
TEST(LifeSpanTest,DoCloseDisallow)219 TEST(LifeSpanTest, DoCloseDisallow) {
220 LifeSpanTestHandler::Settings settings;
221 settings.allow_do_close = false;
222 CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
223 handler->ExecuteTest();
224
225 EXPECT_TRUE(handler->got_after_created_);
226 EXPECT_TRUE(handler->got_do_close_);
227 EXPECT_FALSE(handler->got_before_close_);
228 EXPECT_FALSE(handler->got_before_unload_dialog_);
229 EXPECT_TRUE(handler->got_unload_message_);
230 EXPECT_TRUE(handler->got_load_end_);
231 EXPECT_TRUE(handler->got_delay_close_);
232
233 ReleaseAndWaitForDestructor(handler);
234 }
235
TEST(LifeSpanTest,DoCloseDisallowForce)236 TEST(LifeSpanTest, DoCloseDisallowForce) {
237 LifeSpanTestHandler::Settings settings;
238 settings.allow_do_close = false;
239 settings.force_close = true;
240 CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
241 handler->ExecuteTest();
242
243 EXPECT_TRUE(handler->got_after_created_);
244 EXPECT_TRUE(handler->got_do_close_);
245 EXPECT_FALSE(handler->got_before_close_);
246 EXPECT_FALSE(handler->got_before_unload_dialog_);
247 EXPECT_TRUE(handler->got_unload_message_);
248 EXPECT_TRUE(handler->got_load_end_);
249 EXPECT_TRUE(handler->got_delay_close_);
250
251 ReleaseAndWaitForDestructor(handler);
252 }
253
TEST(LifeSpanTest,DoCloseDisallowWithOnUnloadAllow)254 TEST(LifeSpanTest, DoCloseDisallowWithOnUnloadAllow) {
255 LifeSpanTestHandler::Settings settings;
256 settings.allow_do_close = false;
257 settings.add_onunload_handler = true;
258 settings.accept_before_unload_dialog = true;
259 CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
260 handler->ExecuteTest();
261
262 EXPECT_TRUE(handler->got_after_created_);
263 EXPECT_TRUE(handler->got_do_close_);
264 EXPECT_FALSE(handler->got_before_close_);
265 EXPECT_TRUE(handler->got_before_unload_dialog_);
266 EXPECT_TRUE(handler->got_unload_message_);
267 EXPECT_TRUE(handler->got_load_end_);
268 EXPECT_TRUE(handler->got_delay_close_);
269
270 ReleaseAndWaitForDestructor(handler);
271 }
272
TEST(LifeSpanTest,DoCloseAllowWithOnUnloadForce)273 TEST(LifeSpanTest, DoCloseAllowWithOnUnloadForce) {
274 LifeSpanTestHandler::Settings settings;
275 settings.allow_do_close = true;
276 settings.add_onunload_handler = true;
277 settings.force_close = true;
278 CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
279 handler->ExecuteTest();
280
281 EXPECT_TRUE(handler->got_after_created_);
282 EXPECT_TRUE(handler->got_do_close_);
283 EXPECT_TRUE(handler->got_before_close_);
284 EXPECT_FALSE(handler->got_before_unload_dialog_);
285 EXPECT_TRUE(handler->got_unload_message_);
286 EXPECT_TRUE(handler->got_load_end_);
287 EXPECT_FALSE(handler->got_delay_close_);
288
289 ReleaseAndWaitForDestructor(handler);
290 }
291
TEST(LifeSpanTest,DoCloseDisallowWithOnUnloadForce)292 TEST(LifeSpanTest, DoCloseDisallowWithOnUnloadForce) {
293 LifeSpanTestHandler::Settings settings;
294 settings.allow_do_close = false;
295 settings.add_onunload_handler = true;
296 settings.force_close = true;
297 CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
298 handler->ExecuteTest();
299
300 EXPECT_TRUE(handler->got_after_created_);
301 EXPECT_TRUE(handler->got_do_close_);
302 EXPECT_FALSE(handler->got_before_close_);
303 EXPECT_FALSE(handler->got_before_unload_dialog_);
304 EXPECT_TRUE(handler->got_unload_message_);
305 EXPECT_TRUE(handler->got_load_end_);
306 EXPECT_TRUE(handler->got_delay_close_);
307
308 ReleaseAndWaitForDestructor(handler);
309 }
310
TEST(LifeSpanTest,OnUnloadAllow)311 TEST(LifeSpanTest, OnUnloadAllow) {
312 LifeSpanTestHandler::Settings settings;
313 settings.add_onunload_handler = true;
314 settings.accept_before_unload_dialog = true;
315 CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
316 handler->ExecuteTest();
317
318 EXPECT_TRUE(handler->got_after_created_);
319 EXPECT_TRUE(handler->got_do_close_);
320 EXPECT_TRUE(handler->got_before_close_);
321 EXPECT_TRUE(handler->got_before_unload_dialog_);
322 EXPECT_TRUE(handler->got_unload_message_);
323 EXPECT_TRUE(handler->got_load_end_);
324 EXPECT_FALSE(handler->got_delay_close_);
325
326 ReleaseAndWaitForDestructor(handler);
327 }
328
TEST(LifeSpanTest,OnUnloadDisallow)329 TEST(LifeSpanTest, OnUnloadDisallow) {
330 LifeSpanTestHandler::Settings settings;
331 settings.add_onunload_handler = true;
332 settings.accept_before_unload_dialog = false;
333 CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
334 handler->ExecuteTest();
335
336 EXPECT_TRUE(handler->got_after_created_);
337 EXPECT_FALSE(handler->got_do_close_);
338 EXPECT_FALSE(handler->got_before_close_);
339 EXPECT_TRUE(handler->got_before_unload_dialog_);
340 EXPECT_FALSE(handler->got_unload_message_);
341 EXPECT_TRUE(handler->got_load_end_);
342 EXPECT_TRUE(handler->got_delay_close_);
343
344 ReleaseAndWaitForDestructor(handler);
345 }
346