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