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.
8 #include "base/callback.h"
9 #include "base/compiler_specific.h"
10 #include "base/files/file_path.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/run_loop.h"
14 #include "base/synchronization/lock.h"
15 #include "base/threading/thread.h"
16 #include "base/values.h"
17 #include "chrome/test/chromedriver/chrome/status.h"
18 #include "chrome/test/chromedriver/chrome/stub_chrome.h"
19 #include "chrome/test/chromedriver/chrome/stub_web_view.h"
20 #include "chrome/test/chromedriver/chrome/web_view.h"
21 #include "chrome/test/chromedriver/commands.h"
22 #include "chrome/test/chromedriver/element_commands.h"
23 #include "chrome/test/chromedriver/session.h"
24 #include "chrome/test/chromedriver/session_commands.h"
25 #include "chrome/test/chromedriver/window_commands.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 #include "third_party/webdriver/atoms.h"
31 void OnGetStatus(const Status& status,
32 scoped_ptr<base::Value> value,
33 const std::string& session_id) {
34 ASSERT_EQ(kOk, status.code());
35 base::DictionaryValue* dict;
36 ASSERT_TRUE(value->GetAsDictionary(&dict));
38 ASSERT_TRUE(dict->Get("os.name", &unused));
39 ASSERT_TRUE(dict->Get("os.version", &unused));
40 ASSERT_TRUE(dict->Get("os.arch", &unused));
41 ASSERT_TRUE(dict->Get("build.version", &unused));
46 TEST(CommandsTest, GetStatus) {
47 base::DictionaryValue params;
48 ExecuteGetStatus(params, std::string(), base::Bind(&OnGetStatus));
55 const base::DictionaryValue& params,
56 const std::string& session_id,
57 const CommandCallback& callback) {
59 EXPECT_STREQ("id", session_id.c_str());
61 EXPECT_STREQ("id2", session_id.c_str());
64 callback.Run(Status(kOk), scoped_ptr<base::Value>(), session_id);
67 void OnQuitAll(const Status& status,
68 scoped_ptr<base::Value> value,
69 const std::string& session_id) {
70 ASSERT_EQ(kOk, status.code());
71 ASSERT_FALSE(value.get());
76 TEST(CommandsTest, QuitAll) {
78 Session session("id");
79 Session session2("id2");
80 map[session.id] = make_linked_ptr(new base::Thread("1"));
81 map[session2.id] = make_linked_ptr(new base::Thread("2"));
84 Command cmd = base::Bind(&ExecuteStubQuit, &count);
85 base::DictionaryValue params;
86 base::MessageLoop loop;
87 ExecuteQuitAll(cmd, &map, params, std::string(), base::Bind(&OnQuitAll));
93 Status ExecuteSimpleCommand(
94 const std::string& expected_id,
95 base::DictionaryValue* expected_params,
98 const base::DictionaryValue& params,
99 scoped_ptr<base::Value>* return_value) {
100 EXPECT_EQ(expected_id, session->id);
101 EXPECT_TRUE(expected_params->Equals(¶ms));
102 return_value->reset(value->DeepCopy());
103 session->quit = true;
107 void OnSimpleCommand(base::RunLoop* run_loop,
108 const std::string& expected_session_id,
109 base::Value* expected_value,
110 const Status& status,
111 scoped_ptr<base::Value> value,
112 const std::string& session_id) {
113 ASSERT_EQ(kOk, status.code());
114 ASSERT_TRUE(expected_value->Equals(value.get()));
115 ASSERT_EQ(expected_session_id, session_id);
121 TEST(CommandsTest, ExecuteSessionCommand) {
122 SessionThreadMap map;
123 linked_ptr<base::Thread> thread(new base::Thread("1"));
124 ASSERT_TRUE(thread->Start());
125 std::string id("id");
126 thread->message_loop()->PostTask(
128 base::Bind(&internal::CreateSessionOnSessionThreadForTesting, id));
131 base::DictionaryValue params;
132 params.SetInteger("param", 5);
133 base::FundamentalValue expected_value(6);
134 SessionCommand cmd = base::Bind(
135 &ExecuteSimpleCommand, id, ¶ms, &expected_value);
137 base::MessageLoop loop;
138 base::RunLoop run_loop;
139 ExecuteSessionCommand(
146 base::Bind(&OnSimpleCommand, &run_loop, id, &expected_value));
152 Status ShouldNotBeCalled(
154 const base::DictionaryValue& params,
155 scoped_ptr<base::Value>* value) {
160 void OnNoSuchSession(const Status& status,
161 scoped_ptr<base::Value> value,
162 const std::string& session_id) {
163 EXPECT_EQ(kNoSuchSession, status.code());
164 EXPECT_FALSE(value.get());
167 void OnNoSuchSessionIsOk(const Status& status,
168 scoped_ptr<base::Value> value,
169 const std::string& session_id) {
170 EXPECT_EQ(kOk, status.code());
171 EXPECT_FALSE(value.get());
176 TEST(CommandsTest, ExecuteSessionCommandOnNoSuchSession) {
177 SessionThreadMap map;
178 base::DictionaryValue params;
179 ExecuteSessionCommand(&map,
181 base::Bind(&ShouldNotBeCalled),
185 base::Bind(&OnNoSuchSession));
188 TEST(CommandsTest, ExecuteSessionCommandOnNoSuchSessionWhenItExpectsOk) {
189 SessionThreadMap map;
190 base::DictionaryValue params;
191 ExecuteSessionCommand(&map,
193 base::Bind(&ShouldNotBeCalled),
197 base::Bind(&OnNoSuchSessionIsOk));
202 void OnNoSuchSessionAndQuit(base::RunLoop* run_loop,
203 const Status& status,
204 scoped_ptr<base::Value> value,
205 const std::string& session_id) {
207 EXPECT_EQ(kNoSuchSession, status.code());
208 EXPECT_FALSE(value.get());
213 TEST(CommandsTest, ExecuteSessionCommandOnJustDeletedSession) {
214 SessionThreadMap map;
215 linked_ptr<base::Thread> thread(new base::Thread("1"));
216 ASSERT_TRUE(thread->Start());
217 std::string id("id");
220 base::MessageLoop loop;
221 base::RunLoop run_loop;
222 ExecuteSessionCommand(&map,
224 base::Bind(&ShouldNotBeCalled),
226 base::DictionaryValue(),
228 base::Bind(&OnNoSuchSessionAndQuit, &run_loop));
235 kElementExistsQueryOnce = 0,
236 kElementExistsQueryTwice,
237 kElementNotExistsQueryOnce,
238 kElementExistsTimeout
241 class FindElementWebView : public StubWebView {
243 FindElementWebView(bool only_one, TestScenario scenario)
244 : StubWebView("1"), only_one_(only_one), scenario_(scenario),
247 case kElementExistsQueryOnce:
248 case kElementExistsQueryTwice:
249 case kElementExistsTimeout: {
251 base::DictionaryValue element;
252 element.SetString("ELEMENT", "1");
253 result_.reset(element.DeepCopy());
255 base::DictionaryValue element1;
256 element1.SetString("ELEMENT", "1");
257 base::DictionaryValue element2;
258 element2.SetString("ELEMENT", "2");
259 base::ListValue list;
260 list.Append(element1.DeepCopy());
261 list.Append(element2.DeepCopy());
262 result_.reset(list.DeepCopy());
266 case kElementNotExistsQueryOnce: {
268 result_.reset(base::Value::CreateNullValue());
270 result_.reset(new base::ListValue());
275 virtual ~FindElementWebView() {}
277 void Verify(const std::string& expected_frame,
278 const base::ListValue* expected_args,
279 const base::Value* actrual_result) {
280 EXPECT_EQ(expected_frame, frame_);
281 std::string function;
283 function = webdriver::atoms::asString(webdriver::atoms::FIND_ELEMENT);
285 function = webdriver::atoms::asString(webdriver::atoms::FIND_ELEMENTS);
286 EXPECT_EQ(function, function_);
287 ASSERT_TRUE(args_.get());
288 EXPECT_TRUE(expected_args->Equals(args_.get()));
289 ASSERT_TRUE(actrual_result);
290 EXPECT_TRUE(result_->Equals(actrual_result));
293 // Overridden from WebView:
294 virtual Status CallFunction(const std::string& frame,
295 const std::string& function,
296 const base::ListValue& args,
297 scoped_ptr<base::Value>* result) OVERRIDE {
299 if (scenario_ == kElementExistsTimeout ||
300 (scenario_ == kElementExistsQueryTwice && current_count_ == 1)) {
301 // Always return empty result when testing timeout.
303 result->reset(base::Value::CreateNullValue());
305 result->reset(new base::ListValue());
308 case kElementExistsQueryOnce:
309 case kElementNotExistsQueryOnce: {
310 EXPECT_EQ(1, current_count_);
313 case kElementExistsQueryTwice: {
314 EXPECT_EQ(2, current_count_);
322 result->reset(result_->DeepCopy());
324 function_ = function;
325 args_.reset(args.DeepCopy());
332 TestScenario scenario_;
335 std::string function_;
336 scoped_ptr<base::ListValue> args_;
337 scoped_ptr<base::Value> result_;
342 TEST(CommandsTest, SuccessfulFindElement) {
343 FindElementWebView web_view(true, kElementExistsQueryTwice);
344 Session session("id");
345 session.implicit_wait = base::TimeDelta::FromSeconds(1);
346 session.SwitchToSubFrame("frame_id1", std::string());
347 base::DictionaryValue params;
348 params.SetString("using", "id");
349 params.SetString("value", "a");
350 scoped_ptr<base::Value> result;
352 ExecuteFindElement(1, &session, &web_view, params, &result).code());
353 base::DictionaryValue param;
354 param.SetString("id", "a");
355 base::ListValue expected_args;
356 expected_args.Append(param.DeepCopy());
357 web_view.Verify("frame_id1", &expected_args, result.get());
360 TEST(CommandsTest, FailedFindElement) {
361 FindElementWebView web_view(true, kElementNotExistsQueryOnce);
362 Session session("id");
363 base::DictionaryValue params;
364 params.SetString("using", "id");
365 params.SetString("value", "a");
366 scoped_ptr<base::Value> result;
367 ASSERT_EQ(kNoSuchElement,
368 ExecuteFindElement(1, &session, &web_view, params, &result).code());
371 TEST(CommandsTest, SuccessfulFindElements) {
372 FindElementWebView web_view(false, kElementExistsQueryTwice);
373 Session session("id");
374 session.implicit_wait = base::TimeDelta::FromSeconds(1);
375 session.SwitchToSubFrame("frame_id2", std::string());
376 base::DictionaryValue params;
377 params.SetString("using", "name");
378 params.SetString("value", "b");
379 scoped_ptr<base::Value> result;
382 ExecuteFindElements(1, &session, &web_view, params, &result).code());
383 base::DictionaryValue param;
384 param.SetString("name", "b");
385 base::ListValue expected_args;
386 expected_args.Append(param.DeepCopy());
387 web_view.Verify("frame_id2", &expected_args, result.get());
390 TEST(CommandsTest, FailedFindElements) {
391 Session session("id");
392 FindElementWebView web_view(false, kElementNotExistsQueryOnce);
393 base::DictionaryValue params;
394 params.SetString("using", "id");
395 params.SetString("value", "a");
396 scoped_ptr<base::Value> result;
399 ExecuteFindElements(1, &session, &web_view, params, &result).code());
400 base::ListValue* list;
401 ASSERT_TRUE(result->GetAsList(&list));
402 ASSERT_EQ(0U, list->GetSize());
405 TEST(CommandsTest, SuccessfulFindChildElement) {
406 FindElementWebView web_view(true, kElementExistsQueryTwice);
407 Session session("id");
408 session.implicit_wait = base::TimeDelta::FromSeconds(1);
409 session.SwitchToSubFrame("frame_id3", std::string());
410 base::DictionaryValue params;
411 params.SetString("using", "tag name");
412 params.SetString("value", "div");
413 std::string element_id = "1";
414 scoped_ptr<base::Value> result;
417 ExecuteFindChildElement(
418 1, &session, &web_view, element_id, params, &result).code());
419 base::DictionaryValue locator_param;
420 locator_param.SetString("tag name", "div");
421 base::DictionaryValue root_element_param;
422 root_element_param.SetString("ELEMENT", element_id);
423 base::ListValue expected_args;
424 expected_args.Append(locator_param.DeepCopy());
425 expected_args.Append(root_element_param.DeepCopy());
426 web_view.Verify("frame_id3", &expected_args, result.get());
429 TEST(CommandsTest, FailedFindChildElement) {
430 Session session("id");
431 FindElementWebView web_view(true, kElementNotExistsQueryOnce);
432 base::DictionaryValue params;
433 params.SetString("using", "id");
434 params.SetString("value", "a");
435 std::string element_id = "1";
436 scoped_ptr<base::Value> result;
439 ExecuteFindChildElement(
440 1, &session, &web_view, element_id, params, &result).code());
443 TEST(CommandsTest, SuccessfulFindChildElements) {
444 FindElementWebView web_view(false, kElementExistsQueryTwice);
445 Session session("id");
446 session.implicit_wait = base::TimeDelta::FromSeconds(1);
447 session.SwitchToSubFrame("frame_id4", std::string());
448 base::DictionaryValue params;
449 params.SetString("using", "class name");
450 params.SetString("value", "c");
451 std::string element_id = "1";
452 scoped_ptr<base::Value> result;
455 ExecuteFindChildElements(
456 1, &session, &web_view, element_id, params, &result).code());
457 base::DictionaryValue locator_param;
458 locator_param.SetString("class name", "c");
459 base::DictionaryValue root_element_param;
460 root_element_param.SetString("ELEMENT", element_id);
461 base::ListValue expected_args;
462 expected_args.Append(locator_param.DeepCopy());
463 expected_args.Append(root_element_param.DeepCopy());
464 web_view.Verify("frame_id4", &expected_args, result.get());
467 TEST(CommandsTest, FailedFindChildElements) {
468 Session session("id");
469 FindElementWebView web_view(false, kElementNotExistsQueryOnce);
470 base::DictionaryValue params;
471 params.SetString("using", "id");
472 params.SetString("value", "a");
473 std::string element_id = "1";
474 scoped_ptr<base::Value> result;
477 ExecuteFindChildElements(
478 1, &session, &web_view, element_id, params, &result).code());
479 base::ListValue* list;
480 ASSERT_TRUE(result->GetAsList(&list));
481 ASSERT_EQ(0U, list->GetSize());
484 TEST(CommandsTest, TimeoutInFindElement) {
485 Session session("id");
486 FindElementWebView web_view(true, kElementExistsTimeout);
487 session.implicit_wait = base::TimeDelta::FromMilliseconds(2);
488 base::DictionaryValue params;
489 params.SetString("using", "id");
490 params.SetString("value", "a");
491 params.SetString("id", "1");
492 scoped_ptr<base::Value> result;
493 ASSERT_EQ(kNoSuchElement,
494 ExecuteFindElement(1, &session, &web_view, params, &result).code());
499 class ErrorCallFunctionWebView : public StubWebView {
501 explicit ErrorCallFunctionWebView(StatusCode code)
502 : StubWebView("1"), code_(code) {}
503 virtual ~ErrorCallFunctionWebView() {}
505 // Overridden from WebView:
506 virtual Status CallFunction(const std::string& frame,
507 const std::string& function,
508 const base::ListValue& args,
509 scoped_ptr<base::Value>* result) OVERRIDE {
510 return Status(code_);
519 TEST(CommandsTest, ErrorFindElement) {
520 Session session("id");
521 ErrorCallFunctionWebView web_view(kUnknownError);
522 base::DictionaryValue params;
523 params.SetString("using", "id");
524 params.SetString("value", "a");
525 scoped_ptr<base::Value> value;
526 ASSERT_EQ(kUnknownError,
527 ExecuteFindElement(1, &session, &web_view, params, &value).code());
528 ASSERT_EQ(kUnknownError,
529 ExecuteFindElements(1, &session, &web_view, params, &value).code());
532 TEST(CommandsTest, ErrorFindChildElement) {
533 Session session("id");
534 ErrorCallFunctionWebView web_view(kStaleElementReference);
535 base::DictionaryValue params;
536 params.SetString("using", "id");
537 params.SetString("value", "a");
538 std::string element_id = "1";
539 scoped_ptr<base::Value> result;
541 kStaleElementReference,
542 ExecuteFindChildElement(
543 1, &session, &web_view, element_id, params, &result).code());
545 kStaleElementReference,
546 ExecuteFindChildElements(
547 1, &session, &web_view, element_id, params, &result).code());