Move render_view_context_menu.* and related files out of tab_contents.
[chromium-blink-merge.git] / chrome / test / chromedriver / element_commands.cc
blobac7585d64341a3d6670c70bbd73ea78a7a6a059b
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.
5 #include "chrome/test/chromedriver/element_commands.h"
7 #include <cmath>
8 #include <list>
9 #include <vector>
11 #include "base/callback.h"
12 #include "base/files/file_path.h"
13 #include "base/strings/string_split.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/threading/platform_thread.h"
16 #include "base/time/time.h"
17 #include "base/values.h"
18 #include "chrome/test/chromedriver/basic_types.h"
19 #include "chrome/test/chromedriver/chrome/chrome.h"
20 #include "chrome/test/chromedriver/chrome/js.h"
21 #include "chrome/test/chromedriver/chrome/status.h"
22 #include "chrome/test/chromedriver/chrome/ui_events.h"
23 #include "chrome/test/chromedriver/chrome/web_view.h"
24 #include "chrome/test/chromedriver/element_util.h"
25 #include "chrome/test/chromedriver/session.h"
26 #include "chrome/test/chromedriver/util.h"
27 #include "third_party/webdriver/atoms.h"
29 const int kFlickTouchEventsPerSecond = 30;
31 namespace {
33 Status SendKeysToElement(
34 Session* session,
35 WebView* web_view,
36 const std::string& element_id,
37 const base::ListValue* key_list) {
38 bool is_displayed = false;
39 bool is_focused = false;
40 base::TimeTicks start_time = base::TimeTicks::Now();
41 while (true) {
42 Status status = IsElementDisplayed(
43 session, web_view, element_id, true, &is_displayed);
44 if (status.IsError())
45 return status;
46 if (is_displayed)
47 break;
48 status = IsElementFocused(session, web_view, element_id, &is_focused);
49 if (status.IsError())
50 return status;
51 if (is_focused)
52 break;
53 if (base::TimeTicks::Now() - start_time >= session->implicit_wait) {
54 return Status(kElementNotVisible);
56 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
59 bool is_enabled = false;
60 Status status = IsElementEnabled(session, web_view, element_id, &is_enabled);
61 if (status.IsError())
62 return status;
63 if (!is_enabled)
64 return Status(kInvalidElementState);
66 if (!is_focused) {
67 base::ListValue args;
68 args.Append(CreateElement(element_id));
69 scoped_ptr<base::Value> result;
70 status = web_view->CallFunction(
71 session->GetCurrentFrameId(), kFocusScript, args, &result);
72 if (status.IsError())
73 return status;
76 return SendKeysOnWindow(web_view, key_list, true, &session->sticky_modifiers);
79 Status ExecuteTouchSingleTapAtom(
80 Session* session,
81 WebView* web_view,
82 const std::string& element_id,
83 const base::DictionaryValue& params,
84 scoped_ptr<base::Value>* value) {
85 base::ListValue args;
86 args.Append(CreateElement(element_id));
87 return web_view->CallFunction(
88 session->GetCurrentFrameId(),
89 webdriver::atoms::asString(webdriver::atoms::TOUCH_SINGLE_TAP),
90 args,
91 value);
94 } // namespace
96 Status ExecuteElementCommand(
97 const ElementCommand& command,
98 Session* session,
99 WebView* web_view,
100 const base::DictionaryValue& params,
101 scoped_ptr<base::Value>* value) {
102 std::string id;
103 if (params.GetString("id", &id) || params.GetString("element", &id))
104 return command.Run(session, web_view, id, params, value);
105 return Status(kUnknownError, "element identifier must be a string");
108 Status ExecuteFindChildElement(
109 int interval_ms,
110 Session* session,
111 WebView* web_view,
112 const std::string& element_id,
113 const base::DictionaryValue& params,
114 scoped_ptr<base::Value>* value) {
115 return FindElement(
116 interval_ms, true, &element_id, session, web_view, params, value);
119 Status ExecuteFindChildElements(
120 int interval_ms,
121 Session* session,
122 WebView* web_view,
123 const std::string& element_id,
124 const base::DictionaryValue& params,
125 scoped_ptr<base::Value>* value) {
126 return FindElement(
127 interval_ms, false, &element_id, session, web_view, params, value);
130 Status ExecuteHoverOverElement(
131 Session* session,
132 WebView* web_view,
133 const std::string& element_id,
134 const base::DictionaryValue& params,
135 scoped_ptr<base::Value>* value) {
136 WebPoint location;
137 Status status = GetElementClickableLocation(
138 session, web_view, element_id, &location);
139 if (status.IsError())
140 return status;
142 MouseEvent move_event(
143 kMovedMouseEventType, kNoneMouseButton, location.x, location.y,
144 session->sticky_modifiers, 0);
145 std::list<MouseEvent> events;
146 events.push_back(move_event);
147 status = web_view->DispatchMouseEvents(events, session->GetCurrentFrameId());
148 if (status.IsOk())
149 session->mouse_position = location;
150 return status;
153 Status ExecuteClickElement(
154 Session* session,
155 WebView* web_view,
156 const std::string& element_id,
157 const base::DictionaryValue& params,
158 scoped_ptr<base::Value>* value) {
159 std::string tag_name;
160 Status status = GetElementTagName(session, web_view, element_id, &tag_name);
161 if (status.IsError())
162 return status;
163 if (tag_name == "option") {
164 bool is_toggleable;
165 status = IsOptionElementTogglable(
166 session, web_view, element_id, &is_toggleable);
167 if (status.IsError())
168 return status;
169 if (is_toggleable)
170 return ToggleOptionElement(session, web_view, element_id);
171 else
172 return SetOptionElementSelected(session, web_view, element_id, true);
173 } else {
174 WebPoint location;
175 status = GetElementClickableLocation(
176 session, web_view, element_id, &location);
177 if (status.IsError())
178 return status;
180 std::list<MouseEvent> events;
181 events.push_back(
182 MouseEvent(kMovedMouseEventType, kNoneMouseButton,
183 location.x, location.y, session->sticky_modifiers, 0));
184 events.push_back(
185 MouseEvent(kPressedMouseEventType, kLeftMouseButton,
186 location.x, location.y, session->sticky_modifiers, 1));
187 events.push_back(
188 MouseEvent(kReleasedMouseEventType, kLeftMouseButton,
189 location.x, location.y, session->sticky_modifiers, 1));
190 status =
191 web_view->DispatchMouseEvents(events, session->GetCurrentFrameId());
192 if (status.IsOk())
193 session->mouse_position = location;
194 return status;
198 Status ExecuteTouchSingleTap(
199 Session* session,
200 WebView* web_view,
201 const std::string& element_id,
202 const base::DictionaryValue& params,
203 scoped_ptr<base::Value>* value) {
204 // Fall back to javascript atom for pre-m30 Chrome.
205 if (session->chrome->GetBuildNo() < 1576)
206 return ExecuteTouchSingleTapAtom(
207 session, web_view, element_id, params, value);
209 WebPoint location;
210 Status status = GetElementClickableLocation(
211 session, web_view, element_id, &location);
212 if (status.IsError())
213 return status;
215 std::list<TouchEvent> events;
216 events.push_back(
217 TouchEvent(kTouchStart, location.x, location.y));
218 events.push_back(
219 TouchEvent(kTouchEnd, location.x, location.y));
220 return web_view->DispatchTouchEvents(events);
223 Status ExecuteFlick(
224 Session* session,
225 WebView* web_view,
226 const std::string& element_id,
227 const base::DictionaryValue& params,
228 scoped_ptr<base::Value>* value) {
229 WebPoint location;
230 Status status = GetElementClickableLocation(
231 session, web_view, element_id, &location);
232 if (status.IsError())
233 return status;
235 int xoffset, yoffset, speed;
236 if (!params.GetInteger("xoffset", &xoffset))
237 return Status(kUnknownError, "'xoffset' must be an integer");
238 if (!params.GetInteger("yoffset", &yoffset))
239 return Status(kUnknownError, "'yoffset' must be an integer");
240 if (!params.GetInteger("speed", &speed))
241 return Status(kUnknownError, "'speed' must be an integer");
242 if (speed < 1)
243 return Status(kUnknownError, "'speed' must be a positive integer");
245 status = web_view->DispatchTouchEvent(
246 TouchEvent(kTouchStart, location.x, location.y));
247 if (status.IsError())
248 return status;
250 const double offset =
251 std::sqrt(static_cast<double>(xoffset * xoffset + yoffset * yoffset));
252 const double xoffset_per_event =
253 (speed * xoffset) / (kFlickTouchEventsPerSecond * offset);
254 const double yoffset_per_event =
255 (speed * yoffset) / (kFlickTouchEventsPerSecond * offset);
256 const int total_events =
257 (offset * kFlickTouchEventsPerSecond) / speed;
258 for (int i = 0; i < total_events; i++) {
259 status = web_view->DispatchTouchEvent(
260 TouchEvent(kTouchMove,
261 location.x + xoffset_per_event * i,
262 location.y + yoffset_per_event * i));
263 if (status.IsError())
264 return status;
265 base::PlatformThread::Sleep(
266 base::TimeDelta::FromMilliseconds(1000 / kFlickTouchEventsPerSecond));
268 return web_view->DispatchTouchEvent(
269 TouchEvent(kTouchEnd, location.x + xoffset, location.y + yoffset));
272 Status ExecuteClearElement(
273 Session* session,
274 WebView* web_view,
275 const std::string& element_id,
276 const base::DictionaryValue& params,
277 scoped_ptr<base::Value>* value) {
278 base::ListValue args;
279 args.Append(CreateElement(element_id));
280 scoped_ptr<base::Value> result;
281 return web_view->CallFunction(
282 session->GetCurrentFrameId(),
283 webdriver::atoms::asString(webdriver::atoms::CLEAR),
284 args, &result);
287 Status ExecuteSendKeysToElement(
288 Session* session,
289 WebView* web_view,
290 const std::string& element_id,
291 const base::DictionaryValue& params,
292 scoped_ptr<base::Value>* value) {
293 const base::ListValue* key_list;
294 if (!params.GetList("value", &key_list))
295 return Status(kUnknownError, "'value' must be a list");
297 bool is_input = false;
298 Status status = IsElementAttributeEqualToIgnoreCase(
299 session, web_view, element_id, "tagName", "input", &is_input);
300 if (status.IsError())
301 return status;
302 bool is_file = false;
303 status = IsElementAttributeEqualToIgnoreCase(
304 session, web_view, element_id, "type", "file", &is_file);
305 if (status.IsError())
306 return status;
307 if (is_input && is_file) {
308 // Compress array into a single string.
309 base::FilePath::StringType paths_string;
310 for (size_t i = 0; i < key_list->GetSize(); ++i) {
311 base::FilePath::StringType path_part;
312 if (!key_list->GetString(i, &path_part))
313 return Status(kUnknownError, "'value' is invalid");
314 paths_string.append(path_part);
317 // Separate the string into separate paths, delimited by '\n'.
318 std::vector<base::FilePath::StringType> path_strings;
319 base::SplitString(paths_string, '\n', &path_strings);
320 std::vector<base::FilePath> paths;
321 for (size_t i = 0; i < path_strings.size(); ++i)
322 paths.push_back(base::FilePath(path_strings[i]));
324 bool multiple = false;
325 status = IsElementAttributeEqualToIgnoreCase(
326 session, web_view, element_id, "multiple", "true", &multiple);
327 if (status.IsError())
328 return status;
329 if (!multiple && paths.size() > 1)
330 return Status(kUnknownError, "the element can not hold multiple files");
332 scoped_ptr<base::DictionaryValue> element(CreateElement(element_id));
333 return web_view->SetFileInputFiles(
334 session->GetCurrentFrameId(), *element, paths);
335 } else {
336 return SendKeysToElement(session, web_view, element_id, key_list);
340 Status ExecuteSubmitElement(
341 Session* session,
342 WebView* web_view,
343 const std::string& element_id,
344 const base::DictionaryValue& params,
345 scoped_ptr<base::Value>* value) {
346 base::ListValue args;
347 args.Append(CreateElement(element_id));
348 return web_view->CallFunction(
349 session->GetCurrentFrameId(),
350 webdriver::atoms::asString(webdriver::atoms::SUBMIT),
351 args,
352 value);
355 Status ExecuteGetElementText(
356 Session* session,
357 WebView* web_view,
358 const std::string& element_id,
359 const base::DictionaryValue& params,
360 scoped_ptr<base::Value>* value) {
361 base::ListValue args;
362 args.Append(CreateElement(element_id));
363 return web_view->CallFunction(
364 session->GetCurrentFrameId(),
365 webdriver::atoms::asString(webdriver::atoms::GET_TEXT),
366 args,
367 value);
370 Status ExecuteGetElementValue(
371 Session* session,
372 WebView* web_view,
373 const std::string& element_id,
374 const base::DictionaryValue& params,
375 scoped_ptr<base::Value>* value) {
376 base::ListValue args;
377 args.Append(CreateElement(element_id));
378 return web_view->CallFunction(
379 session->GetCurrentFrameId(),
380 "function(elem) { return elem['value'] }",
381 args,
382 value);
385 Status ExecuteGetElementTagName(
386 Session* session,
387 WebView* web_view,
388 const std::string& element_id,
389 const base::DictionaryValue& params,
390 scoped_ptr<base::Value>* value) {
391 base::ListValue args;
392 args.Append(CreateElement(element_id));
393 return web_view->CallFunction(
394 session->GetCurrentFrameId(),
395 "function(elem) { return elem.tagName.toLowerCase() }",
396 args,
397 value);
400 Status ExecuteIsElementSelected(
401 Session* session,
402 WebView* web_view,
403 const std::string& element_id,
404 const base::DictionaryValue& params,
405 scoped_ptr<base::Value>* value) {
406 base::ListValue args;
407 args.Append(CreateElement(element_id));
408 return web_view->CallFunction(
409 session->GetCurrentFrameId(),
410 webdriver::atoms::asString(webdriver::atoms::IS_SELECTED),
411 args,
412 value);
415 Status ExecuteIsElementEnabled(
416 Session* session,
417 WebView* web_view,
418 const std::string& element_id,
419 const base::DictionaryValue& params,
420 scoped_ptr<base::Value>* value) {
421 base::ListValue args;
422 args.Append(CreateElement(element_id));
423 return web_view->CallFunction(
424 session->GetCurrentFrameId(),
425 webdriver::atoms::asString(webdriver::atoms::IS_ENABLED),
426 args,
427 value);
430 Status ExecuteIsElementDisplayed(
431 Session* session,
432 WebView* web_view,
433 const std::string& element_id,
434 const base::DictionaryValue& params,
435 scoped_ptr<base::Value>* value) {
436 base::ListValue args;
437 args.Append(CreateElement(element_id));
438 return web_view->CallFunction(
439 session->GetCurrentFrameId(),
440 webdriver::atoms::asString(webdriver::atoms::IS_DISPLAYED),
441 args,
442 value);
445 Status ExecuteGetElementLocation(
446 Session* session,
447 WebView* web_view,
448 const std::string& element_id,
449 const base::DictionaryValue& params,
450 scoped_ptr<base::Value>* value) {
451 base::ListValue args;
452 args.Append(CreateElement(element_id));
453 return web_view->CallFunction(
454 session->GetCurrentFrameId(),
455 webdriver::atoms::asString(webdriver::atoms::GET_LOCATION),
456 args,
457 value);
460 Status ExecuteGetElementLocationOnceScrolledIntoView(
461 Session* session,
462 WebView* web_view,
463 const std::string& element_id,
464 const base::DictionaryValue& params,
465 scoped_ptr<base::Value>* value) {
466 WebPoint location;
467 Status status = ScrollElementIntoView(
468 session, web_view, element_id, &location);
469 if (status.IsError())
470 return status;
471 value->reset(CreateValueFrom(location));
472 return Status(kOk);
475 Status ExecuteGetElementSize(
476 Session* session,
477 WebView* web_view,
478 const std::string& element_id,
479 const base::DictionaryValue& params,
480 scoped_ptr<base::Value>* value) {
481 base::ListValue args;
482 args.Append(CreateElement(element_id));
483 return web_view->CallFunction(
484 session->GetCurrentFrameId(),
485 webdriver::atoms::asString(webdriver::atoms::GET_SIZE),
486 args,
487 value);
490 Status ExecuteGetElementAttribute(
491 Session* session,
492 WebView* web_view,
493 const std::string& element_id,
494 const base::DictionaryValue& params,
495 scoped_ptr<base::Value>* value) {
496 std::string name;
497 if (!params.GetString("name", &name))
498 return Status(kUnknownError, "missing 'name'");
499 return GetElementAttribute(session, web_view, element_id, name, value);
502 Status ExecuteGetElementValueOfCSSProperty(
503 Session* session,
504 WebView* web_view,
505 const std::string& element_id,
506 const base::DictionaryValue& params,
507 scoped_ptr<base::Value>* value) {
508 std::string property_name;
509 if (!params.GetString("propertyName", &property_name))
510 return Status(kUnknownError, "missing 'propertyName'");
511 std::string property_value;
512 Status status = GetElementEffectiveStyle(
513 session, web_view, element_id, property_name, &property_value);
514 if (status.IsError())
515 return status;
516 value->reset(new base::StringValue(property_value));
517 return Status(kOk);
520 Status ExecuteElementEquals(
521 Session* session,
522 WebView* web_view,
523 const std::string& element_id,
524 const base::DictionaryValue& params,
525 scoped_ptr<base::Value>* value) {
526 std::string other_element_id;
527 if (!params.GetString("other", &other_element_id))
528 return Status(kUnknownError, "'other' must be a string");
529 value->reset(new base::FundamentalValue(element_id == other_element_id));
530 return Status(kOk);