This source file includes following definitions.
- SendKeysToElement
- ExecuteTouchSingleTapAtom
- ExecuteElementCommand
- ExecuteFindChildElement
- ExecuteFindChildElements
- ExecuteHoverOverElement
- ExecuteClickElement
- ExecuteTouchSingleTap
- ExecuteFlick
- ExecuteClearElement
- ExecuteSendKeysToElement
- ExecuteSubmitElement
- ExecuteGetElementText
- ExecuteGetElementValue
- ExecuteGetElementTagName
- ExecuteIsElementSelected
- ExecuteIsElementEnabled
- ExecuteIsElementDisplayed
- ExecuteGetElementLocation
- ExecuteGetElementLocationOnceScrolledIntoView
- ExecuteGetElementSize
- ExecuteGetElementAttribute
- ExecuteGetElementValueOfCSSProperty
- ExecuteElementEquals
#include "chrome/test/chromedriver/element_commands.h"
#include <cmath>
#include <list>
#include <vector>
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chrome/test/chromedriver/basic_types.h"
#include "chrome/test/chromedriver/chrome/chrome.h"
#include "chrome/test/chromedriver/chrome/js.h"
#include "chrome/test/chromedriver/chrome/status.h"
#include "chrome/test/chromedriver/chrome/ui_events.h"
#include "chrome/test/chromedriver/chrome/web_view.h"
#include "chrome/test/chromedriver/element_util.h"
#include "chrome/test/chromedriver/session.h"
#include "chrome/test/chromedriver/util.h"
#include "third_party/webdriver/atoms.h"
const int kFlickTouchEventsPerSecond = 30;
namespace {
Status SendKeysToElement(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::ListValue* key_list) {
bool is_displayed = false;
bool is_focused = false;
base::TimeTicks start_time = base::TimeTicks::Now();
while (true) {
Status status = IsElementDisplayed(
session, web_view, element_id, true, &is_displayed);
if (status.IsError())
return status;
if (is_displayed)
break;
status = IsElementFocused(session, web_view, element_id, &is_focused);
if (status.IsError())
return status;
if (is_focused)
break;
if (base::TimeTicks::Now() - start_time >= session->implicit_wait) {
return Status(kElementNotVisible);
}
base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
}
bool is_enabled = false;
Status status = IsElementEnabled(session, web_view, element_id, &is_enabled);
if (status.IsError())
return status;
if (!is_enabled)
return Status(kInvalidElementState);
if (!is_focused) {
base::ListValue args;
args.Append(CreateElement(element_id));
scoped_ptr<base::Value> result;
status = web_view->CallFunction(
session->GetCurrentFrameId(), kFocusScript, args, &result);
if (status.IsError())
return status;
}
return SendKeysOnWindow(web_view, key_list, true, &session->sticky_modifiers);
}
Status ExecuteTouchSingleTapAtom(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
base::ListValue args;
args.Append(CreateElement(element_id));
return web_view->CallFunction(
session->GetCurrentFrameId(),
webdriver::atoms::asString(webdriver::atoms::TOUCH_SINGLE_TAP),
args,
value);
}
}
Status ExecuteElementCommand(
const ElementCommand& command,
Session* session,
WebView* web_view,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
std::string id;
if (params.GetString("id", &id) || params.GetString("element", &id))
return command.Run(session, web_view, id, params, value);
return Status(kUnknownError, "element identifier must be a string");
}
Status ExecuteFindChildElement(
int interval_ms,
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
return FindElement(
interval_ms, true, &element_id, session, web_view, params, value);
}
Status ExecuteFindChildElements(
int interval_ms,
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
return FindElement(
interval_ms, false, &element_id, session, web_view, params, value);
}
Status ExecuteHoverOverElement(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
WebPoint location;
Status status = GetElementClickableLocation(
session, web_view, element_id, &location);
if (status.IsError())
return status;
MouseEvent move_event(
kMovedMouseEventType, kNoneMouseButton, location.x, location.y,
session->sticky_modifiers, 0);
std::list<MouseEvent> events;
events.push_back(move_event);
status = web_view->DispatchMouseEvents(events, session->GetCurrentFrameId());
if (status.IsOk())
session->mouse_position = location;
return status;
}
Status ExecuteClickElement(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
std::string tag_name;
Status status = GetElementTagName(session, web_view, element_id, &tag_name);
if (status.IsError())
return status;
if (tag_name == "option") {
bool is_toggleable;
status = IsOptionElementTogglable(
session, web_view, element_id, &is_toggleable);
if (status.IsError())
return status;
if (is_toggleable)
return ToggleOptionElement(session, web_view, element_id);
else
return SetOptionElementSelected(session, web_view, element_id, true);
} else {
WebPoint location;
status = GetElementClickableLocation(
session, web_view, element_id, &location);
if (status.IsError())
return status;
std::list<MouseEvent> events;
events.push_back(
MouseEvent(kMovedMouseEventType, kNoneMouseButton,
location.x, location.y, session->sticky_modifiers, 0));
events.push_back(
MouseEvent(kPressedMouseEventType, kLeftMouseButton,
location.x, location.y, session->sticky_modifiers, 1));
events.push_back(
MouseEvent(kReleasedMouseEventType, kLeftMouseButton,
location.x, location.y, session->sticky_modifiers, 1));
status =
web_view->DispatchMouseEvents(events, session->GetCurrentFrameId());
if (status.IsOk())
session->mouse_position = location;
return status;
}
}
Status ExecuteTouchSingleTap(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
if (session->chrome->GetBuildNo() < 1576)
return ExecuteTouchSingleTapAtom(
session, web_view, element_id, params, value);
WebPoint location;
Status status = GetElementClickableLocation(
session, web_view, element_id, &location);
if (status.IsError())
return status;
std::list<TouchEvent> events;
events.push_back(
TouchEvent(kTouchStart, location.x, location.y));
events.push_back(
TouchEvent(kTouchEnd, location.x, location.y));
return web_view->DispatchTouchEvents(events);
}
Status ExecuteFlick(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
WebPoint location;
Status status = GetElementClickableLocation(
session, web_view, element_id, &location);
if (status.IsError())
return status;
int xoffset, yoffset, speed;
if (!params.GetInteger("xoffset", &xoffset))
return Status(kUnknownError, "'xoffset' must be an integer");
if (!params.GetInteger("yoffset", &yoffset))
return Status(kUnknownError, "'yoffset' must be an integer");
if (!params.GetInteger("speed", &speed))
return Status(kUnknownError, "'speed' must be an integer");
if (speed < 1)
return Status(kUnknownError, "'speed' must be a positive integer");
status = web_view->DispatchTouchEvent(
TouchEvent(kTouchStart, location.x, location.y));
if (status.IsError())
return status;
const double offset =
std::sqrt(static_cast<double>(xoffset * xoffset + yoffset * yoffset));
const double xoffset_per_event =
(speed * xoffset) / (kFlickTouchEventsPerSecond * offset);
const double yoffset_per_event =
(speed * yoffset) / (kFlickTouchEventsPerSecond * offset);
const int total_events =
(offset * kFlickTouchEventsPerSecond) / speed;
for (int i = 0; i < total_events; i++) {
status = web_view->DispatchTouchEvent(
TouchEvent(kTouchMove,
location.x + xoffset_per_event * i,
location.y + yoffset_per_event * i));
if (status.IsError())
return status;
base::PlatformThread::Sleep(
base::TimeDelta::FromMilliseconds(1000 / kFlickTouchEventsPerSecond));
}
return web_view->DispatchTouchEvent(
TouchEvent(kTouchEnd, location.x + xoffset, location.y + yoffset));
}
Status ExecuteClearElement(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
base::ListValue args;
args.Append(CreateElement(element_id));
scoped_ptr<base::Value> result;
return web_view->CallFunction(
session->GetCurrentFrameId(),
webdriver::atoms::asString(webdriver::atoms::CLEAR),
args, &result);
}
Status ExecuteSendKeysToElement(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
const base::ListValue* key_list;
if (!params.GetList("value", &key_list))
return Status(kUnknownError, "'value' must be a list");
bool is_input = false;
Status status = IsElementAttributeEqualToIgnoreCase(
session, web_view, element_id, "tagName", "input", &is_input);
if (status.IsError())
return status;
bool is_file = false;
status = IsElementAttributeEqualToIgnoreCase(
session, web_view, element_id, "type", "file", &is_file);
if (status.IsError())
return status;
if (is_input && is_file) {
base::FilePath::StringType paths_string;
for (size_t i = 0; i < key_list->GetSize(); ++i) {
base::FilePath::StringType path_part;
if (!key_list->GetString(i, &path_part))
return Status(kUnknownError, "'value' is invalid");
paths_string.append(path_part);
}
std::vector<base::FilePath::StringType> path_strings;
base::SplitString(paths_string, '\n', &path_strings);
std::vector<base::FilePath> paths;
for (size_t i = 0; i < path_strings.size(); ++i)
paths.push_back(base::FilePath(path_strings[i]));
bool multiple = false;
status = IsElementAttributeEqualToIgnoreCase(
session, web_view, element_id, "multiple", "true", &multiple);
if (status.IsError())
return status;
if (!multiple && paths.size() > 1)
return Status(kUnknownError, "the element can not hold multiple files");
scoped_ptr<base::DictionaryValue> element(CreateElement(element_id));
return web_view->SetFileInputFiles(
session->GetCurrentFrameId(), *element, paths);
} else {
return SendKeysToElement(session, web_view, element_id, key_list);
}
}
Status ExecuteSubmitElement(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
base::ListValue args;
args.Append(CreateElement(element_id));
return web_view->CallFunction(
session->GetCurrentFrameId(),
webdriver::atoms::asString(webdriver::atoms::SUBMIT),
args,
value);
}
Status ExecuteGetElementText(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
base::ListValue args;
args.Append(CreateElement(element_id));
return web_view->CallFunction(
session->GetCurrentFrameId(),
webdriver::atoms::asString(webdriver::atoms::GET_TEXT),
args,
value);
}
Status ExecuteGetElementValue(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
base::ListValue args;
args.Append(CreateElement(element_id));
return web_view->CallFunction(
session->GetCurrentFrameId(),
"function(elem) { return elem['value'] }",
args,
value);
}
Status ExecuteGetElementTagName(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
base::ListValue args;
args.Append(CreateElement(element_id));
return web_view->CallFunction(
session->GetCurrentFrameId(),
"function(elem) { return elem.tagName.toLowerCase() }",
args,
value);
}
Status ExecuteIsElementSelected(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
base::ListValue args;
args.Append(CreateElement(element_id));
return web_view->CallFunction(
session->GetCurrentFrameId(),
webdriver::atoms::asString(webdriver::atoms::IS_SELECTED),
args,
value);
}
Status ExecuteIsElementEnabled(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
base::ListValue args;
args.Append(CreateElement(element_id));
return web_view->CallFunction(
session->GetCurrentFrameId(),
webdriver::atoms::asString(webdriver::atoms::IS_ENABLED),
args,
value);
}
Status ExecuteIsElementDisplayed(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
base::ListValue args;
args.Append(CreateElement(element_id));
return web_view->CallFunction(
session->GetCurrentFrameId(),
webdriver::atoms::asString(webdriver::atoms::IS_DISPLAYED),
args,
value);
}
Status ExecuteGetElementLocation(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
base::ListValue args;
args.Append(CreateElement(element_id));
return web_view->CallFunction(
session->GetCurrentFrameId(),
webdriver::atoms::asString(webdriver::atoms::GET_LOCATION),
args,
value);
}
Status ExecuteGetElementLocationOnceScrolledIntoView(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
WebPoint location;
Status status = ScrollElementIntoView(
session, web_view, element_id, &location);
if (status.IsError())
return status;
value->reset(CreateValueFrom(location));
return Status(kOk);
}
Status ExecuteGetElementSize(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
base::ListValue args;
args.Append(CreateElement(element_id));
return web_view->CallFunction(
session->GetCurrentFrameId(),
webdriver::atoms::asString(webdriver::atoms::GET_SIZE),
args,
value);
}
Status ExecuteGetElementAttribute(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
std::string name;
if (!params.GetString("name", &name))
return Status(kUnknownError, "missing 'name'");
return GetElementAttribute(session, web_view, element_id, name, value);
}
Status ExecuteGetElementValueOfCSSProperty(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
std::string property_name;
if (!params.GetString("propertyName", &property_name))
return Status(kUnknownError, "missing 'propertyName'");
std::string property_value;
Status status = GetElementEffectiveStyle(
session, web_view, element_id, property_name, &property_value);
if (status.IsError())
return status;
value->reset(new base::StringValue(property_value));
return Status(kOk);
}
Status ExecuteElementEquals(
Session* session,
WebView* web_view,
const std::string& element_id,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
std::string other_element_id;
if (!params.GetString("other", &other_element_id))
return Status(kUnknownError, "'other' must be a string");
value->reset(new base::FundamentalValue(element_id == other_element_id));
return Status(kOk);
}