1 // Copyright (c) 2012 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_bind.h"
6 #include "include/test/cef_test_helpers.h"
7 #include "include/wrapper/cef_closure_task.h"
8 #include "tests/ceftests/test_handler.h"
9 #include "tests/gtest/include/gtest/gtest.h"
10
11 namespace {
12
13 const char* kStartUrl = "http://tests/JSDialogTestHandler.Start";
14 const char* kEndUrl = "http://tests/JSDialogTestHandler.End?r=";
15
16 class JSDialogTestHandler : public TestHandler {
17 public:
18 enum TestType {
19 TYPE_ALERT,
20 TYPE_CONFIRM,
21 TYPE_PROMPT,
22 TYPE_ONBEFOREUNLOAD,
23 };
24 enum TestMode {
25 MODE_SUPPRESS,
26 MODE_RUN_IMMEDIATE,
27 MODE_RUN_DELAYED,
28 };
29
JSDialogTestHandler(TestType type,TestMode mode,bool success,const std::string & user_input,const std::string & result)30 JSDialogTestHandler(TestType type,
31 TestMode mode,
32 bool success,
33 const std::string& user_input,
34 const std::string& result)
35 : type_(type),
36 mode_(mode),
37 success_(success),
38 user_input_(user_input),
39 result_(result) {}
40
RunTest()41 void RunTest() override {
42 std::string content = "<html><head><body>START<script>";
43 if (type_ == TYPE_ALERT) {
44 content +=
45 "alert('My alert message'); "
46 "document.location='" +
47 std::string(kEndUrl) + "';";
48 } else if (type_ == TYPE_CONFIRM) {
49 content +=
50 "var r = confirm('My confirm message')?'ok':'cancel'; "
51 "document.location='" +
52 std::string(kEndUrl) + "'+r;";
53 } else if (type_ == TYPE_PROMPT) {
54 content +=
55 "var r = prompt('My prompt message','my default'); "
56 "document.location='" +
57 std::string(kEndUrl) + "'+r;";
58 } else if (type_ == TYPE_ONBEFOREUNLOAD) {
59 content +=
60 "window.onbeforeunload=function() {"
61 " return 'My unload message'; };";
62 }
63 content += "</script></body></html>";
64
65 AddResource(kStartUrl, content, "text/html");
66 AddResource(kEndUrl, "<html><body>END</body></html>", "text/html");
67
68 // Create the browser
69 CreateBrowser(kStartUrl);
70
71 // Time out the test after a reasonable period of time.
72 SetTestTimeout();
73 }
74
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)75 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
76 CefRefPtr<CefFrame> frame,
77 int httpStatusCode) override {
78 if (!frame->IsMain())
79 return;
80
81 std::string url = frame->GetURL();
82 if (url.find(kEndUrl) == 0) {
83 got_onloadend_.yes();
84
85 std::string result = url.substr(strlen(kEndUrl));
86 EXPECT_STREQ(result_.c_str(), result.c_str());
87
88 DestroyTest();
89 } else if (type_ == TYPE_ONBEFOREUNLOAD) {
90 // Send the page a user gesture to enable firing of the onbefureunload
91 // handler. See https://crbug.com/707007.
92 CefExecuteJavaScriptWithUserGestureForTests(frame, CefString());
93
94 // Trigger the onunload handler.
95 frame->LoadURL(kEndUrl);
96 }
97 }
98
Continue(CefRefPtr<CefJSDialogCallback> callback)99 void Continue(CefRefPtr<CefJSDialogCallback> callback) {
100 callback->Continue(success_, user_input_);
101 }
102
OnJSDialog(CefRefPtr<CefBrowser> browser,const CefString & origin_url,JSDialogType dialog_type,const CefString & message_text,const CefString & default_prompt_text,CefRefPtr<CefJSDialogCallback> callback,bool & suppress_message)103 bool OnJSDialog(CefRefPtr<CefBrowser> browser,
104 const CefString& origin_url,
105 JSDialogType dialog_type,
106 const CefString& message_text,
107 const CefString& default_prompt_text,
108 CefRefPtr<CefJSDialogCallback> callback,
109 bool& suppress_message) override {
110 got_onjsdialog_.yes();
111
112 EXPECT_STREQ(kStartUrl, origin_url.ToString().c_str());
113
114 if (type_ == TYPE_ALERT) {
115 EXPECT_EQ(JSDIALOGTYPE_ALERT, dialog_type);
116 EXPECT_STREQ("My alert message", message_text.ToString().c_str());
117 EXPECT_TRUE(default_prompt_text.empty());
118 } else if (type_ == TYPE_CONFIRM) {
119 EXPECT_EQ(JSDIALOGTYPE_CONFIRM, dialog_type);
120 EXPECT_STREQ("My confirm message", message_text.ToString().c_str());
121 EXPECT_TRUE(default_prompt_text.empty());
122 } else if (type_ == TYPE_PROMPT) {
123 EXPECT_EQ(JSDIALOGTYPE_PROMPT, dialog_type);
124 EXPECT_STREQ("My prompt message", message_text.ToString().c_str());
125 EXPECT_STREQ("my default", default_prompt_text.ToString().c_str());
126 }
127
128 EXPECT_FALSE(suppress_message);
129
130 if (mode_ == MODE_SUPPRESS) {
131 // Suppress the dialog.
132 suppress_message = true;
133 return false;
134 } else if (mode_ == MODE_RUN_IMMEDIATE) {
135 // Continue immediately.
136 callback->Continue(success_, user_input_);
137 } else if (mode_ == MODE_RUN_DELAYED) {
138 // Continue asynchronously.
139 CefPostTask(TID_UI,
140 base::Bind(&JSDialogTestHandler::Continue, this, callback));
141 }
142
143 return true;
144 }
145
OnBeforeUnloadDialog(CefRefPtr<CefBrowser> browser,const CefString & message_text,bool is_reload,CefRefPtr<CefJSDialogCallback> callback)146 bool OnBeforeUnloadDialog(CefRefPtr<CefBrowser> browser,
147 const CefString& message_text,
148 bool is_reload,
149 CefRefPtr<CefJSDialogCallback> callback) override {
150 got_onbeforeunloaddialog_.yes();
151
152 if (type_ == TYPE_ONBEFOREUNLOAD) {
153 // The message is no longer configurable via JavaScript.
154 // See http://crbug.com/587940.
155 EXPECT_STREQ("Is it OK to leave/reload this page?",
156 message_text.ToString().c_str());
157 EXPECT_FALSE(is_reload);
158 }
159
160 if (mode_ == MODE_RUN_IMMEDIATE) {
161 // Continue immediately.
162 callback->Continue(success_, user_input_);
163 } else if (mode_ == MODE_RUN_DELAYED) {
164 // Continue asynchronously.
165 CefPostTask(TID_UI,
166 base::Bind(&JSDialogTestHandler::Continue, this, callback));
167 }
168
169 return true;
170 }
171
OnResetDialogState(CefRefPtr<CefBrowser> browser)172 void OnResetDialogState(CefRefPtr<CefBrowser> browser) override {
173 got_onresetdialogstate_.yes();
174 }
175
176 TestType type_;
177 TestMode mode_;
178 bool success_;
179 std::string user_input_;
180 std::string result_;
181
182 TrackCallback got_onjsdialog_;
183 TrackCallback got_onbeforeunloaddialog_;
184 TrackCallback got_onresetdialogstate_;
185 TrackCallback got_onloadend_;
186
187 IMPLEMENT_REFCOUNTING(JSDialogTestHandler);
188 };
189
190 } // namespace
191
192 // Alert dialog with suppression.
TEST(JSDialogTest,AlertSuppress)193 TEST(JSDialogTest, AlertSuppress) {
194 CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
195 JSDialogTestHandler::TYPE_ALERT, JSDialogTestHandler::MODE_SUPPRESS,
196 true, // success
197 "", // user_input
198 ""); // result
199 handler->ExecuteTest();
200
201 EXPECT_TRUE(handler->got_onjsdialog_);
202 EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
203 EXPECT_TRUE(handler->got_onresetdialogstate_);
204 EXPECT_TRUE(handler->got_onloadend_);
205
206 ReleaseAndWaitForDestructor(handler);
207 }
208
209 // Alert dialog with immediate callback.
TEST(JSDialogTest,AlertRunImmediate)210 TEST(JSDialogTest, AlertRunImmediate) {
211 CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
212 JSDialogTestHandler::TYPE_ALERT, JSDialogTestHandler::MODE_RUN_IMMEDIATE,
213 true, // success
214 "", // user_input
215 ""); // result
216 handler->ExecuteTest();
217
218 EXPECT_TRUE(handler->got_onjsdialog_);
219 EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
220 EXPECT_TRUE(handler->got_onresetdialogstate_);
221 EXPECT_TRUE(handler->got_onloadend_);
222
223 ReleaseAndWaitForDestructor(handler);
224 }
225
226 // Alert dialog with delayed callback.
TEST(JSDialogTest,AlertRunDelayed)227 TEST(JSDialogTest, AlertRunDelayed) {
228 CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
229 JSDialogTestHandler::TYPE_ALERT, JSDialogTestHandler::MODE_RUN_DELAYED,
230 true, // success
231 "", // user_input
232 ""); // result
233 handler->ExecuteTest();
234
235 EXPECT_TRUE(handler->got_onjsdialog_);
236 EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
237 EXPECT_TRUE(handler->got_onresetdialogstate_);
238 EXPECT_TRUE(handler->got_onloadend_);
239
240 ReleaseAndWaitForDestructor(handler);
241 }
242
243 // Confirm dialog with suppression.
TEST(JSDialogTest,ConfirmSuppress)244 TEST(JSDialogTest, ConfirmSuppress) {
245 CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
246 JSDialogTestHandler::TYPE_CONFIRM, JSDialogTestHandler::MODE_SUPPRESS,
247 true, // success
248 "", // user_input
249 "cancel"); // result
250 handler->ExecuteTest();
251
252 EXPECT_TRUE(handler->got_onjsdialog_);
253 EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
254 EXPECT_TRUE(handler->got_onresetdialogstate_);
255 EXPECT_TRUE(handler->got_onloadend_);
256
257 ReleaseAndWaitForDestructor(handler);
258 }
259
260 // Confirm dialog run immediately return OK.
TEST(JSDialogTest,ConfirmRunImmediateOk)261 TEST(JSDialogTest, ConfirmRunImmediateOk) {
262 CefRefPtr<JSDialogTestHandler> handler =
263 new JSDialogTestHandler(JSDialogTestHandler::TYPE_CONFIRM,
264 JSDialogTestHandler::MODE_RUN_IMMEDIATE,
265 true, // success
266 "", // user_input
267 "ok"); // result
268 handler->ExecuteTest();
269
270 EXPECT_TRUE(handler->got_onjsdialog_);
271 EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
272 EXPECT_TRUE(handler->got_onresetdialogstate_);
273 EXPECT_TRUE(handler->got_onloadend_);
274
275 ReleaseAndWaitForDestructor(handler);
276 }
277
278 // Confirm dialog run immediately return Cancel.
TEST(JSDialogTest,ConfirmRunImmediateCancel)279 TEST(JSDialogTest, ConfirmRunImmediateCancel) {
280 CefRefPtr<JSDialogTestHandler> handler =
281 new JSDialogTestHandler(JSDialogTestHandler::TYPE_CONFIRM,
282 JSDialogTestHandler::MODE_RUN_IMMEDIATE,
283 false, // success
284 "", // user_input
285 "cancel"); // result
286 handler->ExecuteTest();
287
288 EXPECT_TRUE(handler->got_onjsdialog_);
289 EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
290 EXPECT_TRUE(handler->got_onresetdialogstate_);
291 EXPECT_TRUE(handler->got_onloadend_);
292
293 ReleaseAndWaitForDestructor(handler);
294 }
295
296 // Confirm dialog run delayed return OK.
TEST(JSDialogTest,ConfirmRunDelayedOk)297 TEST(JSDialogTest, ConfirmRunDelayedOk) {
298 CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
299 JSDialogTestHandler::TYPE_CONFIRM, JSDialogTestHandler::MODE_RUN_DELAYED,
300 true, // success
301 "", // user_input
302 "ok"); // result
303 handler->ExecuteTest();
304
305 EXPECT_TRUE(handler->got_onjsdialog_);
306 EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
307 EXPECT_TRUE(handler->got_onresetdialogstate_);
308 EXPECT_TRUE(handler->got_onloadend_);
309
310 ReleaseAndWaitForDestructor(handler);
311 }
312
313 // Confirm dialog run delayed return Cancel.
TEST(JSDialogTest,ConfirmRunDelayedCancel)314 TEST(JSDialogTest, ConfirmRunDelayedCancel) {
315 CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
316 JSDialogTestHandler::TYPE_CONFIRM, JSDialogTestHandler::MODE_RUN_DELAYED,
317 false, // success
318 "", // user_input
319 "cancel"); // result
320 handler->ExecuteTest();
321
322 EXPECT_TRUE(handler->got_onjsdialog_);
323 EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
324 EXPECT_TRUE(handler->got_onresetdialogstate_);
325 EXPECT_TRUE(handler->got_onloadend_);
326
327 ReleaseAndWaitForDestructor(handler);
328 }
329
330 // Prompt dialog with suppression.
TEST(JSDialogTest,PromptSuppress)331 TEST(JSDialogTest, PromptSuppress) {
332 CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
333 JSDialogTestHandler::TYPE_PROMPT, JSDialogTestHandler::MODE_SUPPRESS,
334 true, // success
335 "some_value", // user_input
336 "null"); // result
337 handler->ExecuteTest();
338
339 EXPECT_TRUE(handler->got_onjsdialog_);
340 EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
341 EXPECT_TRUE(handler->got_onresetdialogstate_);
342 EXPECT_TRUE(handler->got_onloadend_);
343
344 ReleaseAndWaitForDestructor(handler);
345 }
346
347 // Prompt dialog run immediately return OK.
TEST(JSDialogTest,PromptRunImmediateOk)348 TEST(JSDialogTest, PromptRunImmediateOk) {
349 CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
350 JSDialogTestHandler::TYPE_PROMPT, JSDialogTestHandler::MODE_RUN_IMMEDIATE,
351 true, // success
352 "some_value", // user_input
353 "some_value"); // result
354 handler->ExecuteTest();
355
356 EXPECT_TRUE(handler->got_onjsdialog_);
357 EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
358 EXPECT_TRUE(handler->got_onresetdialogstate_);
359 EXPECT_TRUE(handler->got_onloadend_);
360
361 ReleaseAndWaitForDestructor(handler);
362 }
363
364 // Prompt dialog run immediately return Cancel.
TEST(JSDialogTest,PromptRunImmediateCancel)365 TEST(JSDialogTest, PromptRunImmediateCancel) {
366 CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
367 JSDialogTestHandler::TYPE_PROMPT, JSDialogTestHandler::MODE_RUN_IMMEDIATE,
368 false, // success
369 "some_value", // user_input
370 "null"); // result
371 handler->ExecuteTest();
372
373 EXPECT_TRUE(handler->got_onjsdialog_);
374 EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
375 EXPECT_TRUE(handler->got_onresetdialogstate_);
376 EXPECT_TRUE(handler->got_onloadend_);
377
378 ReleaseAndWaitForDestructor(handler);
379 }
380
381 // Prompt dialog run delayed return OK.
TEST(JSDialogTest,PromptRunDelayedOk)382 TEST(JSDialogTest, PromptRunDelayedOk) {
383 CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
384 JSDialogTestHandler::TYPE_PROMPT, JSDialogTestHandler::MODE_RUN_DELAYED,
385 true, // success
386 "some_value", // user_input
387 "some_value"); // result
388 handler->ExecuteTest();
389
390 EXPECT_TRUE(handler->got_onjsdialog_);
391 EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
392 EXPECT_TRUE(handler->got_onresetdialogstate_);
393 EXPECT_TRUE(handler->got_onloadend_);
394
395 ReleaseAndWaitForDestructor(handler);
396 }
397
398 // Prompt dialog run delayed return Cancel.
TEST(JSDialogTest,PromptRunDelayedCancel)399 TEST(JSDialogTest, PromptRunDelayedCancel) {
400 CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
401 JSDialogTestHandler::TYPE_PROMPT, JSDialogTestHandler::MODE_RUN_DELAYED,
402 false, // success
403 "some_value", // user_input
404 "null"); // result
405 handler->ExecuteTest();
406
407 EXPECT_TRUE(handler->got_onjsdialog_);
408 EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
409 EXPECT_TRUE(handler->got_onresetdialogstate_);
410 EXPECT_TRUE(handler->got_onloadend_);
411
412 ReleaseAndWaitForDestructor(handler);
413 }
414
415 // OnBeforeUnload dialog with immediate callback.
TEST(JSDialogTest,OnBeforeUnloadRunImmediate)416 TEST(JSDialogTest, OnBeforeUnloadRunImmediate) {
417 CefRefPtr<JSDialogTestHandler> handler =
418 new JSDialogTestHandler(JSDialogTestHandler::TYPE_ONBEFOREUNLOAD,
419 JSDialogTestHandler::MODE_RUN_IMMEDIATE,
420 true, // success
421 "", // user_input
422 ""); // result
423 handler->ExecuteTest();
424
425 EXPECT_FALSE(handler->got_onjsdialog_);
426 EXPECT_TRUE(handler->got_onbeforeunloaddialog_);
427 EXPECT_TRUE(handler->got_onresetdialogstate_);
428 EXPECT_TRUE(handler->got_onloadend_);
429
430 ReleaseAndWaitForDestructor(handler);
431 }
432
433 // OnBeforeUnload dialog with delayed callback.
TEST(JSDialogTest,OnBeforeUnloadRunDelayed)434 TEST(JSDialogTest, OnBeforeUnloadRunDelayed) {
435 CefRefPtr<JSDialogTestHandler> handler =
436 new JSDialogTestHandler(JSDialogTestHandler::TYPE_ONBEFOREUNLOAD,
437 JSDialogTestHandler::MODE_RUN_DELAYED,
438 true, // success
439 "", // user_input
440 ""); // result
441 handler->ExecuteTest();
442
443 EXPECT_FALSE(handler->got_onjsdialog_);
444 EXPECT_TRUE(handler->got_onbeforeunloaddialog_);
445 EXPECT_TRUE(handler->got_onresetdialogstate_);
446 EXPECT_TRUE(handler->got_onloadend_);
447
448 ReleaseAndWaitForDestructor(handler);
449 }
450