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());