Merge html-office-public repo into src
[chromium-blink-merge.git] / chrome / test / base / web_ui_browser_test.cc
blob4ba0b0b0006c87a9a0c38f4c67b2157979b46dba
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/values.h"
15 #include "chrome/browser/chrome_content_browser_client.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/browser_commands.h"
19 #include "chrome/browser/ui/tabs/tab_strip_model.h"
20 #include "chrome/browser/ui/webui/web_ui_test_handler.h"
21 #include "chrome/common/chrome_paths.h"
22 #include "chrome/common/url_constants.h"
23 #include "chrome/test/base/test_chrome_web_ui_controller_factory.h"
24 #include "chrome/test/base/ui_test_utils.h"
25 #include "content/public/browser/url_data_source.h"
26 #include "content/public/browser/web_contents.h"
27 #include "content/public/browser/web_contents_observer.h"
28 #include "content/public/browser/web_ui_controller.h"
29 #include "content/public/browser/web_ui_message_handler.h"
30 #include "content/public/test/browser_test_utils.h"
31 #include "content/public/test/test_navigation_observer.h"
32 #include "net/base/filename_util.h"
33 #include "ui/base/resource/resource_handle.h"
35 #if defined(ENABLE_PRINT_PREVIEW)
36 #include "chrome/browser/printing/print_preview_dialog_controller.h"
37 #endif
39 using content::RenderViewHost;
40 using content::WebContents;
41 using content::WebUIController;
42 using content::WebUIMessageHandler;
44 namespace {
46 base::LazyInstance<std::vector<std::string> > error_messages_ =
47 LAZY_INSTANCE_INITIALIZER;
49 // Intercepts all log messages.
50 bool LogHandler(int severity,
51 const char* file,
52 int line,
53 size_t message_start,
54 const std::string& str) {
55 if (severity == logging::LOG_ERROR && file &&
56 std::string("CONSOLE") == file) {
57 error_messages_.Get().push_back(str);
60 return false;
63 class WebUIJsInjectionReadyObserver : public content::WebContentsObserver {
64 public:
65 WebUIJsInjectionReadyObserver(content::WebContents* web_contents,
66 WebUIBrowserTest* browser_test,
67 const std::string& preload_test_fixture,
68 const std::string& preload_test_name)
69 : content::WebContentsObserver(web_contents),
70 browser_test_(browser_test),
71 preload_test_fixture_(preload_test_fixture),
72 preload_test_name_(preload_test_name) {}
74 void RenderViewCreated(content::RenderViewHost* rvh) override {
75 browser_test_->PreLoadJavascriptLibraries(
76 preload_test_fixture_, preload_test_name_, rvh);
79 private:
80 WebUIBrowserTest* browser_test_;
81 std::string preload_test_fixture_;
82 std::string preload_test_name_;
85 } // namespace
87 WebUIBrowserTest::~WebUIBrowserTest() {
90 bool WebUIBrowserTest::RunJavascriptFunction(const std::string& function_name) {
91 ConstValueVector empty_args;
92 return RunJavascriptFunction(function_name, empty_args);
95 bool WebUIBrowserTest::RunJavascriptFunction(const std::string& function_name,
96 base::Value* arg) {
97 ConstValueVector args;
98 args.push_back(arg);
99 return RunJavascriptFunction(function_name, args);
102 bool WebUIBrowserTest::RunJavascriptFunction(const std::string& function_name,
103 base::Value* arg1,
104 base::Value* arg2) {
105 ConstValueVector args;
106 args.push_back(arg1);
107 args.push_back(arg2);
108 return RunJavascriptFunction(function_name, args);
111 bool WebUIBrowserTest::RunJavascriptFunction(
112 const std::string& function_name,
113 const ConstValueVector& function_arguments) {
114 return RunJavascriptUsingHandler(
115 function_name, function_arguments, false, false, NULL);
118 bool WebUIBrowserTest::RunJavascriptTestF(bool is_async,
119 const std::string& test_fixture,
120 const std::string& test_name) {
121 ConstValueVector args;
122 args.push_back(new base::StringValue(test_fixture));
123 args.push_back(new base::StringValue(test_name));
125 if (is_async)
126 return RunJavascriptAsyncTest("RUN_TEST_F", args);
127 else
128 return RunJavascriptTest("RUN_TEST_F", args);
131 bool WebUIBrowserTest::RunJavascriptTest(const std::string& test_name) {
132 ConstValueVector empty_args;
133 return RunJavascriptTest(test_name, empty_args);
136 bool WebUIBrowserTest::RunJavascriptTest(const std::string& test_name,
137 base::Value* arg) {
138 ConstValueVector args;
139 args.push_back(arg);
140 return RunJavascriptTest(test_name, args);
143 bool WebUIBrowserTest::RunJavascriptTest(const std::string& test_name,
144 base::Value* arg1,
145 base::Value* arg2) {
146 ConstValueVector args;
147 args.push_back(arg1);
148 args.push_back(arg2);
149 return RunJavascriptTest(test_name, args);
152 bool WebUIBrowserTest::RunJavascriptTest(
153 const std::string& test_name,
154 const ConstValueVector& test_arguments) {
155 return RunJavascriptUsingHandler(
156 test_name, test_arguments, true, false, NULL);
159 bool WebUIBrowserTest::RunJavascriptAsyncTest(const std::string& test_name) {
160 ConstValueVector empty_args;
161 return RunJavascriptAsyncTest(test_name, empty_args);
164 bool WebUIBrowserTest::RunJavascriptAsyncTest(const std::string& test_name,
165 base::Value* arg) {
166 ConstValueVector args;
167 args.push_back(arg);
168 return RunJavascriptAsyncTest(test_name, args);
171 bool WebUIBrowserTest::RunJavascriptAsyncTest(const std::string& test_name,
172 base::Value* arg1,
173 base::Value* arg2) {
174 ConstValueVector args;
175 args.push_back(arg1);
176 args.push_back(arg2);
177 return RunJavascriptAsyncTest(test_name, args);
180 bool WebUIBrowserTest::RunJavascriptAsyncTest(const std::string& test_name,
181 base::Value* arg1,
182 base::Value* arg2,
183 base::Value* arg3) {
184 ConstValueVector args;
185 args.push_back(arg1);
186 args.push_back(arg2);
187 args.push_back(arg3);
188 return RunJavascriptAsyncTest(test_name, args);
191 bool WebUIBrowserTest::RunJavascriptAsyncTest(
192 const std::string& test_name,
193 const ConstValueVector& test_arguments) {
194 return RunJavascriptUsingHandler(test_name, test_arguments, true, true, NULL);
197 void WebUIBrowserTest::PreLoadJavascriptLibraries(
198 const std::string& preload_test_fixture,
199 const std::string& preload_test_name,
200 RenderViewHost* preload_host) {
201 ASSERT_FALSE(libraries_preloaded_);
202 ConstValueVector args;
203 args.push_back(new base::StringValue(preload_test_fixture));
204 args.push_back(new base::StringValue(preload_test_name));
205 RunJavascriptUsingHandler(
206 "preloadJavascriptLibraries", args, false, false, preload_host);
207 libraries_preloaded_ = true;
210 void WebUIBrowserTest::BrowsePreload(const GURL& browse_to) {
211 content::WebContents* web_contents =
212 browser()->tab_strip_model()->GetActiveWebContents();
213 WebUIJsInjectionReadyObserver injection_observer(
214 web_contents, this, preload_test_fixture_, preload_test_name_);
215 content::TestNavigationObserver navigation_observer(web_contents);
216 chrome::NavigateParams params(
217 browser(), GURL(browse_to), ui::PAGE_TRANSITION_TYPED);
218 params.disposition = CURRENT_TAB;
219 chrome::Navigate(&params);
220 navigation_observer.Wait();
223 #if defined(ENABLE_PRINT_PREVIEW)
225 // This custom ContentBrowserClient is used to get notified when a WebContents
226 // for the print preview dialog gets created.
227 class PrintContentBrowserClient : public chrome::ChromeContentBrowserClient {
228 public:
229 PrintContentBrowserClient(WebUIBrowserTest* browser_test,
230 const std::string& preload_test_fixture,
231 const std::string& preload_test_name)
232 : browser_test_(browser_test),
233 preload_test_fixture_(preload_test_fixture),
234 preload_test_name_(preload_test_name),
235 preview_dialog_(NULL),
236 message_loop_runner_(new content::MessageLoopRunner) {}
238 void Wait() {
239 message_loop_runner_->Run();
240 content::WaitForLoadStop(preview_dialog_);
243 private:
244 // ChromeContentBrowserClient implementation:
245 content::WebContentsViewDelegate* GetWebContentsViewDelegate(
246 content::WebContents* web_contents) override {
247 preview_dialog_ = web_contents;
248 observer_.reset(new WebUIJsInjectionReadyObserver(preview_dialog_,
249 browser_test_,
250 preload_test_fixture_,
251 preload_test_name_));
252 message_loop_runner_->Quit();
253 return NULL;
256 WebUIBrowserTest* browser_test_;
257 scoped_ptr<WebUIJsInjectionReadyObserver> observer_;
258 std::string preload_test_fixture_;
259 std::string preload_test_name_;
260 content::WebContents* preview_dialog_;
261 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
263 #endif
265 void WebUIBrowserTest::BrowsePrintPreload(const GURL& browse_to) {
266 #if defined(ENABLE_PRINT_PREVIEW)
267 ui_test_utils::NavigateToURL(browser(), browse_to);
269 PrintContentBrowserClient new_client(
270 this, preload_test_fixture_, preload_test_name_);
271 content::ContentBrowserClient* old_client =
272 SetBrowserClientForTesting(&new_client);
274 chrome::Print(browser());
275 new_client.Wait();
277 SetBrowserClientForTesting(old_client);
279 printing::PrintPreviewDialogController* tab_controller =
280 printing::PrintPreviewDialogController::GetInstance();
281 ASSERT_TRUE(tab_controller);
282 WebContents* preview_dialog = tab_controller->GetPrintPreviewForContents(
283 browser()->tab_strip_model()->GetActiveWebContents());
284 ASSERT_TRUE(preview_dialog);
285 SetWebUIInstance(preview_dialog->GetWebUI());
286 #else
287 NOTREACHED();
288 #endif
291 const char WebUIBrowserTest::kDummyURL[] = "chrome://DummyURL";
293 WebUIBrowserTest::WebUIBrowserTest()
294 : test_handler_(new WebUITestHandler()),
295 libraries_preloaded_(false),
296 override_selected_web_ui_(NULL) {
299 void WebUIBrowserTest::set_preload_test_fixture(
300 const std::string& preload_test_fixture) {
301 preload_test_fixture_ = preload_test_fixture;
304 void WebUIBrowserTest::set_preload_test_name(
305 const std::string& preload_test_name) {
306 preload_test_name_ = preload_test_name;
309 namespace {
311 // DataSource for the dummy URL. If no data source is provided then an error
312 // page is shown. While this doesn't matter for most tests, without it,
313 // navigation to different anchors cannot be listened to (via the hashchange
314 // event).
315 class MockWebUIDataSource : public content::URLDataSource {
316 public:
317 MockWebUIDataSource() {}
319 private:
320 ~MockWebUIDataSource() override {}
322 std::string GetSource() const override { return "dummyurl"; }
324 void StartDataRequest(
325 const std::string& path,
326 int render_process_id,
327 int render_frame_id,
328 const content::URLDataSource::GotDataCallback& callback) override {
329 std::string dummy_html = "<html><body>Dummy</body></html>";
330 scoped_refptr<base::RefCountedString> response =
331 base::RefCountedString::TakeString(&dummy_html);
332 callback.Run(response.get());
335 std::string GetMimeType(const std::string& path) const override {
336 return "text/html";
339 DISALLOW_COPY_AND_ASSIGN(MockWebUIDataSource);
342 // WebUIProvider to allow attaching the DataSource for the dummy URL when
343 // testing.
344 class MockWebUIProvider
345 : public TestChromeWebUIControllerFactory::WebUIProvider {
346 public:
347 MockWebUIProvider() {}
349 // Returns a new WebUI
350 WebUIController* NewWebUI(content::WebUI* web_ui, const GURL& url) override {
351 WebUIController* controller = new content::WebUIController(web_ui);
352 Profile* profile = Profile::FromWebUI(web_ui);
353 content::URLDataSource::Add(profile, new MockWebUIDataSource());
354 return controller;
357 private:
358 DISALLOW_COPY_AND_ASSIGN(MockWebUIProvider);
361 base::LazyInstance<MockWebUIProvider> mock_provider_ =
362 LAZY_INSTANCE_INITIALIZER;
364 } // namespace
366 void WebUIBrowserTest::SetUpOnMainThread() {
367 JavaScriptBrowserTest::SetUpOnMainThread();
369 logging::SetLogMessageHandler(&LogHandler);
371 AddLibrary(base::FilePath(kA11yAuditLibraryJSPath));
373 content::WebUIControllerFactory::UnregisterFactoryForTesting(
374 ChromeWebUIControllerFactory::GetInstance());
376 test_factory_.reset(new TestChromeWebUIControllerFactory);
378 content::WebUIControllerFactory::RegisterFactory(test_factory_.get());
380 test_factory_->AddFactoryOverride(GURL(kDummyURL).host(),
381 mock_provider_.Pointer());
384 void WebUIBrowserTest::TearDownOnMainThread() {
385 logging::SetLogMessageHandler(NULL);
387 test_factory_->RemoveFactoryOverride(GURL(kDummyURL).host());
388 content::WebUIControllerFactory::UnregisterFactoryForTesting(
389 test_factory_.get());
391 // This is needed to avoid a debug assert after the test completes, see stack
392 // trace in http://crrev.com/179347
393 content::WebUIControllerFactory::RegisterFactory(
394 ChromeWebUIControllerFactory::GetInstance());
396 test_factory_.reset();
399 void WebUIBrowserTest::SetWebUIInstance(content::WebUI* web_ui) {
400 override_selected_web_ui_ = web_ui;
403 WebUIMessageHandler* WebUIBrowserTest::GetMockMessageHandler() {
404 return NULL;
407 bool WebUIBrowserTest::RunJavascriptUsingHandler(
408 const std::string& function_name,
409 const ConstValueVector& function_arguments,
410 bool is_test,
411 bool is_async,
412 RenderViewHost* preload_host) {
413 // Get the user libraries. Preloading them individually is best, then
414 // we can assign each one a filename for better stack traces. Otherwise
415 // append them all to |content|.
416 base::string16 content;
417 std::vector<base::string16> libraries;
418 if (!libraries_preloaded_) {
419 BuildJavascriptLibraries(&libraries);
420 if (!preload_host) {
421 content = JoinString(libraries, '\n');
422 libraries.clear();
426 if (!function_name.empty()) {
427 base::string16 called_function;
428 if (is_test) {
429 called_function =
430 BuildRunTestJSCall(is_async, function_name, function_arguments);
431 } else {
432 called_function = content::WebUI::GetJavascriptCall(
433 function_name, function_arguments.get());
435 content.append(called_function);
438 if (!preload_host)
439 SetupHandlers();
441 bool result = true;
443 for (size_t i = 0; i < libraries.size(); ++i)
444 test_handler_->PreloadJavaScript(libraries[i], preload_host);
446 if (is_test)
447 result = test_handler_->RunJavaScriptTestWithResult(content);
448 else if (preload_host)
449 test_handler_->PreloadJavaScript(content, preload_host);
450 else
451 test_handler_->RunJavaScript(content);
453 if (error_messages_.Get().size() > 0) {
454 LOG(ERROR) << "Encountered javascript console error(s)";
455 result = false;
456 error_messages_.Get().clear();
458 return result;
461 void WebUIBrowserTest::SetupHandlers() {
462 content::WebUI* web_ui_instance =
463 override_selected_web_ui_
464 ? override_selected_web_ui_
465 : browser()->tab_strip_model()->GetActiveWebContents()->GetWebUI();
466 ASSERT_TRUE(web_ui_instance != NULL);
468 test_handler_->set_web_ui(web_ui_instance);
469 test_handler_->RegisterMessages();
471 if (GetMockMessageHandler()) {
472 GetMockMessageHandler()->set_web_ui(web_ui_instance);
473 GetMockMessageHandler()->RegisterMessages();
477 GURL WebUIBrowserTest::WebUITestDataPathToURL(
478 const base::FilePath::StringType& path) {
479 base::FilePath dir_test_data;
480 EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &dir_test_data));
481 base::FilePath test_path(dir_test_data.Append(kWebUITestFolder).Append(path));
482 EXPECT_TRUE(base::PathExists(test_path));
483 return net::FilePathToFileURL(test_path);