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