Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(369)

Side by Side Diff: chrome/browser/ui/webui/web_ui_browsertest.cc

Issue 7087014: Support automatic javascript test registry in gtest when creating WebUI tests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Adjusted comments and PathService replacement. Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 #include "chrome/browser/ui/webui/web_ui_browsertest.h" 4 #include "chrome/browser/ui/webui/web_ui_browsertest.h"
5 5
6 #include <string> 6 #include <string>
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/file_util.h"
10 #include "base/lazy_instance.h"
9 #include "base/path_service.h" 11 #include "base/path_service.h"
10 #include "base/utf_string_conversions.h" 12 #include "base/utf_string_conversions.h"
11 #include "base/values.h" 13 #include "base/values.h"
12 #include "chrome/browser/ui/browser.h" 14 #include "chrome/browser/ui/browser.h"
13 #include "chrome/common/chrome_paths.h" 15 #include "chrome/common/chrome_paths.h"
14 #include "chrome/common/url_constants.h" 16 #include "chrome/common/url_constants.h"
17 #include "chrome/test/out_of_proc_test_runner.h"
15 #include "chrome/test/ui_test_utils.h" 18 #include "chrome/test/ui_test_utils.h"
16 #include "content/browser/tab_contents/tab_contents.h" 19 #include "content/browser/tab_contents/tab_contents.h"
17 #include "content/browser/webui/web_ui.h" 20 #include "content/browser/webui/web_ui.h"
18 #include "ui/base/resource/resource_bundle.h" 21 #include "ui/base/resource/resource_bundle.h"
22 #include "v8/include/v8.h"
19 23
20 static const FilePath::CharType* kWebUILibraryJS = 24 namespace {
21 FILE_PATH_LITERAL("test_api.js"); 25 const FilePath::StringType kWebUILibraryJS = FILE_PATH_LITERAL("test_api.js");
22 static const FilePath::CharType* kWebUITestFolder = FILE_PATH_LITERAL("webui"); 26 const FilePath::StringType kWebUITestFolder = FILE_PATH_LITERAL("webui");
23 static std::vector<std::string> error_messages_; 27 const FilePath::StringType kSrcBaseName = FILE_PATH_LITERAL("src");
28 const FilePath::StringType kBuildBaseName = FILE_PATH_LITERAL("build");
29
30 base::LazyInstance<std::vector<std::string> > error_messages_(
31 base::LINKER_INITIALIZED);
32
33 // This method is called before the system is initialized, and we can't use
34 // PathService. In order to support both automated builds and engineers on
35 // multiple platforms, we look down for a src dir if we are within a build
36 // directory and up for src if we are not.
37 FilePath GetTestDataDirectory() {
38 FilePath test_data_directory;
39 EXPECT_TRUE(file_util::GetCurrentDirectory(&test_data_directory));
40 DLOG(INFO) << "test_data_directory = " << test_data_directory.value();
41 if (test_data_directory.BaseName().value() == kBuildBaseName) {
42 FilePath src_subdir = test_data_directory.Append(kSrcBaseName);
43 if (file_util::PathExists(test_data_directory.Append(kSrcBaseName)))
44 test_data_directory = src_subdir;
45 }
46 while (test_data_directory.BaseName().value() != kSrcBaseName) {
47 FilePath dir_name = test_data_directory.DirName();
48 if (test_data_directory == dir_name)
49 break;
50 test_data_directory = dir_name;
51 }
52 EXPECT_EQ(kSrcBaseName, test_data_directory.BaseName().value());
53 test_data_directory = test_data_directory.Append(FILE_PATH_LITERAL("chrome"));
54 test_data_directory = test_data_directory.Append(FILE_PATH_LITERAL("test"));
55 test_data_directory = test_data_directory.Append(FILE_PATH_LITERAL("data"));
56 return test_data_directory.Append(kWebUITestFolder);
57 }
24 58
25 // Intercepts all log messages. 59 // Intercepts all log messages.
26 bool LogHandler(int severity, 60 bool LogHandler(int severity,
27 const char* file, 61 const char* file,
28 int line, 62 int line,
29 size_t message_start, 63 size_t message_start,
30 const std::string& str) { 64 const std::string& str) {
31 if (severity == logging::LOG_ERROR) { 65 if (severity == logging::LOG_ERROR) {
32 error_messages_.push_back(str); 66 error_messages_.Get().push_back(str);
33 return true; 67 return true;
34 } else { 68 } else {
35 // For debugging messages while developing tests. 69 // For debugging messages while developing tests.
36 return false; 70 return false;
37 } 71 }
38 } 72 }
39 73
74 // Read the specified |library| into |content|, prepending |test_data_directory|
75 // when |library| is relative.
76 void ReadLibraryToString(const FilePath& test_data_directory,
77 const FilePath& library,
78 std::string* content) {
79 ASSERT_TRUE(content);
80 if (library.IsAbsolute())
81 ASSERT_TRUE(file_util::ReadFileToString(library, content));
82 else
83 ASSERT_TRUE(file_util::ReadFileToString(test_data_directory.Append(library),
84 content));
85 }
86
87 // Gets functions defined in |library_path| starting with "test". Results are
88 // stored in |testFuncs|, which may not be NULL.
89 bool GetTestFuncs(const FilePath& library_path,
90 std::vector<std::string>* testFuncs) {
91 DCHECK(testFuncs);
92
93 // For export of test_api functions.
94 std::string content = "var window = {};";
95 ReadLibraryToString(GetTestDataDirectory(), library_path, &content);
96 content.append("this;");
97
98 // Run the script, dispose the context, and check the results.
99 v8::HandleScope handle_scope;
100 v8::Persistent<v8::Context> context = v8::Context::New();
101 v8::Context::Scope context_scope(context);
102 v8::Handle<v8::String> source = v8::String::New(content.data(),
103 content.size());
104 v8::Handle<v8::Script> script = v8::Script::Compile(source);
105 v8::TryCatch trycatch;
106 v8::Handle<v8::Value> result = script->Run();
107 context.Dispose();
108 if (result.IsEmpty()) {
109 v8::Handle<v8::Value> exception = trycatch.Exception();
110 v8::String::AsciiValue exception_str(exception);
111 NOTREACHED() << "Exception: " << *exception_str;
112 return false;
113 }
114
115 // Examine the resulting object for properties which are functions, and push
116 // them into |testFuncs|.
117 v8::Local<v8::Object> result_obj = result->ToObject();
118 v8::Local<v8::Array> property_names = result_obj->GetPropertyNames();
119 for (uint32_t index = 0; index < property_names->Length(); ++index) {
120 v8::Local<v8::String> property_name(
121 property_names->Get(index).As<v8::String>());
122 if (!result_obj->HasOwnProperty(property_name))
123 continue;
124 v8::Local<v8::Value> value = result_obj->Get(property_name);
125 if (value.IsEmpty() || !value->IsFunction())
126 continue;
127 v8::String::AsciiValue property_name_ascii(property_name);
128 testFuncs->push_back(std::string(*property_name_ascii,
129 property_name_ascii.length()));
130 }
131 return true;
132 }
133
134 // Since v8 cannot get an isolation thread at linker initialization time on
135 // non-linux systems, we defer the registry until runtime.
136 class WebUITestCallback : public ::test::RegisterTestCallback {
137 public:
138 WebUITestCallback(
139 const ::FilePath& library_path,
140 const char* test_case_name, const char* name,
141 const char* type_param,
142 const char* value_param,
143 ::testing::internal::TypeId fixture_class_id,
144 ::testing::internal::SetUpTestCaseFunc set_up_tc,
145 ::testing::internal::TearDownTestCaseFunc tear_down_tc,
146 ::testing::internal::TestMetaFactoryBase<std::string>* meta_factory)
147 : library_path_(library_path),
148 test_case_name_(test_case_name),
149 name_(name),
150 type_param_(type_param),
151 value_param_(value_param),
152 fixture_class_id_(fixture_class_id),
153 set_up_tc_(set_up_tc),
154 tear_down_tc_(tear_down_tc),
155 meta_factory_(meta_factory) {}
156
157 private:
158 virtual void RegisterTest() const {
159 std::vector<std::string> testFuncs;
160 EXPECT_TRUE(GetTestFuncs(library_path_, &testFuncs));
161 for (std::vector<std::string>::const_iterator it = testFuncs.begin();
162 it != testFuncs.end(); ++it) {
163 std::string test_name = *it + "/" + name_;
164 ::testing::internal::MakeAndRegisterTestInfo(
165 test_case_name_.c_str(), test_name.c_str(),
166 type_param_.c_str(),
167 value_param_.c_str(),
168 fixture_class_id_,
169 set_up_tc_,
170 tear_down_tc_,
171 meta_factory_->CreateTestFactory(*it));
172 }
173 }
174
175 ::FilePath library_path_;
176 std::string test_case_name_;
177 std::string name_;
178 std::string type_param_;
179 std::string value_param_;
180 ::testing::internal::TypeId fixture_class_id_;
181 ::testing::internal::SetUpTestCaseFunc set_up_tc_;
182 ::testing::internal::TearDownTestCaseFunc tear_down_tc_;
183 ::testing::internal::TestMetaFactoryBase<std::string>* meta_factory_;
184
185 DISALLOW_COPY_AND_ASSIGN(WebUITestCallback);
186 };
187
188 } // namespace
189
40 WebUIBrowserTest::~WebUIBrowserTest() {} 190 WebUIBrowserTest::~WebUIBrowserTest() {}
41 191
42 bool WebUIBrowserTest::RunJavascriptFunction(const std::string& function_name) { 192 bool WebUIBrowserTest::RunJavascriptFunction(const std::string& function_name) {
43 return RunJavascriptFunction(function_name, ConstValueVector()); 193 return RunJavascriptFunction(function_name, ConstValueVector());
44 } 194 }
45 195
46 bool WebUIBrowserTest::RunJavascriptFunction(const std::string& function_name, 196 bool WebUIBrowserTest::RunJavascriptFunction(const std::string& function_name,
47 const Value& arg) { 197 const Value& arg) {
48 ConstValueVector args; 198 ConstValueVector args;
49 args.push_back(&arg); 199 args.push_back(&arg);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 bool WebUIBrowserTest::RunJavascriptTest( 238 bool WebUIBrowserTest::RunJavascriptTest(
89 const std::string& test_name, 239 const std::string& test_name,
90 const ConstValueVector& test_arguments) { 240 const ConstValueVector& test_arguments) {
91 return RunJavascriptUsingHandler(test_name, test_arguments, true); 241 return RunJavascriptUsingHandler(test_name, test_arguments, true);
92 } 242 }
93 243
94 WebUIBrowserTest::WebUIBrowserTest() 244 WebUIBrowserTest::WebUIBrowserTest()
95 : test_handler_(new WebUITestHandler()) {} 245 : test_handler_(new WebUITestHandler()) {}
96 246
97 void WebUIBrowserTest::SetUpInProcessBrowserTestFixture() { 247 void WebUIBrowserTest::SetUpInProcessBrowserTestFixture() {
98 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory_)); 248 test_data_directory_ = GetTestDataDirectory();
99 test_data_directory_ = test_data_directory_.Append(kWebUITestFolder);
100 249
101 // TODO(dtseng): should this be part of every BrowserTest or just WebUI test. 250 // TODO(dtseng): should this be part of every BrowserTest or just WebUI test.
102 FilePath resources_pack_path; 251 FilePath resources_pack_path;
103 PathService::Get(chrome::FILE_RESOURCES_PACK, &resources_pack_path); 252 PathService::Get(chrome::FILE_RESOURCES_PACK, &resources_pack_path);
104 ResourceBundle::AddDataPackToSharedInstance(resources_pack_path); 253 ResourceBundle::AddDataPackToSharedInstance(resources_pack_path);
105 254
106 AddLibrary(FilePath(kWebUILibraryJS)); 255 AddLibrary(FilePath(kWebUILibraryJS));
107 } 256 }
108 257
109 WebUIMessageHandler* WebUIBrowserTest::GetMockMessageHandler() { 258 WebUIMessageHandler* WebUIBrowserTest::GetMockMessageHandler() {
110 return NULL; 259 return NULL;
111 } 260 }
112 261
113 void WebUIBrowserTest::BuildJavascriptLibraries(std::string* content) { 262 int WebUIBrowserTest::AddJSToRegistry(
263 const FilePath& library_path,
264 const char* test_case_name, const char* name,
265 const char* type_param,
266 const char* value_param,
267 ::testing::internal::TypeId fixture_class_id,
268 ::testing::internal::SetUpTestCaseFunc set_up_tc,
269 ::testing::internal::TearDownTestCaseFunc tear_down_tc,
270 ::testing::internal::TestMetaFactoryBase<std::string>* meta_factory) {
271 test::AddRegisterTestCallback(new WebUITestCallback(
272 library_path, test_case_name, name, type_param, value_param,
273 fixture_class_id, set_up_tc, tear_down_tc, meta_factory));
274
275 return 0;
276 }
277
278
279 void WebUIBrowserTest::BuildJavascriptLibraries(std::string* content) const {
114 ASSERT_TRUE(content != NULL); 280 ASSERT_TRUE(content != NULL);
115 std::string library_content, src_content; 281 std::string library_content;
116 282
117 std::vector<FilePath>::iterator user_libraries_iterator; 283 std::vector<FilePath>::const_iterator user_libraries_iterator;
118 for (user_libraries_iterator = user_libraries.begin(); 284 for (user_libraries_iterator = user_libraries_.begin();
119 user_libraries_iterator != user_libraries.end(); 285 user_libraries_iterator != user_libraries_.end();
120 ++user_libraries_iterator) { 286 ++user_libraries_iterator) {
121 if (user_libraries_iterator->IsAbsolute()) { 287 ReadLibraryToString(test_data_directory_, *user_libraries_iterator,
122 ASSERT_TRUE(file_util::ReadFileToString(*user_libraries_iterator, 288 &library_content);
123 &library_content));
124 } else {
125 ASSERT_TRUE(file_util::ReadFileToString(
126 test_data_directory_.Append(*user_libraries_iterator),
127 &library_content));
128 }
129 content->append(library_content); 289 content->append(library_content);
130 content->append(";\n"); 290 content->append(";\n");
131 } 291 }
132 } 292 }
133 293
134 string16 WebUIBrowserTest::BuildRunTestJSCall( 294 string16 WebUIBrowserTest::BuildRunTestJSCall(
135 const std::string& function_name, 295 const std::string& function_name,
136 const WebUIBrowserTest::ConstValueVector& test_func_args) { 296 const WebUIBrowserTest::ConstValueVector& test_func_args) {
137 WebUIBrowserTest::ConstValueVector arguments; 297 WebUIBrowserTest::ConstValueVector arguments;
138 StringValue function_name_arg(function_name); 298 StringValue function_name_arg(function_name);
(...skipping 24 matching lines...) Expand all
163 called_function = WebUI::GetJavascriptCall(function_name, 323 called_function = WebUI::GetJavascriptCall(function_name,
164 function_arguments); 324 function_arguments);
165 } 325 }
166 content.append(UTF16ToUTF8(called_function)); 326 content.append(UTF16ToUTF8(called_function));
167 } 327 }
168 SetupHandlers(); 328 SetupHandlers();
169 logging::SetLogMessageHandler(&LogHandler); 329 logging::SetLogMessageHandler(&LogHandler);
170 bool result = test_handler_->RunJavascript(content, is_test); 330 bool result = test_handler_->RunJavascript(content, is_test);
171 logging::SetLogMessageHandler(NULL); 331 logging::SetLogMessageHandler(NULL);
172 332
173 if (error_messages_.size() > 0) { 333 if (error_messages_.Get().size() > 0) {
174 LOG(ERROR) << "Encountered javascript console error(s)"; 334 LOG(ERROR) << "Encountered javascript console error(s)";
175 result = false; 335 result = false;
176 error_messages_.clear(); 336 error_messages_.Get().clear();
177 } 337 }
178 return result; 338 return result;
179 } 339 }
180 340
181 void WebUIBrowserTest::SetupHandlers() { 341 void WebUIBrowserTest::SetupHandlers() {
182 WebUI* web_ui_instance = 342 WebUI* web_ui_instance =
183 browser()->GetSelectedTabContents()->web_ui(); 343 browser()->GetSelectedTabContents()->web_ui();
184 ASSERT_TRUE(web_ui_instance != NULL); 344 ASSERT_TRUE(web_ui_instance != NULL);
185 web_ui_instance->register_callback_overwrites(true); 345 web_ui_instance->register_callback_overwrites(true);
186 test_handler_->Attach(web_ui_instance); 346 test_handler_->Attach(web_ui_instance);
187 347
188 if (GetMockMessageHandler()) 348 if (GetMockMessageHandler())
189 GetMockMessageHandler()->Attach(web_ui_instance); 349 GetMockMessageHandler()->Attach(web_ui_instance);
190 } 350 }
191 351
192 void WebUIBrowserTest::AddLibrary(const FilePath& library_path) { 352 void WebUIBrowserTest::AddLibrary(const FilePath& library_path) {
193 user_libraries.push_back(library_path); 353 user_libraries_.push_back(library_path);
194 } 354 }
195 355
196 IN_PROC_BROWSER_TEST_F(WebUIBrowserTest, TestSamplePass) { 356 IN_PROC_BROWSER_TEST_F(WebUIBrowserTest, TestSamplePass) {
197 AddLibrary(FilePath(FILE_PATH_LITERAL("sample_downloads.js"))); 357 AddLibrary(FilePath(FILE_PATH_LITERAL("sample_passing.js")));
198 358
199 // Navigate to UI. 359 // Navigate to UI.
200 // TODO(dtseng): make accessor for subclasses to return? 360 // TODO(dtseng): make accessor for subclasses to return?
201 ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIDownloadsURL)); 361 ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIDownloadsURL));
202 362
203 ASSERT_TRUE(RunJavascriptTest("testAssertFalse")); 363 ASSERT_TRUE(RunJavascriptTest("testAssertFalse"));
204 ASSERT_TRUE(RunJavascriptTest("testInitialFocus")); 364 ASSERT_TRUE(RunJavascriptTest("testInitialFocus"));
365 }
366
367 IN_PROC_BROWSER_TEST_F(WebUIBrowserTest, TestSampleFail) {
368 AddLibrary(FilePath(FILE_PATH_LITERAL("sample_failing.js")));
369
370 // Navigate to UI.
371 // TODO(dtseng): make accessor for subclasses to return?
372 ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIDownloadsURL));
373
205 ASSERT_FALSE(RunJavascriptTest("testConsoleError")); 374 ASSERT_FALSE(RunJavascriptTest("testConsoleError"));
206 } 375 }
376
377 WEB_UI_BROWSER_TEST_JS(WebUIBrowserTest, TestJSPass,
378 FILE_PATH_LITERAL("sample_passing.js")) {
379 ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIDownloadsURL));
380 }
381
382 WEB_UI_BROWSER_TEST_JS_FALSE(WebUIBrowserTest, TestJSFail,
383 FILE_PATH_LITERAL("sample_failing.js")) {
384 ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIDownloadsURL));
385 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698