Update CrOS OOBE throbber to MD throbber; delete old asset
[chromium-blink-merge.git] / chrome / test / base / web_ui_browser_test.cc
blob0b9d3a5bf98c8b3407b435d6a5eecd0c2139764c
1 // Copyright 2014 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.
5 #include "chrome/test/base/web_ui_browser_test.h"
7 #include <string>
8 #include <vector>
10 #include "base/lazy_instance.h"
11 #include "base/memory/ref_counted_memory.h"
12 #include "base/path_service.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/values.h"
16 #include "chrome/browser/chrome_content_browser_client.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/browser_commands.h"
20 #include "chrome/browser/ui/tabs/tab_strip_model.h"
21 #include "chrome/browser/ui/webui/web_ui_test_handler.h"
22 #include "chrome/common/chrome_paths.h"
23 #include "chrome/common/url_constants.h"
24 #include "chrome/test/base/test_chrome_web_ui_controller_factory.h"
25 #include "chrome/test/base/ui_test_utils.h"
26 #include "content/public/browser/url_data_source.h"
27 #include "content/public/browser/web_contents.h"
28 #include "content/public/browser/web_contents_observer.h"
29 #include "content/public/browser/web_ui_controller.h"
30 #include "content/public/browser/web_ui_message_handler.h"
31 #include "content/public/test/browser_test_utils.h"
32 #include "content/public/test/test_navigation_observer.h"
33 #include "net/base/filename_util.h"
34 #include "ui/base/resource/resource_handle.h"
36 #if defined(ENABLE_PRINT_PREVIEW)
37 #include "chrome/browser/printing/print_preview_dialog_controller.h"
38 #endif
40 using content::RenderViewHost;
41 using content::WebContents;
42 using content::WebUIController;
43 using content::WebUIMessageHandler;
45 namespace {
47 base::LazyInstance<std::vector<std::string> > error_messages_ =
48 LAZY_INSTANCE_INITIALIZER;
50 // Intercepts all log messages.
51 bool LogHandler(int severity,
52 const char* file,
53 int line,
54 size_t message_start,
55 const std::string& str) {
56 if (severity == logging::LOG_ERROR && file &&
57 std::string("CONSOLE") == file) {
58 error_messages_.Get().push_back(str);
61 return false;
64 class WebUIJsInjectionReadyObserver : public content::WebContentsObserver {
65 public:
66 WebUIJsInjectionReadyObserver(content::WebContents* web_contents,
67 WebUIBrowserTest* browser_test,
68 const std::string& preload_test_fixture,
69 const std::string& preload_test_name)
70 : content::WebContentsObserver(web_contents),
71 browser_test_(browser_test),
72 preload_test_fixture_(preload_test_fixture),
73 preload_test_name_(preload_test_name) {}
75 void RenderViewCreated(content::RenderViewHost* rvh) override {
76 browser_test_->PreLoadJavascriptLibraries(
77 preload_test_fixture_, preload_test_name_, rvh);
80 private:
81 WebUIBrowserTest* browser_test_;
82 std::string preload_test_fixture_;
83 std::string preload_test_name_;
86 } // namespace
88 WebUIBrowserTest::~WebUIBrowserTest() {
91 bool WebUIBrowserTest::RunJavascriptFunction(const std::string& function_name) {
92 ConstValueVector empty_args;
93 return RunJavascriptFunction(function_name, empty_args);
96 bool WebUIBrowserTest::RunJavascriptFunction(const std::string& function_name,
97 base::Value* arg) {
98 ConstValueVector args;
99 args.push_back(arg);
100 return RunJavascriptFunction(function_name, args);
103 bool WebUIBrowserTest::RunJavascriptFunction(const std::string& function_name,
104 base::Value* arg1,
105 base::Value* arg2) {
106 ConstValueVector args;
107 args.push_back(arg1);
108 args.push_back(arg2);
109 return RunJavascriptFunction(function_name, args);
112 bool WebUIBrowserTest::RunJavascriptFunction(
113 const std::string& function_name,
114 const ConstValueVector& function_arguments) {
115 return RunJavascriptUsingHandler(
116 function_name, function_arguments, false, false, NULL);
119 bool WebUIBrowserTest::RunJavascriptTestF(bool is_async,
120 const std::string& test_fixture,
121 const std::string& test_name) {
122 ConstValueVector args;
123 args.push_back(new base::StringValue(test_fixture));
124 args.push_back(new base::StringValue(test_name));
126 if (is_async)
127 return RunJavascriptAsyncTest("RUN_TEST_F", args);
128 else
129 return RunJavascriptTest("RUN_TEST_F", args);
132 bool WebUIBrowserTest::RunJavascriptTest(const std::string& test_name) {
133 ConstValueVector empty_args;
134 return RunJavascriptTest(test_name, empty_args);
137 bool WebUIBrowserTest::RunJavascriptTest(const std::string& test_name,
138 base::Value* arg) {
139 ConstValueVector args;
140 args.push_back(arg);
141 return RunJavascriptTest(test_name, args);
144 bool WebUIBrowserTest::RunJavascriptTest(const std::string& test_name,
145 base::Value* arg1,
146 base::Value* arg2) {
147 ConstValueVector args;
148 args.push_back(arg1);
149 args.push_back(arg2);
150 return RunJavascriptTest(test_name, args);
153 bool WebUIBrowserTest::RunJavascriptTest(
154 const std::string& test_name,
155 const ConstValueVector& test_arguments) {
156 return RunJavascriptUsingHandler(
157 test_name, test_arguments, true, false, NULL);
160 bool WebUIBrowserTest::RunJavascriptAsyncTest(const std::string& test_name) {
161 ConstValueVector empty_args;
162 return RunJavascriptAsyncTest(test_name, empty_args);
165 bool WebUIBrowserTest::RunJavascriptAsyncTest(const std::string& test_name,
166 base::Value* arg) {
167 ConstValueVector args;
168 args.push_back(arg);
169 return RunJavascriptAsyncTest(test_name, args);
172 bool WebUIBrowserTest::RunJavascriptAsyncTest(const std::string& test_name,
173 base::Value* arg1,
174 base::Value* arg2) {
175 ConstValueVector args;
176 args.push_back(arg1);
177 args.push_back(arg2);
178 return RunJavascriptAsyncTest(test_name, args);
181 bool WebUIBrowserTest::RunJavascriptAsyncTest(const std::string& test_name,
182 base::Value* arg1,
183 base::Value* arg2,
184 base::Value* arg3) {
185 ConstValueVector args;
186 args.push_back(arg1);
187 args.push_back(arg2);
188 args.push_back(arg3);
189 return RunJavascriptAsyncTest(test_name, args);
192 bool WebUIBrowserTest::RunJavascriptAsyncTest(
193 const std::string& test_name,
194 const ConstValueVector& test_arguments) {
195 return RunJavascriptUsingHandler(test_name, test_arguments, true, true, NULL);
198 void WebUIBrowserTest::PreLoadJavascriptLibraries(
199 const std::string& preload_test_fixture,
200 const std::string& preload_test_name,
201 RenderViewHost* preload_host) {
202 ASSERT_FALSE(libraries_preloaded_);
203 ConstValueVector args;
204 args.push_back(new base::StringValue(preload_test_fixture));
205 args.push_back(new base::StringValue(preload_test_name));
206 RunJavascriptUsingHandler(
207 "preloadJavascriptLibraries", args, false, false, preload_host);
208 libraries_preloaded_ = true;
211 void WebUIBrowserTest::BrowsePreload(const GURL& browse_to) {
212 content::WebContents* web_contents =
213 browser()->tab_strip_model()->GetActiveWebContents();
214 WebUIJsInjectionReadyObserver injection_observer(
215 web_contents, this, preload_test_fixture_, preload_test_name_);
216 content::TestNavigationObserver navigation_observer(web_contents);
217 chrome::NavigateParams params(
218 browser(), GURL(browse_to), ui::PAGE_TRANSITION_TYPED);
219 params.disposition = CURRENT_TAB;
220 chrome::Navigate(&params);
221 navigation_observer.Wait();
224 #if defined(ENABLE_PRINT_PREVIEW)
226 // This custom ContentBrowserClient is used to get notified when a WebContents
227 // for the print preview dialog gets created.
228 class PrintContentBrowserClient : public chrome::ChromeContentBrowserClient {
229 public:
230 PrintContentBrowserClient(WebUIBrowserTest* browser_test,
231 const std::string& preload_test_fixture,
232 const std::string& preload_test_name)
233 : browser_test_(browser_test),
234 preload_test_fixture_(preload_test_fixture),
235 preload_test_name_(preload_test_name),
236 preview_dialog_(NULL),
237 message_loop_runner_(new content::MessageLoopRunner) {}
239 void Wait() {
240 message_loop_runner_->Run();
241 content::WaitForLoadStop(preview_dialog_);
244 private:
245 // ChromeContentBrowserClient implementation:
246 content::WebContentsViewDelegate* GetWebContentsViewDelegate(
247 content::WebContents* web_contents) override {
248 preview_dialog_ = web_contents;
249 observer_.reset(new WebUIJsInjectionReadyObserver(preview_dialog_,
250 browser_test_,
251 preload_test_fixture_,
252 preload_test_name_));
253 message_loop_runner_->Quit();
254 return NULL;
257 WebUIBrowserTest* browser_test_;
258 scoped_ptr<WebUIJsInjectionReadyObserver> observer_;
259 std::string preload_test_fixture_;
260 std::string preload_test_name_;
261 content::WebContents* preview_dialog_;
262 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
264 #endif
266 void WebUIBrowserTest::BrowsePrintPreload(const GURL& browse_to) {
267 #if defined(ENABLE_PRINT_PREVIEW)
268 ui_test_utils::NavigateToURL(browser(), browse_to);
270 PrintContentBrowserClient new_client(
271 this, preload_test_fixture_, preload_test_name_);
272 content::ContentBrowserClient* old_client =
273 SetBrowserClientForTesting(&new_client);
275 chrome::Print(browser());
276 new_client.Wait();
278 SetBrowserClientForTesting(old_client);
280 printing::PrintPreviewDialogController* tab_controller =
281 printing::PrintPreviewDialogController::GetInstance();
282 ASSERT_TRUE(tab_controller);
283 WebContents* preview_dialog = tab_controller->GetPrintPreviewForContents(
284 browser()->tab_strip_model()->GetActiveWebContents());
285 ASSERT_TRUE(preview_dialog);
286 SetWebUIInstance(preview_dialog->GetWebUI());
287 #else
288 NOTREACHED();
289 #endif
292 const char WebUIBrowserTest::kDummyURL[] = "chrome://DummyURL";
294 WebUIBrowserTest::WebUIBrowserTest()
295 : test_handler_(new WebUITestHandler()),
296 libraries_preloaded_(false),
297 override_selected_web_ui_(NULL) {
300 void WebUIBrowserTest::set_preload_test_fixture(
301 const std::string& preload_test_fixture) {
302 preload_test_fixture_ = preload_test_fixture;
305 void WebUIBrowserTest::set_preload_test_name(
306 const std::string& preload_test_name) {
307 preload_test_name_ = preload_test_name;
310 namespace {
312 // DataSource for the dummy URL. If no data source is provided then an error
313 // page is shown. While this doesn't matter for most tests, without it,
314 // navigation to different anchors cannot be listened to (via the hashchange
315 // event).
316 class MockWebUIDataSource : public content::URLDataSource {
317 public:
318 MockWebUIDataSource() {}
320 private:
321 ~MockWebUIDataSource() override {}
323 std::string GetSource() const override { return "dummyurl"; }
325 void StartDataRequest(
326 const std::string& path,
327 int render_process_id,
328 int render_frame_id,
329 const content::URLDataSource::GotDataCallback& callback) override {
330 std::string dummy_html = "<html><body>Dummy</body></html>";
331 scoped_refptr<base::RefCountedString> response =
332 base::RefCountedString::TakeString(&dummy_html);
333 callback.Run(response.get());
336 std::string GetMimeType(const std::string& path) const override {
337 return "text/html";
340 DISALLOW_COPY_AND_ASSIGN(MockWebUIDataSource);
343 // WebUIProvider to allow attaching the DataSource for the dummy URL when
344 // testing.
345 class MockWebUIProvider
346 : public TestChromeWebUIControllerFactory::WebUIProvider {
347 public:
348 MockWebUIProvider() {}
350 // Returns a new WebUI
351 WebUIController* NewWebUI(content::WebUI* web_ui, const GURL& url) override {
352 WebUIController* controller = new content::WebUIController(web_ui);
353 Profile* profile = Profile::FromWebUI(web_ui);
354 content::URLDataSource::Add(profile, new MockWebUIDataSource());
355 return controller;
358 private:
359 DISALLOW_COPY_AND_ASSIGN(MockWebUIProvider);
362 base::LazyInstance<MockWebUIProvider> mock_provider_ =
363 LAZY_INSTANCE_INITIALIZER;
365 } // namespace
367 void WebUIBrowserTest::SetUpOnMainThread() {
368 JavaScriptBrowserTest::SetUpOnMainThread();
370 logging::SetLogMessageHandler(&LogHandler);
372 AddLibrary(base::FilePath(kA11yAuditLibraryJSPath));
374 content::WebUIControllerFactory::UnregisterFactoryForTesting(
375 ChromeWebUIControllerFactory::GetInstance());
377 test_factory_.reset(new TestChromeWebUIControllerFactory);
379 content::WebUIControllerFactory::RegisterFactory(test_factory_.get());
381 test_factory_->AddFactoryOverride(GURL(kDummyURL).host(),
382 mock_provider_.Pointer());
385 void WebUIBrowserTest::TearDownOnMainThread() {
386 logging::SetLogMessageHandler(NULL);
388 test_factory_->RemoveFactoryOverride(GURL(kDummyURL).host());
389 content::WebUIControllerFactory::UnregisterFactoryForTesting(
390 test_factory_.get());
392 // This is needed to avoid a debug assert after the test completes, see stack
393 // trace in http://crrev.com/179347
394 content::WebUIControllerFactory::RegisterFactory(
395 ChromeWebUIControllerFactory::GetInstance());
397 test_factory_.reset();
400 void WebUIBrowserTest::SetWebUIInstance(content::WebUI* web_ui) {
401 override_selected_web_ui_ = web_ui;
404 WebUIMessageHandler* WebUIBrowserTest::GetMockMessageHandler() {
405 return NULL;
408 bool WebUIBrowserTest::RunJavascriptUsingHandler(
409 const std::string& function_name,
410 const ConstValueVector& function_arguments,
411 bool is_test,
412 bool is_async,
413 RenderViewHost* preload_host) {
414 // Get the user libraries. Preloading them individually is best, then
415 // we can assign each one a filename for better stack traces. Otherwise
416 // append them all to |content|.
417 base::string16 content;
418 std::vector<base::string16> libraries;
419 if (!libraries_preloaded_) {
420 BuildJavascriptLibraries(&libraries);
421 if (!preload_host) {
422 content = base::JoinString(libraries, base::ASCIIToUTF16("\n"));
423 libraries.clear();
427 if (!function_name.empty()) {
428 base::string16 called_function;
429 if (is_test) {
430 called_function =
431 BuildRunTestJSCall(is_async, function_name, function_arguments);
432 } else {
433 called_function = content::WebUI::GetJavascriptCall(
434 function_name, function_arguments.get());
436 content.append(called_function);
439 if (!preload_host)
440 SetupHandlers();
442 bool result = true;
444 for (size_t i = 0; i < libraries.size(); ++i)
445 test_handler_->PreloadJavaScript(libraries[i], preload_host);
447 if (is_test)
448 result = test_handler_->RunJavaScriptTestWithResult(content);
449 else if (preload_host)
450 test_handler_->PreloadJavaScript(content, preload_host);
451 else
452 test_handler_->RunJavaScript(content);
454 if (error_messages_.Get().size() > 0) {
455 LOG(ERROR) << "Encountered javascript console error(s)";
456 result = false;
457 error_messages_.Get().clear();
459 return result;
462 void WebUIBrowserTest::SetupHandlers() {
463 content::WebUI* web_ui_instance =
464 override_selected_web_ui_
465 ? override_selected_web_ui_
466 : browser()->tab_strip_model()->GetActiveWebContents()->GetWebUI();
467 ASSERT_TRUE(web_ui_instance != NULL);
469 test_handler_->set_web_ui(web_ui_instance);
470 test_handler_->RegisterMessages();
472 if (GetMockMessageHandler()) {
473 GetMockMessageHandler()->set_web_ui(web_ui_instance);
474 GetMockMessageHandler()->RegisterMessages();
478 GURL WebUIBrowserTest::WebUITestDataPathToURL(
479 const base::FilePath::StringType& path) {
480 base::FilePath dir_test_data;
481 EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &dir_test_data));
482 base::FilePath test_path(dir_test_data.Append(kWebUITestFolder).Append(path));
483 EXPECT_TRUE(base::PathExists(test_path));
484 return net::FilePathToFileURL(test_path);