Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / test / base / web_ui_browser_test.cc
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.
4
5 #include "chrome/test/base/web_ui_browser_test.h"
6
7 #include <string>
8 #include <vector>
9
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"
34
35 #if defined(ENABLE_PRINT_PREVIEW)
36 #include "chrome/browser/printing/print_preview_dialog_controller.h"
37 #endif
38
39 using content::RenderViewHost;
40 using content::WebContents;
41 using content::WebUIController;
42 using content::WebUIMessageHandler;
43
44 namespace {
45
46 base::LazyInstance<std::vector<std::string> > error_messages_ =
47     LAZY_INSTANCE_INITIALIZER;
48
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);
58   }
59
60   return false;
61 }
62
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) {}
73
74   void RenderViewCreated(content::RenderViewHost* rvh) override {
75     browser_test_->PreLoadJavascriptLibraries(
76         preload_test_fixture_, preload_test_name_, rvh);
77   }
78
79  private:
80   WebUIBrowserTest* browser_test_;
81   std::string preload_test_fixture_;
82   std::string preload_test_name_;
83 };
84
85 }  // namespace
86
87 WebUIBrowserTest::~WebUIBrowserTest() {
88 }
89
90 bool WebUIBrowserTest::RunJavascriptFunction(const std::string& function_name) {
91   ConstValueVector empty_args;
92   return RunJavascriptFunction(function_name, empty_args);
93 }
94
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);
100 }
101
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);
109 }
110
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);
116 }
117
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));
124
125   if (is_async)
126     return RunJavascriptAsyncTest("RUN_TEST_F", args);
127   else
128     return RunJavascriptTest("RUN_TEST_F", args);
129 }
130
131 bool WebUIBrowserTest::RunJavascriptTest(const std::string& test_name) {
132   ConstValueVector empty_args;
133   return RunJavascriptTest(test_name, empty_args);
134 }
135
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);
141 }
142
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);
150 }
151
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);
157 }
158
159 bool WebUIBrowserTest::RunJavascriptAsyncTest(const std::string& test_name) {
160   ConstValueVector empty_args;
161   return RunJavascriptAsyncTest(test_name, empty_args);
162 }
163
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);
169 }
170
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);
178 }
179
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);
189 }
190
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);
195 }
196
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;
208 }
209
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();
221 }
222
223 #if defined(ENABLE_PRINT_PREVIEW)
224
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) {}
237
238   void Wait() {
239     message_loop_runner_->Run();
240     content::WaitForLoadStop(preview_dialog_);
241   }
242
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;
254   }
255
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_;
262 };
263 #endif
264
265 void WebUIBrowserTest::BrowsePrintPreload(const GURL& browse_to) {
266 #if defined(ENABLE_PRINT_PREVIEW)
267   ui_test_utils::NavigateToURL(browser(), browse_to);
268
269   PrintContentBrowserClient new_client(
270       this, preload_test_fixture_, preload_test_name_);
271   content::ContentBrowserClient* old_client =
272       SetBrowserClientForTesting(&new_client);
273
274   chrome::Print(browser());
275   new_client.Wait();
276
277   SetBrowserClientForTesting(old_client);
278
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
289 }
290
291 const char WebUIBrowserTest::kDummyURL[] = "chrome://DummyURL";
292
293 WebUIBrowserTest::WebUIBrowserTest()
294     : test_handler_(new WebUITestHandler()),
295       libraries_preloaded_(false),
296       override_selected_web_ui_(NULL) {
297 }
298
299 void WebUIBrowserTest::set_preload_test_fixture(
300     const std::string& preload_test_fixture) {
301   preload_test_fixture_ = preload_test_fixture;
302 }
303
304 void WebUIBrowserTest::set_preload_test_name(
305     const std::string& preload_test_name) {
306   preload_test_name_ = preload_test_name;
307 }
308
309 namespace {
310
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() {}
318
319  private:
320   ~MockWebUIDataSource() override {}
321
322   std::string GetSource() const override { return "dummyurl"; }
323
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());
333   }
334
335   std::string GetMimeType(const std::string& path) const override {
336     return "text/html";
337   }
338
339   DISALLOW_COPY_AND_ASSIGN(MockWebUIDataSource);
340 };
341
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() {}
348
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;
355   }
356
357  private:
358   DISALLOW_COPY_AND_ASSIGN(MockWebUIProvider);
359 };
360
361 base::LazyInstance<MockWebUIProvider> mock_provider_ =
362     LAZY_INSTANCE_INITIALIZER;
363
364 }  // namespace
365
366 void WebUIBrowserTest::SetUpOnMainThread() {
367   JavaScriptBrowserTest::SetUpOnMainThread();
368
369   logging::SetLogMessageHandler(&LogHandler);
370
371   AddLibrary(base::FilePath(kA11yAuditLibraryJSPath));
372
373   content::WebUIControllerFactory::UnregisterFactoryForTesting(
374       ChromeWebUIControllerFactory::GetInstance());
375
376   test_factory_.reset(new TestChromeWebUIControllerFactory);
377
378   content::WebUIControllerFactory::RegisterFactory(test_factory_.get());
379
380   test_factory_->AddFactoryOverride(GURL(kDummyURL).host(),
381                                     mock_provider_.Pointer());
382 }
383
384 void WebUIBrowserTest::TearDownOnMainThread() {
385   logging::SetLogMessageHandler(NULL);
386
387   test_factory_->RemoveFactoryOverride(GURL(kDummyURL).host());
388   content::WebUIControllerFactory::UnregisterFactoryForTesting(
389       test_factory_.get());
390
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());
395
396   test_factory_.reset();
397 }
398
399 void WebUIBrowserTest::SetWebUIInstance(content::WebUI* web_ui) {
400   override_selected_web_ui_ = web_ui;
401 }
402
403 WebUIMessageHandler* WebUIBrowserTest::GetMockMessageHandler() {
404   return NULL;
405 }
406
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();
423     }
424   }
425
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());
434     }
435     content.append(called_function);
436   }
437
438   if (!preload_host)
439     SetupHandlers();
440
441   bool result = true;
442
443   for (size_t i = 0; i < libraries.size(); ++i)
444     test_handler_->PreloadJavaScript(libraries[i], preload_host);
445
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);
452
453   if (error_messages_.Get().size() > 0) {
454     LOG(ERROR) << "Encountered javascript console error(s)";
455     result = false;
456     error_messages_.Get().clear();
457   }
458   return result;
459 }
460
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);
467
468   test_handler_->set_web_ui(web_ui_instance);
469   test_handler_->RegisterMessages();
470
471   if (GetMockMessageHandler()) {
472     GetMockMessageHandler()->set_web_ui(web_ui_instance);
473     GetMockMessageHandler()->RegisterMessages();
474   }
475 }
476
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);
484 }