1 // Copyright (c) 2013 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/chromedriver/window_commands.h"
6
7 #include <list>
8 #include <string>
9
10 #include "base/callback.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/threading/platform_thread.h"
14 #include "base/time/time.h"
15 #include "base/values.h"
16 #include "chrome/test/chromedriver/basic_types.h"
17 #include "chrome/test/chromedriver/chrome/automation_extension.h"
18 #include "chrome/test/chromedriver/chrome/chrome.h"
19 #include "chrome/test/chromedriver/chrome/chrome_desktop_impl.h"
20 #include "chrome/test/chromedriver/chrome/devtools_client.h"
21 #include "chrome/test/chromedriver/chrome/geoposition.h"
22 #include "chrome/test/chromedriver/chrome/javascript_dialog_manager.h"
23 #include "chrome/test/chromedriver/chrome/js.h"
24 #include "chrome/test/chromedriver/chrome/status.h"
25 #include "chrome/test/chromedriver/chrome/ui_events.h"
26 #include "chrome/test/chromedriver/chrome/web_view.h"
27 #include "chrome/test/chromedriver/element_util.h"
28 #include "chrome/test/chromedriver/session.h"
29 #include "chrome/test/chromedriver/util.h"
30
31 namespace {
32
GetMouseButton(const base::DictionaryValue & params,MouseButton * button)33 Status GetMouseButton(const base::DictionaryValue& params,
34 MouseButton* button) {
35 int button_num;
36 if (!params.GetInteger("button", &button_num)) {
37 button_num = 0; // Default to left mouse button.
38 } else if (button_num < 0 || button_num > 2) {
39 return Status(kUnknownError,
40 base::StringPrintf("invalid button: %d", button_num));
41 }
42 *button = static_cast<MouseButton>(button_num);
43 return Status(kOk);
44 }
45
GetUrl(WebView * web_view,const std::string & frame,std::string * url)46 Status GetUrl(WebView* web_view, const std::string& frame, std::string* url) {
47 scoped_ptr<base::Value> value;
48 base::ListValue args;
49 Status status = web_view->CallFunction(
50 frame, "function() { return document.URL; }", args, &value);
51 if (status.IsError())
52 return status;
53 if (!value->GetAsString(url))
54 return Status(kUnknownError, "javascript failed to return the url");
55 return Status(kOk);
56 }
57
58 struct Cookie {
Cookie__anon5f3e40540111::Cookie59 Cookie(const std::string& name,
60 const std::string& value,
61 const std::string& domain,
62 const std::string& path,
63 double expiry,
64 bool secure,
65 bool session)
66 : name(name), value(value), domain(domain), path(path), expiry(expiry),
67 secure(secure), session(session) {}
68
69 std::string name;
70 std::string value;
71 std::string domain;
72 std::string path;
73 double expiry;
74 bool secure;
75 bool session;
76 };
77
CreateDictionaryFrom(const Cookie & cookie)78 base::DictionaryValue* CreateDictionaryFrom(const Cookie& cookie) {
79 base::DictionaryValue* dict = new base::DictionaryValue();
80 dict->SetString("name", cookie.name);
81 dict->SetString("value", cookie.value);
82 if (!cookie.domain.empty())
83 dict->SetString("domain", cookie.domain);
84 if (!cookie.path.empty())
85 dict->SetString("path", cookie.path);
86 if (!cookie.session)
87 dict->SetDouble("expiry", cookie.expiry);
88 dict->SetBoolean("secure", cookie.secure);
89 return dict;
90 }
91
GetVisibleCookies(WebView * web_view,std::list<Cookie> * cookies)92 Status GetVisibleCookies(WebView* web_view,
93 std::list<Cookie>* cookies) {
94 scoped_ptr<base::ListValue> internal_cookies;
95 Status status = web_view->GetCookies(&internal_cookies);
96 if (status.IsError())
97 return status;
98 std::list<Cookie> cookies_tmp;
99 for (size_t i = 0; i < internal_cookies->GetSize(); ++i) {
100 base::DictionaryValue* cookie_dict;
101 if (!internal_cookies->GetDictionary(i, &cookie_dict))
102 return Status(kUnknownError, "DevTools returns a non-dictionary cookie");
103
104 std::string name;
105 cookie_dict->GetString("name", &name);
106 std::string value;
107 cookie_dict->GetString("value", &value);
108 std::string domain;
109 cookie_dict->GetString("domain", &domain);
110 std::string path;
111 cookie_dict->GetString("path", &path);
112 double expiry = 0;
113 cookie_dict->GetDouble("expires", &expiry);
114 expiry /= 1000; // Convert from millisecond to second.
115 bool session = false;
116 cookie_dict->GetBoolean("session", &session);
117 bool secure = false;
118 cookie_dict->GetBoolean("secure", &secure);
119
120 cookies_tmp.push_back(
121 Cookie(name, value, domain, path, expiry, secure, session));
122 }
123 cookies->swap(cookies_tmp);
124 return Status(kOk);
125 }
126
ScrollCoordinateInToView(Session * session,WebView * web_view,int x,int y,int * offset_x,int * offset_y)127 Status ScrollCoordinateInToView(
128 Session* session, WebView* web_view, int x, int y, int* offset_x,
129 int* offset_y) {
130 scoped_ptr<base::Value> value;
131 base::ListValue args;
132 args.AppendInteger(x);
133 args.AppendInteger(y);
134 Status status = web_view->CallFunction(
135 std::string(),
136 "function(x, y) {"
137 " if (x < window.pageXOffset ||"
138 " x >= window.pageXOffset + window.innerWidth ||"
139 " y < window.pageYOffset ||"
140 " y >= window.pageYOffset + window.innerHeight) {"
141 " window.scrollTo(x - window.innerWidth/2, y - window.innerHeight/2);"
142 " }"
143 " return {"
144 " view_x: Math.floor(window.pageXOffset),"
145 " view_y: Math.floor(window.pageYOffset),"
146 " view_width: Math.floor(window.innerWidth),"
147 " view_height: Math.floor(window.innerHeight)};"
148 "}",
149 args,
150 &value);
151 if (!status.IsOk())
152 return status;
153 base::DictionaryValue* view_attrib;
154 value->GetAsDictionary(&view_attrib);
155 int view_x, view_y, view_width, view_height;
156 view_attrib->GetInteger("view_x", &view_x);
157 view_attrib->GetInteger("view_y", &view_y);
158 view_attrib->GetInteger("view_width", &view_width);
159 view_attrib->GetInteger("view_height", &view_height);
160 *offset_x = x - view_x;
161 *offset_y = y - view_y;
162 if (*offset_x < 0 || *offset_x >= view_width || *offset_y < 0 ||
163 *offset_y >= view_height)
164 return Status(kUnknownError, "Failed to scroll coordinate into view");
165 return Status(kOk);
166 }
167
ExecuteTouchEvent(Session * session,WebView * web_view,TouchEventType type,const base::DictionaryValue & params)168 Status ExecuteTouchEvent(
169 Session* session, WebView* web_view, TouchEventType type,
170 const base::DictionaryValue& params) {
171 int x, y;
172 if (!params.GetInteger("x", &x))
173 return Status(kUnknownError, "'x' must be an integer");
174 if (!params.GetInteger("y", &y))
175 return Status(kUnknownError, "'y' must be an integer");
176 int relative_x = x;
177 int relative_y = y;
178 Status status = ScrollCoordinateInToView(
179 session, web_view, x, y, &relative_x, &relative_y);
180 if (!status.IsOk())
181 return status;
182 std::list<TouchEvent> events;
183 events.push_back(
184 TouchEvent(type, relative_x, relative_y));
185 return web_view->DispatchTouchEvents(events);
186 }
187
188 } // namespace
189
ExecuteWindowCommand(const WindowCommand & command,Session * session,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)190 Status ExecuteWindowCommand(
191 const WindowCommand& command,
192 Session* session,
193 const base::DictionaryValue& params,
194 scoped_ptr<base::Value>* value) {
195 WebView* web_view = NULL;
196 Status status = session->GetTargetWindow(&web_view);
197 if (status.IsError())
198 return status;
199
200 status = web_view->ConnectIfNecessary();
201 if (status.IsError())
202 return status;
203
204 status = web_view->HandleReceivedEvents();
205 if (status.IsError())
206 return status;
207
208 if (web_view->GetJavaScriptDialogManager()->IsDialogOpen())
209 return Status(kUnexpectedAlertOpen);
210
211 Status nav_status(kOk);
212 for (int attempt = 0; attempt < 2; attempt++) {
213 if (attempt == 1) {
214 if (status.code() == kNoSuchExecutionContext)
215 // Switch to main frame and retry command if subframe no longer exists.
216 session->SwitchToTopFrame();
217 else
218 break;
219 }
220 nav_status = web_view->WaitForPendingNavigations(
221 session->GetCurrentFrameId(), session->page_load_timeout, true);
222 if (nav_status.IsError())
223 return nav_status;
224
225 status = command.Run(session, web_view, params, value);
226 }
227
228 nav_status = web_view->WaitForPendingNavigations(
229 session->GetCurrentFrameId(), session->page_load_timeout, true);
230
231 if (status.IsOk() && nav_status.IsError() &&
232 nav_status.code() != kUnexpectedAlertOpen)
233 return nav_status;
234 if (status.code() == kUnexpectedAlertOpen)
235 return Status(kOk);
236 return status;
237 }
238
ExecuteGet(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)239 Status ExecuteGet(
240 Session* session,
241 WebView* web_view,
242 const base::DictionaryValue& params,
243 scoped_ptr<base::Value>* value) {
244 std::string url;
245 if (!params.GetString("url", &url))
246 return Status(kUnknownError, "'url' must be a string");
247 return web_view->Load(url);
248 }
249
ExecuteExecuteScript(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)250 Status ExecuteExecuteScript(
251 Session* session,
252 WebView* web_view,
253 const base::DictionaryValue& params,
254 scoped_ptr<base::Value>* value) {
255 std::string script;
256 if (!params.GetString("script", &script))
257 return Status(kUnknownError, "'script' must be a string");
258 if (script == ":takeHeapSnapshot") {
259 return web_view->TakeHeapSnapshot(value);
260 } else if (script == ":startProfile") {
261 return web_view->StartProfile();
262 } else if (script == ":endProfile") {
263 return web_view->EndProfile(value);
264 } else {
265 const base::ListValue* args;
266 if (!params.GetList("args", &args))
267 return Status(kUnknownError, "'args' must be a list");
268
269 return web_view->CallFunction(session->GetCurrentFrameId(),
270 "function(){" + script + "}", *args, value);
271 }
272 }
273
ExecuteExecuteAsyncScript(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)274 Status ExecuteExecuteAsyncScript(
275 Session* session,
276 WebView* web_view,
277 const base::DictionaryValue& params,
278 scoped_ptr<base::Value>* value) {
279 std::string script;
280 if (!params.GetString("script", &script))
281 return Status(kUnknownError, "'script' must be a string");
282 const base::ListValue* args;
283 if (!params.GetList("args", &args))
284 return Status(kUnknownError, "'args' must be a list");
285
286 return web_view->CallUserAsyncFunction(
287 session->GetCurrentFrameId(), "function(){" + script + "}", *args,
288 session->script_timeout, value);
289 }
290
ExecuteSwitchToFrame(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)291 Status ExecuteSwitchToFrame(
292 Session* session,
293 WebView* web_view,
294 const base::DictionaryValue& params,
295 scoped_ptr<base::Value>* value) {
296 const base::Value* id;
297 if (!params.Get("id", &id))
298 return Status(kUnknownError, "missing 'id'");
299
300 if (id->IsType(base::Value::TYPE_NULL)) {
301 session->SwitchToTopFrame();
302 return Status(kOk);
303 }
304
305 std::string script;
306 base::ListValue args;
307 const base::DictionaryValue* id_dict;
308 if (id->GetAsDictionary(&id_dict)) {
309 script = "function(elem) { return elem; }";
310 args.Append(id_dict->DeepCopy());
311 } else {
312 script =
313 "function(xpath) {"
314 " return document.evaluate(xpath, document, null, "
315 " XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;"
316 "}";
317 std::string xpath = "(/html/body//iframe|/html/frameset/frame)";
318 std::string id_string;
319 int id_int;
320 if (id->GetAsString(&id_string)) {
321 xpath += base::StringPrintf(
322 "[@name=\"%s\" or @id=\"%s\"]", id_string.c_str(), id_string.c_str());
323 } else if (id->GetAsInteger(&id_int)) {
324 xpath += base::StringPrintf("[%d]", id_int + 1);
325 } else {
326 return Status(kUnknownError, "invalid 'id'");
327 }
328 args.Append(new base::StringValue(xpath));
329 }
330 std::string frame;
331 Status status = web_view->GetFrameByFunction(
332 session->GetCurrentFrameId(), script, args, &frame);
333 if (status.IsError())
334 return status;
335
336 scoped_ptr<base::Value> result;
337 status = web_view->CallFunction(
338 session->GetCurrentFrameId(), script, args, &result);
339 if (status.IsError())
340 return status;
341 const base::DictionaryValue* element;
342 if (!result->GetAsDictionary(&element))
343 return Status(kUnknownError, "fail to locate the sub frame element");
344
345 std::string chrome_driver_id = GenerateId();
346 const char* kSetFrameIdentifier =
347 "function(frame, id) {"
348 " frame.setAttribute('cd_frame_id_', id);"
349 "}";
350 base::ListValue new_args;
351 new_args.Append(element->DeepCopy());
352 new_args.AppendString(chrome_driver_id);
353 result.reset(NULL);
354 status = web_view->CallFunction(
355 session->GetCurrentFrameId(), kSetFrameIdentifier, new_args, &result);
356 if (status.IsError())
357 return status;
358 session->SwitchToSubFrame(frame, chrome_driver_id);
359 return Status(kOk);
360 }
361
ExecuteSwitchToParentFrame(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)362 Status ExecuteSwitchToParentFrame(
363 Session* session,
364 WebView* web_view,
365 const base::DictionaryValue& params,
366 scoped_ptr<base::Value>* value) {
367 session->SwitchToParentFrame();
368 return Status(kOk);
369 }
370
ExecuteGetTitle(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)371 Status ExecuteGetTitle(
372 Session* session,
373 WebView* web_view,
374 const base::DictionaryValue& params,
375 scoped_ptr<base::Value>* value) {
376 const char* kGetTitleScript =
377 "function() {"
378 " if (document.title)"
379 " return document.title;"
380 " else"
381 " return document.URL;"
382 "}";
383 base::ListValue args;
384 return web_view->CallFunction(std::string(), kGetTitleScript, args, value);
385 }
386
ExecuteGetPageSource(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)387 Status ExecuteGetPageSource(
388 Session* session,
389 WebView* web_view,
390 const base::DictionaryValue& params,
391 scoped_ptr<base::Value>* value) {
392 const char* kGetPageSource =
393 "function() {"
394 " return new XMLSerializer().serializeToString(document);"
395 "}";
396 base::ListValue args;
397 return web_view->CallFunction(
398 session->GetCurrentFrameId(), kGetPageSource, args, value);
399 }
400
ExecuteFindElement(int interval_ms,Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)401 Status ExecuteFindElement(
402 int interval_ms,
403 Session* session,
404 WebView* web_view,
405 const base::DictionaryValue& params,
406 scoped_ptr<base::Value>* value) {
407 return FindElement(interval_ms, true, NULL, session, web_view, params, value);
408 }
409
ExecuteFindElements(int interval_ms,Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)410 Status ExecuteFindElements(
411 int interval_ms,
412 Session* session,
413 WebView* web_view,
414 const base::DictionaryValue& params,
415 scoped_ptr<base::Value>* value) {
416 return FindElement(
417 interval_ms, false, NULL, session, web_view, params, value);
418 }
419
ExecuteGetCurrentUrl(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)420 Status ExecuteGetCurrentUrl(
421 Session* session,
422 WebView* web_view,
423 const base::DictionaryValue& params,
424 scoped_ptr<base::Value>* value) {
425 std::string url;
426 Status status = GetUrl(web_view, session->GetCurrentFrameId(), &url);
427 if (status.IsError())
428 return status;
429 value->reset(new base::StringValue(url));
430 return Status(kOk);
431 }
432
ExecuteGoBack(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)433 Status ExecuteGoBack(
434 Session* session,
435 WebView* web_view,
436 const base::DictionaryValue& params,
437 scoped_ptr<base::Value>* value) {
438 return web_view->EvaluateScript(
439 std::string(), "window.history.back();", value);
440 }
441
ExecuteGoForward(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)442 Status ExecuteGoForward(
443 Session* session,
444 WebView* web_view,
445 const base::DictionaryValue& params,
446 scoped_ptr<base::Value>* value) {
447 return web_view->EvaluateScript(
448 std::string(), "window.history.forward();", value);
449 }
450
ExecuteRefresh(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)451 Status ExecuteRefresh(
452 Session* session,
453 WebView* web_view,
454 const base::DictionaryValue& params,
455 scoped_ptr<base::Value>* value) {
456 return web_view->Reload();
457 }
458
ExecuteMouseMoveTo(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)459 Status ExecuteMouseMoveTo(
460 Session* session,
461 WebView* web_view,
462 const base::DictionaryValue& params,
463 scoped_ptr<base::Value>* value) {
464 std::string element_id;
465 bool has_element = params.GetString("element", &element_id);
466 int x_offset = 0;
467 int y_offset = 0;
468 bool has_offset = params.GetInteger("xoffset", &x_offset) &&
469 params.GetInteger("yoffset", &y_offset);
470 if (!has_element && !has_offset)
471 return Status(kUnknownError, "at least an element or offset should be set");
472
473 WebPoint location;
474 if (has_element) {
475 Status status = ScrollElementIntoView(
476 session, web_view, element_id, &location);
477 if (status.IsError())
478 return status;
479 } else {
480 location = session->mouse_position;
481 }
482
483 if (has_offset) {
484 location.Offset(x_offset, y_offset);
485 } else {
486 WebSize size;
487 Status status = GetElementSize(session, web_view, element_id, &size);
488 if (status.IsError())
489 return status;
490 location.Offset(size.width / 2, size.height / 2);
491 }
492
493 std::list<MouseEvent> events;
494 events.push_back(
495 MouseEvent(kMovedMouseEventType, kNoneMouseButton,
496 location.x, location.y, session->sticky_modifiers, 0));
497 Status status =
498 web_view->DispatchMouseEvents(events, session->GetCurrentFrameId());
499 if (status.IsOk())
500 session->mouse_position = location;
501 return status;
502 }
503
ExecuteMouseClick(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)504 Status ExecuteMouseClick(
505 Session* session,
506 WebView* web_view,
507 const base::DictionaryValue& params,
508 scoped_ptr<base::Value>* value) {
509 MouseButton button;
510 Status status = GetMouseButton(params, &button);
511 if (status.IsError())
512 return status;
513 std::list<MouseEvent> events;
514 events.push_back(
515 MouseEvent(kPressedMouseEventType, button,
516 session->mouse_position.x, session->mouse_position.y,
517 session->sticky_modifiers, 1));
518 events.push_back(
519 MouseEvent(kReleasedMouseEventType, button,
520 session->mouse_position.x, session->mouse_position.y,
521 session->sticky_modifiers, 1));
522 return web_view->DispatchMouseEvents(events, session->GetCurrentFrameId());
523 }
524
ExecuteMouseButtonDown(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)525 Status ExecuteMouseButtonDown(
526 Session* session,
527 WebView* web_view,
528 const base::DictionaryValue& params,
529 scoped_ptr<base::Value>* value) {
530 MouseButton button;
531 Status status = GetMouseButton(params, &button);
532 if (status.IsError())
533 return status;
534 std::list<MouseEvent> events;
535 events.push_back(
536 MouseEvent(kPressedMouseEventType, button,
537 session->mouse_position.x, session->mouse_position.y,
538 session->sticky_modifiers, 1));
539 return web_view->DispatchMouseEvents(events, session->GetCurrentFrameId());
540 }
541
ExecuteMouseButtonUp(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)542 Status ExecuteMouseButtonUp(
543 Session* session,
544 WebView* web_view,
545 const base::DictionaryValue& params,
546 scoped_ptr<base::Value>* value) {
547 MouseButton button;
548 Status status = GetMouseButton(params, &button);
549 if (status.IsError())
550 return status;
551 std::list<MouseEvent> events;
552 events.push_back(
553 MouseEvent(kReleasedMouseEventType, button,
554 session->mouse_position.x, session->mouse_position.y,
555 session->sticky_modifiers, 1));
556 return web_view->DispatchMouseEvents(events, session->GetCurrentFrameId());
557 }
558
ExecuteMouseDoubleClick(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)559 Status ExecuteMouseDoubleClick(
560 Session* session,
561 WebView* web_view,
562 const base::DictionaryValue& params,
563 scoped_ptr<base::Value>* value) {
564 MouseButton button;
565 Status status = GetMouseButton(params, &button);
566 if (status.IsError())
567 return status;
568 std::list<MouseEvent> events;
569 events.push_back(
570 MouseEvent(kPressedMouseEventType, button,
571 session->mouse_position.x, session->mouse_position.y,
572 session->sticky_modifiers, 2));
573 events.push_back(
574 MouseEvent(kReleasedMouseEventType, button,
575 session->mouse_position.x, session->mouse_position.y,
576 session->sticky_modifiers, 2));
577 return web_view->DispatchMouseEvents(events, session->GetCurrentFrameId());
578 }
579
ExecuteTouchDown(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)580 Status ExecuteTouchDown(
581 Session* session,
582 WebView* web_view,
583 const base::DictionaryValue& params,
584 scoped_ptr<base::Value>* value) {
585 return ExecuteTouchEvent(session, web_view, kTouchStart, params);
586 }
587
ExecuteTouchUp(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)588 Status ExecuteTouchUp(
589 Session* session,
590 WebView* web_view,
591 const base::DictionaryValue& params,
592 scoped_ptr<base::Value>* value) {
593 return ExecuteTouchEvent(session, web_view, kTouchEnd, params);
594 }
595
ExecuteTouchMove(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)596 Status ExecuteTouchMove(
597 Session* session,
598 WebView* web_view,
599 const base::DictionaryValue& params,
600 scoped_ptr<base::Value>* value) {
601 return ExecuteTouchEvent(session, web_view, kTouchMove, params);
602 }
603
ExecuteGetActiveElement(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)604 Status ExecuteGetActiveElement(
605 Session* session,
606 WebView* web_view,
607 const base::DictionaryValue& params,
608 scoped_ptr<base::Value>* value) {
609 return GetActiveElement(session, web_view, value);
610 }
611
ExecuteSendKeysToActiveElement(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)612 Status ExecuteSendKeysToActiveElement(
613 Session* session,
614 WebView* web_view,
615 const base::DictionaryValue& params,
616 scoped_ptr<base::Value>* value) {
617 const base::ListValue* key_list;
618 if (!params.GetList("value", &key_list))
619 return Status(kUnknownError, "'value' must be a list");
620 return SendKeysOnWindow(
621 web_view, key_list, false, &session->sticky_modifiers);
622 }
623
ExecuteGetAppCacheStatus(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)624 Status ExecuteGetAppCacheStatus(
625 Session* session,
626 WebView* web_view,
627 const base::DictionaryValue& params,
628 scoped_ptr<base::Value>* value) {
629 return web_view->EvaluateScript(
630 session->GetCurrentFrameId(),
631 "applicationCache.status",
632 value);
633 }
634
ExecuteIsBrowserOnline(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)635 Status ExecuteIsBrowserOnline(
636 Session* session,
637 WebView* web_view,
638 const base::DictionaryValue& params,
639 scoped_ptr<base::Value>* value) {
640 return web_view->EvaluateScript(
641 session->GetCurrentFrameId(),
642 "navigator.onLine",
643 value);
644 }
645
ExecuteGetStorageItem(const char * storage,Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)646 Status ExecuteGetStorageItem(
647 const char* storage,
648 Session* session,
649 WebView* web_view,
650 const base::DictionaryValue& params,
651 scoped_ptr<base::Value>* value) {
652 std::string key;
653 if (!params.GetString("key", &key))
654 return Status(kUnknownError, "'key' must be a string");
655 base::ListValue args;
656 args.Append(new base::StringValue(key));
657 return web_view->CallFunction(
658 session->GetCurrentFrameId(),
659 base::StringPrintf("function(key) { return %s[key]; }", storage),
660 args,
661 value);
662 }
663
ExecuteGetStorageKeys(const char * storage,Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)664 Status ExecuteGetStorageKeys(
665 const char* storage,
666 Session* session,
667 WebView* web_view,
668 const base::DictionaryValue& params,
669 scoped_ptr<base::Value>* value) {
670 const char script[] =
671 "var keys = [];"
672 "for (var key in %s) {"
673 " keys.push(key);"
674 "}"
675 "keys";
676 return web_view->EvaluateScript(
677 session->GetCurrentFrameId(),
678 base::StringPrintf(script, storage),
679 value);
680 }
681
ExecuteSetStorageItem(const char * storage,Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)682 Status ExecuteSetStorageItem(
683 const char* storage,
684 Session* session,
685 WebView* web_view,
686 const base::DictionaryValue& params,
687 scoped_ptr<base::Value>* value) {
688 std::string key;
689 if (!params.GetString("key", &key))
690 return Status(kUnknownError, "'key' must be a string");
691 std::string storage_value;
692 if (!params.GetString("value", &storage_value))
693 return Status(kUnknownError, "'value' must be a string");
694 base::ListValue args;
695 args.Append(new base::StringValue(key));
696 args.Append(new base::StringValue(storage_value));
697 return web_view->CallFunction(
698 session->GetCurrentFrameId(),
699 base::StringPrintf("function(key, value) { %s[key] = value; }", storage),
700 args,
701 value);
702 }
703
ExecuteRemoveStorageItem(const char * storage,Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)704 Status ExecuteRemoveStorageItem(
705 const char* storage,
706 Session* session,
707 WebView* web_view,
708 const base::DictionaryValue& params,
709 scoped_ptr<base::Value>* value) {
710 std::string key;
711 if (!params.GetString("key", &key))
712 return Status(kUnknownError, "'key' must be a string");
713 base::ListValue args;
714 args.Append(new base::StringValue(key));
715 return web_view->CallFunction(
716 session->GetCurrentFrameId(),
717 base::StringPrintf("function(key) { %s.removeItem(key) }", storage),
718 args,
719 value);
720 }
721
ExecuteClearStorage(const char * storage,Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)722 Status ExecuteClearStorage(
723 const char* storage,
724 Session* session,
725 WebView* web_view,
726 const base::DictionaryValue& params,
727 scoped_ptr<base::Value>* value) {
728 return web_view->EvaluateScript(
729 session->GetCurrentFrameId(),
730 base::StringPrintf("%s.clear()", storage),
731 value);
732 }
733
ExecuteGetStorageSize(const char * storage,Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)734 Status ExecuteGetStorageSize(
735 const char* storage,
736 Session* session,
737 WebView* web_view,
738 const base::DictionaryValue& params,
739 scoped_ptr<base::Value>* value) {
740 return web_view->EvaluateScript(
741 session->GetCurrentFrameId(),
742 base::StringPrintf("%s.length", storage),
743 value);
744 }
745
ExecuteScreenshot(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)746 Status ExecuteScreenshot(
747 Session* session,
748 WebView* web_view,
749 const base::DictionaryValue& params,
750 scoped_ptr<base::Value>* value) {
751 Status status = session->chrome->ActivateWebView(web_view->GetId());
752 if (status.IsError())
753 return status;
754
755 std::string screenshot;
756 if (session->chrome->GetAsDesktop() && !session->force_devtools_screenshot) {
757 AutomationExtension* extension = NULL;
758 status =
759 session->chrome->GetAsDesktop()->GetAutomationExtension(&extension);
760 if (status.IsError())
761 return status;
762 status = extension->CaptureScreenshot(&screenshot);
763 // If the screenshot was forbidden, fallback to DevTools.
764 if (status.code() == kForbidden)
765 status = web_view->CaptureScreenshot(&screenshot);
766 } else {
767 status = web_view->CaptureScreenshot(&screenshot);
768 }
769 if (status.IsError())
770 return status;
771
772 value->reset(new base::StringValue(screenshot));
773 return Status(kOk);
774 }
775
ExecuteGetCookies(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)776 Status ExecuteGetCookies(
777 Session* session,
778 WebView* web_view,
779 const base::DictionaryValue& params,
780 scoped_ptr<base::Value>* value) {
781 std::list<Cookie> cookies;
782 Status status = GetVisibleCookies(web_view, &cookies);
783 if (status.IsError())
784 return status;
785 scoped_ptr<base::ListValue> cookie_list(new base::ListValue());
786 for (std::list<Cookie>::const_iterator it = cookies.begin();
787 it != cookies.end(); ++it) {
788 cookie_list->Append(CreateDictionaryFrom(*it));
789 }
790 value->reset(cookie_list.release());
791 return Status(kOk);
792 }
793
ExecuteAddCookie(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)794 Status ExecuteAddCookie(
795 Session* session,
796 WebView* web_view,
797 const base::DictionaryValue& params,
798 scoped_ptr<base::Value>* value) {
799 const base::DictionaryValue* cookie;
800 if (!params.GetDictionary("cookie", &cookie))
801 return Status(kUnknownError, "missing 'cookie'");
802 base::ListValue args;
803 args.Append(cookie->DeepCopy());
804 scoped_ptr<base::Value> result;
805 return web_view->CallFunction(
806 session->GetCurrentFrameId(), kAddCookieScript, args, &result);
807 }
808
ExecuteDeleteCookie(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)809 Status ExecuteDeleteCookie(
810 Session* session,
811 WebView* web_view,
812 const base::DictionaryValue& params,
813 scoped_ptr<base::Value>* value) {
814 std::string name;
815 if (!params.GetString("name", &name))
816 return Status(kUnknownError, "missing 'name'");
817 base::DictionaryValue params_url;
818 scoped_ptr<base::Value> value_url;
819 std::string url;
820 Status status = GetUrl(web_view, session->GetCurrentFrameId(), &url);
821 if (status.IsError())
822 return status;
823 return web_view->DeleteCookie(name, url);
824 }
825
ExecuteDeleteAllCookies(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)826 Status ExecuteDeleteAllCookies(
827 Session* session,
828 WebView* web_view,
829 const base::DictionaryValue& params,
830 scoped_ptr<base::Value>* value) {
831 std::list<Cookie> cookies;
832 Status status = GetVisibleCookies(web_view, &cookies);
833 if (status.IsError())
834 return status;
835
836 if (!cookies.empty()) {
837 base::DictionaryValue params_url;
838 scoped_ptr<base::Value> value_url;
839 std::string url;
840 status = GetUrl(web_view, session->GetCurrentFrameId(), &url);
841 if (status.IsError())
842 return status;
843 for (std::list<Cookie>::const_iterator it = cookies.begin();
844 it != cookies.end(); ++it) {
845 status = web_view->DeleteCookie(it->name, url);
846 if (status.IsError())
847 return status;
848 }
849 }
850
851 return Status(kOk);
852 }
853
ExecuteSetLocation(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)854 Status ExecuteSetLocation(
855 Session* session,
856 WebView* web_view,
857 const base::DictionaryValue& params,
858 scoped_ptr<base::Value>* value) {
859 const base::DictionaryValue* location = NULL;
860 Geoposition geoposition;
861 if (!params.GetDictionary("location", &location) ||
862 !location->GetDouble("latitude", &geoposition.latitude) ||
863 !location->GetDouble("longitude", &geoposition.longitude))
864 return Status(kUnknownError, "missing or invalid 'location'");
865 if (location->HasKey("accuracy") &&
866 !location->GetDouble("accuracy", &geoposition.accuracy)) {
867 return Status(kUnknownError, "invalid 'accuracy'");
868 } else {
869 // |accuracy| is not part of the WebDriver spec yet, so if it is not given
870 // default to 100 meters accuracy.
871 geoposition.accuracy = 100;
872 }
873
874 Status status = web_view->OverrideGeolocation(geoposition);
875 if (status.IsOk())
876 session->overridden_geoposition.reset(new Geoposition(geoposition));
877 return status;
878 }
879
ExecuteTakeHeapSnapshot(Session * session,WebView * web_view,const base::DictionaryValue & params,scoped_ptr<base::Value> * value)880 Status ExecuteTakeHeapSnapshot(
881 Session* session,
882 WebView* web_view,
883 const base::DictionaryValue& params,
884 scoped_ptr<base::Value>* value) {
885 return web_view->TakeHeapSnapshot(value);
886 }
887