OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "chrome/test/base/web_ui_browsertest.h" | |
6 | |
7 #include <string> | |
8 #include <vector> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/bind_helpers.h" | |
12 #include "base/lazy_instance.h" | |
13 #include "base/memory/ref_counted_memory.h" | |
14 #include "base/path_service.h" | |
15 #include "base/strings/string_util.h" | |
16 #include "base/strings/utf_string_conversions.h" | |
17 #include "base/values.h" | |
18 #include "chrome/browser/chrome_content_browser_client.h" | |
19 #include "chrome/browser/profiles/profile.h" | |
20 #include "chrome/browser/ui/browser.h" | |
21 #include "chrome/browser/ui/browser_commands.h" | |
22 #include "chrome/browser/ui/browser_navigator.h" | |
23 #include "chrome/browser/ui/tabs/tab_strip_model.h" | |
24 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" | |
25 #include "chrome/browser/ui/webui/web_ui_test_handler.h" | |
26 #include "chrome/common/chrome_paths.h" | |
27 #include "chrome/common/url_constants.h" | |
28 #include "chrome/test/base/test_chrome_web_ui_controller_factory.h" | |
29 #include "chrome/test/base/ui_test_utils.h" | |
30 #include "content/public/browser/navigation_controller.h" | |
31 #include "content/public/browser/notification_observer.h" | |
32 #include "content/public/browser/notification_registrar.h" | |
33 #include "content/public/browser/notification_service.h" | |
34 #include "content/public/browser/notification_types.h" | |
35 #include "content/public/browser/url_data_source.h" | |
36 #include "content/public/browser/web_contents.h" | |
37 #include "content/public/browser/web_contents_observer.h" | |
38 #include "content/public/browser/web_ui_controller.h" | |
39 #include "content/public/browser/web_ui_message_handler.h" | |
40 #include "content/public/test/browser_test_utils.h" | |
41 #include "content/public/test/test_navigation_observer.h" | |
42 #include "net/base/filename_util.h" | |
43 #include "testing/gmock/include/gmock/gmock.h" | |
44 #include "testing/gtest/include/gtest/gtest-spi.h" | |
45 #include "ui/base/resource/resource_bundle.h" | |
46 #include "ui/base/resource/resource_handle.h" | |
47 | |
48 #if defined(ENABLE_FULL_PRINTING) | |
49 #include "chrome/browser/printing/print_preview_dialog_controller.h" | |
50 #endif | |
51 | |
52 using content::NavigationController; | |
53 using content::RenderViewHost; | |
54 using content::WebContents; | |
55 using content::WebUIController; | |
56 using content::WebUIMessageHandler; | |
57 | |
58 namespace { | |
59 | |
60 const base::FilePath::CharType kA11yAuditLibraryJSPath[] = FILE_PATH_LITERAL( | |
61 "third_party/accessibility-audit/axs_testing.js"); | |
62 const base::FilePath::CharType kMockJSPath[] = | |
63 FILE_PATH_LITERAL("chrome/third_party/mock4js/mock4js.js"); | |
64 const base::FilePath::CharType kWebUILibraryJS[] = | |
65 FILE_PATH_LITERAL("test_api.js"); | |
66 const base::FilePath::CharType kWebUITestFolder[] = FILE_PATH_LITERAL("webui"); | |
67 base::LazyInstance<std::vector<std::string> > error_messages_ = | |
68 LAZY_INSTANCE_INITIALIZER; | |
69 | |
70 // Intercepts all log messages. | |
71 bool LogHandler(int severity, | |
72 const char* file, | |
73 int line, | |
74 size_t message_start, | |
75 const std::string& str) { | |
76 if (severity == logging::LOG_ERROR && | |
77 file && | |
78 std::string("CONSOLE") == file) { | |
79 error_messages_.Get().push_back(str); | |
80 } | |
81 | |
82 return false; | |
83 } | |
84 | |
85 class WebUIJsInjectionReadyObserver : public content::WebContentsObserver { | |
86 public: | |
87 WebUIJsInjectionReadyObserver(content::WebContents* web_contents, | |
88 WebUIBrowserTest* browser_test, | |
89 const std::string& preload_test_fixture, | |
90 const std::string& preload_test_name) | |
91 : content::WebContentsObserver(web_contents), | |
92 browser_test_(browser_test), | |
93 preload_test_fixture_(preload_test_fixture), | |
94 preload_test_name_(preload_test_name) {} | |
95 | |
96 virtual void RenderViewCreated(content::RenderViewHost* rvh) OVERRIDE { | |
97 browser_test_->PreLoadJavascriptLibraries( | |
98 preload_test_fixture_, preload_test_name_, rvh); | |
99 } | |
100 | |
101 private: | |
102 WebUIBrowserTest* browser_test_; | |
103 std::string preload_test_fixture_; | |
104 std::string preload_test_name_; | |
105 }; | |
106 | |
107 } // namespace | |
108 | |
109 WebUIBrowserTest::~WebUIBrowserTest() {} | |
110 | |
111 void WebUIBrowserTest::AddLibrary(const base::FilePath& library_path) { | |
112 user_libraries_.push_back(library_path); | |
113 } | |
114 | |
115 bool WebUIBrowserTest::RunJavascriptFunction(const std::string& function_name) { | |
116 ConstValueVector empty_args; | |
117 return RunJavascriptFunction(function_name, empty_args); | |
118 } | |
119 | |
120 bool WebUIBrowserTest::RunJavascriptFunction(const std::string& function_name, | |
121 base::Value* arg) { | |
122 ConstValueVector args; | |
123 args.push_back(arg); | |
124 return RunJavascriptFunction(function_name, args); | |
125 } | |
126 | |
127 bool WebUIBrowserTest::RunJavascriptFunction(const std::string& function_name, | |
128 base::Value* arg1, | |
129 base::Value* arg2) { | |
130 ConstValueVector args; | |
131 args.push_back(arg1); | |
132 args.push_back(arg2); | |
133 return RunJavascriptFunction(function_name, args); | |
134 } | |
135 | |
136 bool WebUIBrowserTest::RunJavascriptFunction( | |
137 const std::string& function_name, | |
138 const ConstValueVector& function_arguments) { | |
139 return RunJavascriptUsingHandler( | |
140 function_name, function_arguments, false, false, NULL); | |
141 } | |
142 | |
143 bool WebUIBrowserTest::RunJavascriptTestF(bool is_async, | |
144 const std::string& test_fixture, | |
145 const std::string& test_name) { | |
146 ConstValueVector args; | |
147 args.push_back(new base::StringValue(test_fixture)); | |
148 args.push_back(new base::StringValue(test_name)); | |
149 | |
150 if (is_async) | |
151 return RunJavascriptAsyncTest("RUN_TEST_F", args); | |
152 else | |
153 return RunJavascriptTest("RUN_TEST_F", args); | |
154 } | |
155 | |
156 bool WebUIBrowserTest::RunJavascriptTest(const std::string& test_name) { | |
157 ConstValueVector empty_args; | |
158 return RunJavascriptTest(test_name, empty_args); | |
159 } | |
160 | |
161 bool WebUIBrowserTest::RunJavascriptTest(const std::string& test_name, | |
162 base::Value* arg) { | |
163 ConstValueVector args; | |
164 args.push_back(arg); | |
165 return RunJavascriptTest(test_name, args); | |
166 } | |
167 | |
168 bool WebUIBrowserTest::RunJavascriptTest(const std::string& test_name, | |
169 base::Value* arg1, | |
170 base::Value* arg2) { | |
171 ConstValueVector args; | |
172 args.push_back(arg1); | |
173 args.push_back(arg2); | |
174 return RunJavascriptTest(test_name, args); | |
175 } | |
176 | |
177 bool WebUIBrowserTest::RunJavascriptTest( | |
178 const std::string& test_name, | |
179 const ConstValueVector& test_arguments) { | |
180 return RunJavascriptUsingHandler( | |
181 test_name, test_arguments, true, false, NULL); | |
182 } | |
183 | |
184 bool WebUIBrowserTest::RunJavascriptAsyncTest(const std::string& test_name) { | |
185 ConstValueVector empty_args; | |
186 return RunJavascriptAsyncTest(test_name, empty_args); | |
187 } | |
188 | |
189 bool WebUIBrowserTest::RunJavascriptAsyncTest(const std::string& test_name, | |
190 base::Value* arg) { | |
191 ConstValueVector args; | |
192 args.push_back(arg); | |
193 return RunJavascriptAsyncTest(test_name, args); | |
194 } | |
195 | |
196 bool WebUIBrowserTest::RunJavascriptAsyncTest(const std::string& test_name, | |
197 base::Value* arg1, | |
198 base::Value* arg2) { | |
199 ConstValueVector args; | |
200 args.push_back(arg1); | |
201 args.push_back(arg2); | |
202 return RunJavascriptAsyncTest(test_name, args); | |
203 } | |
204 | |
205 bool WebUIBrowserTest::RunJavascriptAsyncTest(const std::string& test_name, | |
206 base::Value* arg1, | |
207 base::Value* arg2, | |
208 base::Value* arg3) { | |
209 ConstValueVector args; | |
210 args.push_back(arg1); | |
211 args.push_back(arg2); | |
212 args.push_back(arg3); | |
213 return RunJavascriptAsyncTest(test_name, args); | |
214 } | |
215 | |
216 bool WebUIBrowserTest::RunJavascriptAsyncTest( | |
217 const std::string& test_name, | |
218 const ConstValueVector& test_arguments) { | |
219 return RunJavascriptUsingHandler(test_name, test_arguments, true, true, NULL); | |
220 } | |
221 | |
222 void WebUIBrowserTest::PreLoadJavascriptLibraries( | |
223 const std::string& preload_test_fixture, | |
224 const std::string& preload_test_name, | |
225 RenderViewHost* preload_host) { | |
226 ASSERT_FALSE(libraries_preloaded_); | |
227 ConstValueVector args; | |
228 args.push_back(new base::StringValue(preload_test_fixture)); | |
229 args.push_back(new base::StringValue(preload_test_name)); | |
230 RunJavascriptUsingHandler( | |
231 "preloadJavascriptLibraries", args, false, false, preload_host); | |
232 libraries_preloaded_ = true; | |
233 } | |
234 | |
235 void WebUIBrowserTest::BrowsePreload(const GURL& browse_to) { | |
236 content::WebContents* web_contents = | |
237 browser()->tab_strip_model()->GetActiveWebContents(); | |
238 WebUIJsInjectionReadyObserver injection_observer( | |
239 web_contents, this, preload_test_fixture_, preload_test_name_); | |
240 content::TestNavigationObserver navigation_observer(web_contents); | |
241 chrome::NavigateParams params(browser(), GURL(browse_to), | |
242 content::PAGE_TRANSITION_TYPED); | |
243 params.disposition = CURRENT_TAB; | |
244 chrome::Navigate(¶ms); | |
245 navigation_observer.Wait(); | |
246 } | |
247 | |
248 #if defined(ENABLE_FULL_PRINTING) | |
249 | |
250 // This custom ContentBrowserClient is used to get notified when a WebContents | |
251 // for the print preview dialog gets created. | |
252 class PrintContentBrowserClient : public chrome::ChromeContentBrowserClient { | |
253 public: | |
254 PrintContentBrowserClient(WebUIBrowserTest* browser_test, | |
255 const std::string& preload_test_fixture, | |
256 const std::string& preload_test_name) | |
257 : browser_test_(browser_test), | |
258 preload_test_fixture_(preload_test_fixture), | |
259 preload_test_name_(preload_test_name), | |
260 preview_dialog_(NULL), | |
261 message_loop_runner_(new content::MessageLoopRunner) {} | |
262 | |
263 void Wait() { | |
264 message_loop_runner_->Run(); | |
265 content::WaitForLoadStop(preview_dialog_); | |
266 } | |
267 | |
268 private: | |
269 // ChromeContentBrowserClient implementation: | |
270 virtual content::WebContentsViewDelegate* GetWebContentsViewDelegate( | |
271 content::WebContents* web_contents) OVERRIDE { | |
272 preview_dialog_ = web_contents; | |
273 observer_.reset(new WebUIJsInjectionReadyObserver( | |
274 preview_dialog_, browser_test_, preload_test_fixture_, | |
275 preload_test_name_)); | |
276 message_loop_runner_->Quit(); | |
277 return NULL; | |
278 } | |
279 | |
280 WebUIBrowserTest* browser_test_; | |
281 scoped_ptr<WebUIJsInjectionReadyObserver> observer_; | |
282 std::string preload_test_fixture_; | |
283 std::string preload_test_name_; | |
284 content::WebContents* preview_dialog_; | |
285 scoped_refptr<content::MessageLoopRunner> message_loop_runner_; | |
286 }; | |
287 #endif | |
288 | |
289 void WebUIBrowserTest::BrowsePrintPreload(const GURL& browse_to) { | |
290 #if defined(ENABLE_FULL_PRINTING) | |
291 ui_test_utils::NavigateToURL(browser(), browse_to); | |
292 | |
293 PrintContentBrowserClient new_client( | |
294 this, preload_test_fixture_, preload_test_name_); | |
295 content::ContentBrowserClient* old_client = | |
296 SetBrowserClientForTesting(&new_client); | |
297 | |
298 chrome::Print(browser()); | |
299 new_client.Wait(); | |
300 | |
301 SetBrowserClientForTesting(old_client); | |
302 | |
303 printing::PrintPreviewDialogController* tab_controller = | |
304 printing::PrintPreviewDialogController::GetInstance(); | |
305 ASSERT_TRUE(tab_controller); | |
306 WebContents* preview_dialog = tab_controller->GetPrintPreviewForContents( | |
307 browser()->tab_strip_model()->GetActiveWebContents()); | |
308 ASSERT_TRUE(preview_dialog); | |
309 SetWebUIInstance(preview_dialog->GetWebUI()); | |
310 #else | |
311 NOTREACHED(); | |
312 #endif | |
313 } | |
314 | |
315 const char WebUIBrowserTest::kDummyURL[] = "chrome://DummyURL"; | |
316 | |
317 WebUIBrowserTest::WebUIBrowserTest() | |
318 : test_handler_(new WebUITestHandler()), | |
319 libraries_preloaded_(false), | |
320 override_selected_web_ui_(NULL) {} | |
321 | |
322 void WebUIBrowserTest::set_preload_test_fixture( | |
323 const std::string& preload_test_fixture) { | |
324 preload_test_fixture_ = preload_test_fixture; | |
325 } | |
326 | |
327 void WebUIBrowserTest::set_preload_test_name( | |
328 const std::string& preload_test_name) { | |
329 preload_test_name_ = preload_test_name; | |
330 } | |
331 | |
332 namespace { | |
333 | |
334 // DataSource for the dummy URL. If no data source is provided then an error | |
335 // page is shown. While this doesn't matter for most tests, without it, | |
336 // navigation to different anchors cannot be listened to (via the hashchange | |
337 // event). | |
338 class MockWebUIDataSource : public content::URLDataSource { | |
339 public: | |
340 MockWebUIDataSource() {} | |
341 | |
342 private: | |
343 virtual ~MockWebUIDataSource() {} | |
344 | |
345 virtual std::string GetSource() const OVERRIDE { | |
346 return "dummyurl"; | |
347 } | |
348 | |
349 virtual void StartDataRequest( | |
350 const std::string& path, | |
351 int render_process_id, | |
352 int render_frame_id, | |
353 const content::URLDataSource::GotDataCallback& callback) OVERRIDE { | |
354 std::string dummy_html = "<html><body>Dummy</body></html>"; | |
355 scoped_refptr<base::RefCountedString> response = | |
356 base::RefCountedString::TakeString(&dummy_html); | |
357 callback.Run(response.get()); | |
358 } | |
359 | |
360 virtual std::string GetMimeType(const std::string& path) const OVERRIDE { | |
361 return "text/html"; | |
362 } | |
363 | |
364 DISALLOW_COPY_AND_ASSIGN(MockWebUIDataSource); | |
365 }; | |
366 | |
367 // WebUIProvider to allow attaching the DataSource for the dummy URL when | |
368 // testing. | |
369 class MockWebUIProvider | |
370 : public TestChromeWebUIControllerFactory::WebUIProvider { | |
371 public: | |
372 MockWebUIProvider() {} | |
373 | |
374 // Returns a new WebUI | |
375 virtual WebUIController* NewWebUI(content::WebUI* web_ui, | |
376 const GURL& url) OVERRIDE { | |
377 WebUIController* controller = new content::WebUIController(web_ui); | |
378 Profile* profile = Profile::FromWebUI(web_ui); | |
379 content::URLDataSource::Add(profile, new MockWebUIDataSource()); | |
380 return controller; | |
381 } | |
382 | |
383 private: | |
384 DISALLOW_COPY_AND_ASSIGN(MockWebUIProvider); | |
385 }; | |
386 | |
387 base::LazyInstance<MockWebUIProvider> mock_provider_ = | |
388 LAZY_INSTANCE_INITIALIZER; | |
389 | |
390 } // namespace | |
391 | |
392 void WebUIBrowserTest::SetUpOnMainThread() { | |
393 logging::SetLogMessageHandler(&LogHandler); | |
394 | |
395 content::WebUIControllerFactory::UnregisterFactoryForTesting( | |
396 ChromeWebUIControllerFactory::GetInstance()); | |
397 | |
398 test_factory_.reset(new TestChromeWebUIControllerFactory); | |
399 | |
400 content::WebUIControllerFactory::RegisterFactory(test_factory_.get()); | |
401 | |
402 test_factory_->AddFactoryOverride( | |
403 GURL(kDummyURL).host(), mock_provider_.Pointer()); | |
404 | |
405 base::FilePath test_data_directory; | |
406 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory)); | |
407 test_data_directory = test_data_directory.Append(kWebUITestFolder); | |
408 library_search_paths_.push_back(test_data_directory); | |
409 | |
410 base::FilePath gen_test_data_directory; | |
411 ASSERT_TRUE(PathService::Get(chrome::DIR_GEN_TEST_DATA, | |
412 &gen_test_data_directory)); | |
413 library_search_paths_.push_back(gen_test_data_directory); | |
414 | |
415 base::FilePath source_root_directory; | |
416 ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &source_root_directory)); | |
417 library_search_paths_.push_back(source_root_directory); | |
418 | |
419 // TODO(dtseng): should this be part of every BrowserTest or just WebUI test. | |
420 base::FilePath resources_pack_path; | |
421 PathService::Get(chrome::FILE_RESOURCES_PACK, &resources_pack_path); | |
422 ResourceBundle::GetSharedInstance().AddDataPackFromPath( | |
423 resources_pack_path, ui::SCALE_FACTOR_NONE); | |
424 | |
425 AddLibrary(base::FilePath(kA11yAuditLibraryJSPath)); | |
426 AddLibrary(base::FilePath(kMockJSPath)); | |
427 AddLibrary(base::FilePath(kWebUILibraryJS)); | |
428 } | |
429 | |
430 void WebUIBrowserTest::CleanUpOnMainThread() { | |
431 logging::SetLogMessageHandler(NULL); | |
432 | |
433 test_factory_->RemoveFactoryOverride(GURL(kDummyURL).host()); | |
434 content::WebUIControllerFactory::UnregisterFactoryForTesting( | |
435 test_factory_.get()); | |
436 | |
437 // This is needed to avoid a debug assert after the test completes, see stack | |
438 // trace in http://crrev.com/179347 | |
439 content::WebUIControllerFactory::RegisterFactory( | |
440 ChromeWebUIControllerFactory::GetInstance()); | |
441 | |
442 test_factory_.reset(); | |
443 } | |
444 | |
445 void WebUIBrowserTest::SetWebUIInstance(content::WebUI* web_ui) { | |
446 override_selected_web_ui_ = web_ui; | |
447 } | |
448 | |
449 WebUIMessageHandler* WebUIBrowserTest::GetMockMessageHandler() { | |
450 return NULL; | |
451 } | |
452 | |
453 GURL WebUIBrowserTest::WebUITestDataPathToURL( | |
454 const base::FilePath::StringType& path) { | |
455 base::FilePath dir_test_data; | |
456 EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &dir_test_data)); | |
457 base::FilePath test_path(dir_test_data.Append(kWebUITestFolder).Append(path)); | |
458 EXPECT_TRUE(base::PathExists(test_path)); | |
459 return net::FilePathToFileURL(test_path); | |
460 } | |
461 | |
462 void WebUIBrowserTest::BuildJavascriptLibraries( | |
463 std::vector<base::string16>* libraries) { | |
464 ASSERT_TRUE(libraries != NULL); | |
465 std::vector<base::FilePath>::iterator user_libraries_iterator; | |
466 for (user_libraries_iterator = user_libraries_.begin(); | |
467 user_libraries_iterator != user_libraries_.end(); | |
468 ++user_libraries_iterator) { | |
469 std::string library_content; | |
470 if (user_libraries_iterator->IsAbsolute()) { | |
471 ASSERT_TRUE(base::ReadFileToString(*user_libraries_iterator, | |
472 &library_content)) | |
473 << user_libraries_iterator->value(); | |
474 } else { | |
475 bool ok = false; | |
476 std::vector<base::FilePath>::iterator library_search_path_iterator; | |
477 for (library_search_path_iterator = library_search_paths_.begin(); | |
478 library_search_path_iterator != library_search_paths_.end(); | |
479 ++library_search_path_iterator) { | |
480 ok = base::ReadFileToString( | |
481 base::MakeAbsoluteFilePath( | |
482 library_search_path_iterator->Append(*user_libraries_iterator)), | |
483 &library_content); | |
484 if (ok) | |
485 break; | |
486 } | |
487 ASSERT_TRUE(ok) << "User library not found: " | |
488 << user_libraries_iterator->value(); | |
489 } | |
490 library_content.append(";\n"); | |
491 | |
492 // This magic code puts filenames in stack traces. | |
493 library_content.append("//# sourceURL="); | |
494 library_content.append(user_libraries_iterator->BaseName().AsUTF8Unsafe()); | |
495 library_content.append("\n"); | |
496 libraries->push_back(base::UTF8ToUTF16(library_content)); | |
497 } | |
498 } | |
499 | |
500 base::string16 WebUIBrowserTest::BuildRunTestJSCall( | |
501 bool is_async, | |
502 const std::string& function_name, | |
503 const WebUIBrowserTest::ConstValueVector& test_func_args) { | |
504 ConstValueVector arguments; | |
505 base::FundamentalValue* is_async_arg = new base::FundamentalValue(is_async); | |
506 arguments.push_back(is_async_arg); | |
507 base::StringValue* function_name_arg = new base::StringValue(function_name); | |
508 arguments.push_back(function_name_arg); | |
509 base::ListValue* baked_argument_list = new base::ListValue(); | |
510 ConstValueVector::const_iterator arguments_iterator; | |
511 for (arguments_iterator = test_func_args.begin(); | |
512 arguments_iterator != test_func_args.end(); | |
513 ++arguments_iterator) { | |
514 baked_argument_list->Append((*arguments_iterator)->DeepCopy()); | |
515 } | |
516 arguments.push_back(baked_argument_list); | |
517 return content::WebUI::GetJavascriptCall(std::string("runTest"), | |
518 arguments.get()); | |
519 } | |
520 | |
521 bool WebUIBrowserTest::RunJavascriptUsingHandler( | |
522 const std::string& function_name, | |
523 const ConstValueVector& function_arguments, | |
524 bool is_test, | |
525 bool is_async, | |
526 RenderViewHost* preload_host) { | |
527 // Get the user libraries. Preloading them individually is best, then | |
528 // we can assign each one a filename for better stack traces. Otherwise | |
529 // append them all to |content|. | |
530 base::string16 content; | |
531 std::vector<base::string16> libraries; | |
532 if (!libraries_preloaded_) { | |
533 BuildJavascriptLibraries(&libraries); | |
534 if (!preload_host) { | |
535 content = JoinString(libraries, '\n'); | |
536 libraries.clear(); | |
537 } | |
538 } | |
539 | |
540 if (!function_name.empty()) { | |
541 base::string16 called_function; | |
542 if (is_test) { | |
543 called_function = | |
544 BuildRunTestJSCall(is_async, function_name, function_arguments); | |
545 } else { | |
546 called_function = | |
547 content::WebUI::GetJavascriptCall(function_name, | |
548 function_arguments.get()); | |
549 } | |
550 content.append(called_function); | |
551 } | |
552 | |
553 if (!preload_host) | |
554 SetupHandlers(); | |
555 | |
556 bool result = true; | |
557 | |
558 for (size_t i = 0; i < libraries.size(); ++i) | |
559 test_handler_->PreloadJavaScript(libraries[i], preload_host); | |
560 | |
561 if (is_test) | |
562 result = test_handler_->RunJavaScriptTestWithResult(content); | |
563 else if (preload_host) | |
564 test_handler_->PreloadJavaScript(content, preload_host); | |
565 else | |
566 test_handler_->RunJavaScript(content); | |
567 | |
568 if (error_messages_.Get().size() > 0) { | |
569 LOG(ERROR) << "Encountered javascript console error(s)"; | |
570 result = false; | |
571 error_messages_.Get().clear(); | |
572 } | |
573 return result; | |
574 } | |
575 | |
576 void WebUIBrowserTest::SetupHandlers() { | |
577 content::WebUI* web_ui_instance = override_selected_web_ui_ ? | |
578 override_selected_web_ui_ : | |
579 browser()->tab_strip_model()->GetActiveWebContents()->GetWebUI(); | |
580 ASSERT_TRUE(web_ui_instance != NULL); | |
581 | |
582 test_handler_->set_web_ui(web_ui_instance); | |
583 test_handler_->RegisterMessages(); | |
584 | |
585 if (GetMockMessageHandler()) { | |
586 GetMockMessageHandler()->set_web_ui(web_ui_instance); | |
587 GetMockMessageHandler()->RegisterMessages(); | |
588 } | |
589 } | |
590 | |
591 // According to the interface for EXPECT_FATAL_FAILURE | |
592 // (http://code.google.com/p/googletest/wiki/AdvancedGuide#Catching_Failures) | |
593 // the statement must be statically available. Therefore, we make a static | |
594 // global s_test_ which should point to |this| for the duration of the test run | |
595 // and be cleared afterward. | |
596 class WebUIBrowserExpectFailTest : public WebUIBrowserTest { | |
597 public: | |
598 WebUIBrowserExpectFailTest() { | |
599 EXPECT_FALSE(s_test_); | |
600 s_test_ = this; | |
601 } | |
602 | |
603 protected: | |
604 virtual ~WebUIBrowserExpectFailTest() { | |
605 EXPECT_TRUE(s_test_); | |
606 s_test_ = NULL; | |
607 } | |
608 | |
609 static void RunJavascriptTestNoReturn(const std::string& testname) { | |
610 EXPECT_TRUE(s_test_); | |
611 s_test_->RunJavascriptTest(testname); | |
612 } | |
613 | |
614 static void RunJavascriptAsyncTestNoReturn(const std::string& testname) { | |
615 EXPECT_TRUE(s_test_); | |
616 s_test_->RunJavascriptAsyncTest(testname); | |
617 } | |
618 | |
619 private: | |
620 static WebUIBrowserTest* s_test_; | |
621 }; | |
622 | |
623 WebUIBrowserTest* WebUIBrowserExpectFailTest::s_test_ = NULL; | |
624 | |
625 // Test that bogus javascript fails fast - no timeout waiting for result. | |
626 IN_PROC_BROWSER_TEST_F(WebUIBrowserExpectFailTest, TestFailsFast) { | |
627 AddLibrary(base::FilePath(FILE_PATH_LITERAL("sample_downloads.js"))); | |
628 ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIDownloadsURL)); | |
629 EXPECT_FATAL_FAILURE(RunJavascriptTestNoReturn("DISABLED_BogusFunctionName"), | |
630 "WebUITestHandler::JavaScriptComplete"); | |
631 } | |
632 | |
633 // Test that bogus javascript fails fast - no timeout waiting for result. | |
634 IN_PROC_BROWSER_TEST_F(WebUIBrowserExpectFailTest, TestRuntimeErrorFailsFast) { | |
635 AddLibrary(base::FilePath(FILE_PATH_LITERAL("runtime_error.js"))); | |
636 ui_test_utils::NavigateToURL(browser(), GURL(kDummyURL)); | |
637 EXPECT_FATAL_FAILURE(RunJavascriptTestNoReturn("TestRuntimeErrorFailsFast"), | |
638 "WebUITestHandler::JavaScriptComplete"); | |
639 } | |
640 | |
641 // Test that bogus javascript fails async test fast as well - no timeout waiting | |
642 // for result. | |
643 IN_PROC_BROWSER_TEST_F(WebUIBrowserExpectFailTest, TestFailsAsyncFast) { | |
644 AddLibrary(base::FilePath(FILE_PATH_LITERAL("sample_downloads.js"))); | |
645 ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIDownloadsURL)); | |
646 EXPECT_FATAL_FAILURE( | |
647 RunJavascriptAsyncTestNoReturn("DISABLED_BogusFunctionName"), | |
648 "WebUITestHandler::JavaScriptComplete"); | |
649 } | |
650 | |
651 // Tests that the async framework works. | |
652 class WebUIBrowserAsyncTest : public WebUIBrowserTest { | |
653 public: | |
654 // Calls the testDone() function from test_api.js | |
655 void TestDone() { | |
656 RunJavascriptFunction("testDone"); | |
657 } | |
658 | |
659 // Starts a failing test. | |
660 void RunTestFailsAssert() { | |
661 RunJavascriptFunction("runAsync", new base::StringValue("testFailsAssert")); | |
662 } | |
663 | |
664 // Starts a passing test. | |
665 void RunTestPasses() { | |
666 RunJavascriptFunction("runAsync", new base::StringValue("testPasses")); | |
667 } | |
668 | |
669 protected: | |
670 WebUIBrowserAsyncTest() {} | |
671 | |
672 // Class to synchronize asynchronous javascript activity with the tests. | |
673 class AsyncWebUIMessageHandler : public WebUIMessageHandler { | |
674 public: | |
675 AsyncWebUIMessageHandler() {} | |
676 | |
677 MOCK_METHOD1(HandleTestContinues, void(const base::ListValue*)); | |
678 MOCK_METHOD1(HandleTestFails, void(const base::ListValue*)); | |
679 MOCK_METHOD1(HandleTestPasses, void(const base::ListValue*)); | |
680 | |
681 private: | |
682 virtual void RegisterMessages() OVERRIDE { | |
683 web_ui()->RegisterMessageCallback("startAsyncTest", | |
684 base::Bind(&AsyncWebUIMessageHandler::HandleStartAsyncTest, | |
685 base::Unretained(this))); | |
686 web_ui()->RegisterMessageCallback("testContinues", | |
687 base::Bind(&AsyncWebUIMessageHandler::HandleTestContinues, | |
688 base::Unretained(this))); | |
689 web_ui()->RegisterMessageCallback("testFails", | |
690 base::Bind(&AsyncWebUIMessageHandler::HandleTestFails, | |
691 base::Unretained(this))); | |
692 web_ui()->RegisterMessageCallback("testPasses", | |
693 base::Bind(&AsyncWebUIMessageHandler::HandleTestPasses, | |
694 base::Unretained(this))); | |
695 } | |
696 | |
697 // Starts the test in |list_value|[0] with the runAsync wrapper. | |
698 void HandleStartAsyncTest(const base::ListValue* list_value) { | |
699 const base::Value* test_name; | |
700 ASSERT_TRUE(list_value->Get(0, &test_name)); | |
701 web_ui()->CallJavascriptFunction("runAsync", *test_name); | |
702 } | |
703 | |
704 DISALLOW_COPY_AND_ASSIGN(AsyncWebUIMessageHandler); | |
705 }; | |
706 | |
707 // Handler for this object. | |
708 ::testing::StrictMock<AsyncWebUIMessageHandler> message_handler_; | |
709 | |
710 private: | |
711 // Provide this object's handler. | |
712 virtual WebUIMessageHandler* GetMockMessageHandler() OVERRIDE { | |
713 return &message_handler_; | |
714 } | |
715 | |
716 // Set up and browse to kDummyURL for all tests. | |
717 virtual void SetUpOnMainThread() OVERRIDE { | |
718 WebUIBrowserTest::SetUpOnMainThread(); | |
719 AddLibrary(base::FilePath(FILE_PATH_LITERAL("async.js"))); | |
720 ui_test_utils::NavigateToURL(browser(), GURL(kDummyURL)); | |
721 } | |
722 | |
723 DISALLOW_COPY_AND_ASSIGN(WebUIBrowserAsyncTest); | |
724 }; | |
725 | |
726 // Test that assertions fail immediately after assertion fails (no testContinues | |
727 // message). (Sync version). | |
728 IN_PROC_BROWSER_TEST_F(WebUIBrowserAsyncTest, TestSyncOkTestFail) { | |
729 ASSERT_FALSE(RunJavascriptTest("testFailsAssert")); | |
730 } | |
731 | |
732 // Test that assertions fail immediately after assertion fails (no testContinues | |
733 // message). (Async version). | |
734 IN_PROC_BROWSER_TEST_F(WebUIBrowserAsyncTest, TestAsyncFailsAssert) { | |
735 EXPECT_CALL(message_handler_, HandleTestFails(::testing::_)); | |
736 ASSERT_FALSE(RunJavascriptAsyncTest( | |
737 "startAsyncTest", new base::StringValue("testFailsAssert"))); | |
738 } | |
739 | |
740 // Test that expectations continue the function, but fail the test. | |
741 IN_PROC_BROWSER_TEST_F(WebUIBrowserAsyncTest, TestAsyncFailsExpect) { | |
742 ::testing::InSequence s; | |
743 EXPECT_CALL(message_handler_, HandleTestContinues(::testing::_)); | |
744 EXPECT_CALL(message_handler_, HandleTestFails(::testing::_)); | |
745 ASSERT_FALSE(RunJavascriptAsyncTest( | |
746 "startAsyncTest", new base::StringValue("testFailsExpect"))); | |
747 } | |
748 | |
749 // Test that test continues and passes. (Sync version). | |
750 IN_PROC_BROWSER_TEST_F(WebUIBrowserAsyncTest, TestSyncPasses) { | |
751 EXPECT_CALL(message_handler_, HandleTestContinues(::testing::_)); | |
752 ASSERT_TRUE(RunJavascriptTest("testPasses")); | |
753 } | |
754 | |
755 // Test that test continues and passes. (Async version). | |
756 IN_PROC_BROWSER_TEST_F(WebUIBrowserAsyncTest, TestAsyncPasses) { | |
757 ::testing::InSequence s; | |
758 EXPECT_CALL(message_handler_, HandleTestContinues(::testing::_)); | |
759 EXPECT_CALL(message_handler_, HandleTestPasses(::testing::_)) | |
760 .WillOnce(::testing::InvokeWithoutArgs( | |
761 this, &WebUIBrowserAsyncTest::TestDone)); | |
762 ASSERT_TRUE(RunJavascriptAsyncTest( | |
763 "startAsyncTest", new base::StringValue("testPasses"))); | |
764 } | |
765 | |
766 // Test that two tests pass. | |
767 IN_PROC_BROWSER_TEST_F(WebUIBrowserAsyncTest, TestAsyncPassPass) { | |
768 ::testing::InSequence s; | |
769 EXPECT_CALL(message_handler_, HandleTestContinues(::testing::_)); | |
770 EXPECT_CALL(message_handler_, HandleTestPasses(::testing::_)) | |
771 .WillOnce(::testing::InvokeWithoutArgs( | |
772 this, &WebUIBrowserAsyncTest::RunTestPasses)); | |
773 EXPECT_CALL(message_handler_, HandleTestContinues(::testing::_)); | |
774 EXPECT_CALL(message_handler_, HandleTestPasses(::testing::_)) | |
775 .WillOnce(::testing::InvokeWithoutArgs( | |
776 this, &WebUIBrowserAsyncTest::TestDone)); | |
777 ASSERT_TRUE(RunJavascriptAsyncTest( | |
778 "startAsyncTest", new base::StringValue("testPasses"))); | |
779 } | |
780 | |
781 // Test that first test passes; second fails. | |
782 IN_PROC_BROWSER_TEST_F(WebUIBrowserAsyncTest, TestAsyncPassThenFail) { | |
783 ::testing::InSequence s; | |
784 EXPECT_CALL(message_handler_, HandleTestContinues(::testing::_)); | |
785 EXPECT_CALL(message_handler_, HandleTestPasses(::testing::_)) | |
786 .WillOnce(::testing::InvokeWithoutArgs( | |
787 this, &WebUIBrowserAsyncTest::RunTestFailsAssert)); | |
788 EXPECT_CALL(message_handler_, HandleTestFails(::testing::_)); | |
789 ASSERT_FALSE(RunJavascriptAsyncTest( | |
790 "startAsyncTest", new base::StringValue("testPasses"))); | |
791 } | |
792 | |
793 // Test that testDone() with failure first then sync pass still fails. | |
794 IN_PROC_BROWSER_TEST_F(WebUIBrowserAsyncTest, TestAsyncDoneFailFirstSyncPass) { | |
795 ::testing::InSequence s; | |
796 EXPECT_CALL(message_handler_, HandleTestContinues(::testing::_)); | |
797 EXPECT_CALL(message_handler_, HandleTestFails(::testing::_)); | |
798 | |
799 // Call runAsync directly instead of deferring through startAsyncTest. It will | |
800 // call testDone() on failure, then return. | |
801 ASSERT_FALSE(RunJavascriptAsyncTest( | |
802 "runAsync", new base::StringValue("testAsyncDoneFailFirstSyncPass"))); | |
803 } | |
804 | |
805 // Test that calling testDone during RunJavascriptAsyncTest still completes | |
806 // when waiting for async result. This is similar to the previous test, but call | |
807 // testDone directly and expect pass result. | |
808 IN_PROC_BROWSER_TEST_F(WebUIBrowserAsyncTest, TestTestDoneEarlyPassesAsync) { | |
809 ASSERT_TRUE(RunJavascriptAsyncTest("testDone")); | |
810 } | |
811 | |
812 // Test that calling testDone during RunJavascriptTest still completes when | |
813 // waiting for async result. | |
814 IN_PROC_BROWSER_TEST_F(WebUIBrowserAsyncTest, TestTestDoneEarlyPasses) { | |
815 ASSERT_TRUE(RunJavascriptTest("testDone")); | |
816 } | |
OLD | NEW |