blob: 63aa36f0083222ead603a89c12ff5b78b8efa609 [file] [log] [blame]
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/test/webdriver/commands/webelement_commands.h"
#include "base/memory/scoped_ptr.h"
#include "base/stringprintf.h"
#include "base/third_party/icu/icu_utf.h"
#include "base/values.h"
#include "chrome/test/webdriver/commands/response.h"
#include "chrome/test/webdriver/error_codes.h"
#include "chrome/test/webdriver/session.h"
#include "third_party/webdriver/atoms.h"
#include "ui/gfx/point.h"
#include "ui/gfx/size.h"
namespace webdriver {
///////////////////// WebElementCommand ////////////////////
WebElementCommand::WebElementCommand(
const std::vector<std::string>& path_segments,
const DictionaryValue* const parameters)
: WebDriverCommand(path_segments, parameters),
path_segments_(path_segments) {}
WebElementCommand::~WebElementCommand() {}
bool WebElementCommand::Init(Response* const response) {
if (!WebDriverCommand::Init(response))
return false;
// There should be at least 5 segments to match
// "/session/$session/element/$id"
if (path_segments_.size() < 5) {
SET_WEBDRIVER_ERROR(response, "Path segments is less than 5",
kBadRequest);
return false;
}
// We cannot verify the ID is valid until we execute the command and
// inject the ID into the in-page cache.
element = WebElementId(path_segments_.at(4));
return true;
}
///////////////////// ElementAttributeCommand ////////////////////
ElementAttributeCommand::ElementAttributeCommand(
const std::vector<std::string>& path_segments,
DictionaryValue* parameters)
: WebElementCommand(path_segments, parameters) {}
ElementAttributeCommand::~ElementAttributeCommand() {}
bool ElementAttributeCommand::DoesGet() {
return true;
}
void ElementAttributeCommand::ExecuteGet(Response* const response) {
// There should be at least 7 segments to match
// "/session/$session/element/$id/attribute/$name"
if (path_segments_.size() < 7) {
SET_WEBDRIVER_ERROR(response, "Path segments is less than 7",
kBadRequest);
return;
}
std::string script = base::StringPrintf(
"return (%s).apply(null, arguments);", atoms::GET_ATTRIBUTE);
scoped_ptr<ListValue> args(new ListValue);
args->Append(element.ToValue());
args->Append(Value::CreateStringValue(path_segments_.at(6)));
Value* result = NULL;
ErrorCode status = session_->ExecuteScript(script, args.get(), &result);
response->SetStatus(status);
response->SetValue(result);
}
///////////////////// ElementClearCommand ////////////////////
ElementClearCommand::ElementClearCommand(
const std::vector<std::string>& path_segments,
DictionaryValue* parameters)
: WebElementCommand(path_segments, parameters) {}
ElementClearCommand::~ElementClearCommand() {}
bool ElementClearCommand::DoesPost() {
return true;
}
void ElementClearCommand::ExecutePost(Response* const response) {
scoped_ptr<ListValue> args(new ListValue);
args->Append(element.ToValue());
std::string script = base::StringPrintf(
"(%s).apply(null, arguments);", atoms::CLEAR);
Value* result = NULL;
ErrorCode status = session_->ExecuteScript(script, args.get(), &result);
response->SetStatus(status);
response->SetValue(result);
}
///////////////////// ElementCssCommand ////////////////////
ElementCssCommand::ElementCssCommand(
const std::vector<std::string>& path_segments,
DictionaryValue* parameters)
: WebElementCommand(path_segments, parameters) {}
ElementCssCommand::~ElementCssCommand() {}
bool ElementCssCommand::DoesGet() {
return true;
}
void ElementCssCommand::ExecuteGet(Response* const response) {
// There should be at least 7 segments to match
// "/session/$session/element/$id/css/$propertyName"
if (path_segments_.size() < 7) {
SET_WEBDRIVER_ERROR(response, "Path segments is less than 7",
kBadRequest);
return;
}
std::string script = base::StringPrintf(
"return (%s).apply(null, arguments);", atoms::GET_EFFECTIVE_STYLE);
scoped_ptr<ListValue> args(new ListValue);
args->Append(element.ToValue());
args->Append(Value::CreateStringValue(path_segments_.at(6)));
Value* result = NULL;
ErrorCode status = session_->ExecuteScript(script, args.get(), &result);
response->SetStatus(status);
response->SetValue(result);
}
///////////////////// ElementDisplayedCommand ////////////////////
ElementDisplayedCommand::ElementDisplayedCommand(
const std::vector<std::string>& path_segments,
DictionaryValue* parameters)
: WebElementCommand(path_segments, parameters) {}
ElementDisplayedCommand::~ElementDisplayedCommand() {}
bool ElementDisplayedCommand::DoesGet() {
return true;
}
void ElementDisplayedCommand::ExecuteGet(Response* const response) {
bool is_displayed;
ErrorCode status = session_->IsElementDisplayed(
session_->current_target(), element, &is_displayed);
if (status == kSuccess)
response->SetValue(Value::CreateBooleanValue(is_displayed));
response->SetStatus(status);
}
///////////////////// ElementEnabledCommand ////////////////////
ElementEnabledCommand::ElementEnabledCommand(
const std::vector<std::string>& path_segments,
DictionaryValue* parameters)
: WebElementCommand(path_segments, parameters) {}
ElementEnabledCommand::~ElementEnabledCommand() {}
bool ElementEnabledCommand::DoesGet() {
return true;
}
void ElementEnabledCommand::ExecuteGet(Response* const response) {
scoped_ptr<ListValue> args(new ListValue);
args->Append(element.ToValue());
std::string script = base::StringPrintf(
"return (%s).apply(null, arguments);", atoms::IS_ENABLED);
Value* result = NULL;
ErrorCode status = session_->ExecuteScript(script, args.get(), &result);
response->SetStatus(status);
response->SetValue(result);
}
///////////////////// ElementEqualsCommand ////////////////////
ElementEqualsCommand::ElementEqualsCommand(
const std::vector<std::string>& path_segments,
DictionaryValue* parameters)
: WebElementCommand(path_segments, parameters) {}
ElementEqualsCommand::~ElementEqualsCommand() {}
bool ElementEqualsCommand::DoesGet() {
return true;
}
void ElementEqualsCommand::ExecuteGet(Response* const response) {
// There should be at least 7 segments to match
// "/session/$session/element/$id/equals/$other"
if (path_segments_.size() < 7) {
SET_WEBDRIVER_ERROR(response, "Path segments is less than 7",
kBadRequest);
return;
}
std::string script = "return arguments[0] == arguments[1];";
scoped_ptr<ListValue> args(new ListValue);
args->Append(element.ToValue());
WebElementId other_element(path_segments_.at(6));
args->Append(other_element.ToValue());
Value* result = NULL;
ErrorCode status = session_->ExecuteScript(script, args.get(), &result);
response->SetStatus(status);
response->SetValue(result);
}
///////////////////// ElementLocationCommand ////////////////////
ElementLocationCommand::ElementLocationCommand(
const std::vector<std::string>& path_segments,
DictionaryValue* parameters)
: WebElementCommand(path_segments, parameters) {}
ElementLocationCommand::~ElementLocationCommand() {}
bool ElementLocationCommand::DoesGet() {
return true;
}
void ElementLocationCommand::ExecuteGet(Response* const response) {
std::string script = base::StringPrintf(
"return (%s).apply(null, arguments);", atoms::GET_LOCATION);
ListValue args;
args.Append(element.ToValue());
Value* result = NULL;
ErrorCode status = session_->ExecuteScript(script, &args, &result);
response->SetStatus(status);
response->SetValue(result);
}
///////////////////// ElementLocationInViewCommand ////////////////////
ElementLocationInViewCommand::ElementLocationInViewCommand(
const std::vector<std::string>& path_segments,
DictionaryValue* parameters)
: WebElementCommand(path_segments, parameters) {}
ElementLocationInViewCommand::~ElementLocationInViewCommand() {}
bool ElementLocationInViewCommand::DoesGet() {
return true;
}
void ElementLocationInViewCommand::ExecuteGet(Response* const response) {
gfx::Point location;
ErrorCode code = session_->GetElementLocationInView(element, &location);
response->SetStatus(code);
if (code == kSuccess) {
DictionaryValue* coord_dict = new DictionaryValue();
coord_dict->SetInteger("x", location.x());
coord_dict->SetInteger("y", location.y());
response->SetValue(coord_dict);
}
}
///////////////////// ElementNameCommand ////////////////////
ElementNameCommand::ElementNameCommand(
const std::vector<std::string>& path_segments,
DictionaryValue* parameters)
: WebElementCommand(path_segments, parameters) {}
ElementNameCommand::~ElementNameCommand() {}
bool ElementNameCommand::DoesGet() {
return true;
}
void ElementNameCommand::ExecuteGet(Response* const response) {
scoped_ptr<ListValue> args(new ListValue);
args->Append(element.ToValue());
std::string script = "return arguments[0].tagName;";
Value* result = NULL;
ErrorCode status = session_->ExecuteScript(script, args.get(), &result);
response->SetStatus(status);
response->SetValue(result);
}
///////////////////// ElementSelectedCommand ////////////////////
ElementSelectedCommand::ElementSelectedCommand(
const std::vector<std::string>& path_segments,
DictionaryValue* parameters)
: WebElementCommand(path_segments, parameters) {}
ElementSelectedCommand::~ElementSelectedCommand() {}
bool ElementSelectedCommand::DoesGet() {
return true;
}
bool ElementSelectedCommand::DoesPost() {
return true;
}
void ElementSelectedCommand::ExecuteGet(Response* const response) {
scoped_ptr<ListValue> args(new ListValue);
args->Append(element.ToValue());
std::string script = base::StringPrintf(
"return (%s).apply(null, arguments);", atoms::IS_SELECTED);
Value* result = NULL;
ErrorCode status = session_->ExecuteScript(script, args.get(), &result);
response->SetStatus(status);
response->SetValue(result);
}
void ElementSelectedCommand::ExecutePost(Response* const response) {
scoped_ptr<ListValue> args(new ListValue);
args->Append(element.ToValue());
args->Append(Value::CreateBooleanValue(true));
std::string script = base::StringPrintf(
"return (%s).apply(null, arguments);", atoms::SET_SELECTED);
Value* result = NULL;
ErrorCode status = session_->ExecuteScript(script, args.get(), &result);
response->SetStatus(status);
response->SetValue(result);
}
///////////////////// ElementSizeCommand ////////////////////
ElementSizeCommand::ElementSizeCommand(
const std::vector<std::string>& path_segments,
DictionaryValue* parameters)
: WebElementCommand(path_segments, parameters) {}
ElementSizeCommand::~ElementSizeCommand() {}
bool ElementSizeCommand::DoesGet() {
return true;
}
void ElementSizeCommand::ExecuteGet(Response* const response) {
gfx::Size size;
ErrorCode status = session_->GetElementSize(
session_->current_target(), element, &size);
if (status == kSuccess) {
DictionaryValue* dict = new DictionaryValue();
dict->SetInteger("width", size.width());
dict->SetInteger("height", size.height());
response->SetValue(dict);
}
response->SetStatus(status);
}
///////////////////// ElementSubmitCommand ////////////////////
ElementSubmitCommand::ElementSubmitCommand(
const std::vector<std::string>& path_segments,
DictionaryValue* parameters)
: WebElementCommand(path_segments, parameters) {}
ElementSubmitCommand::~ElementSubmitCommand() {}
bool ElementSubmitCommand::DoesPost() {
return true;
}
void ElementSubmitCommand::ExecutePost(Response* const response) {
// TODO(jleyba): We need to wait for any post-submit navigation events to
// complete before responding to the client.
std::string script = base::StringPrintf(
"(%s).apply(null, arguments);", atoms::SUBMIT);
ListValue args;
args.Append(element.ToValue());
Value* result = NULL;
ErrorCode status = session_->ExecuteScript(script, &args, &result);
response->SetStatus(status);
response->SetValue(result);
}
///////////////////// ElementToggleCommand ////////////////////
ElementToggleCommand::ElementToggleCommand(
const std::vector<std::string>& path_segments,
DictionaryValue* parameters)
: WebElementCommand(path_segments, parameters) {}
ElementToggleCommand::~ElementToggleCommand() {}
bool ElementToggleCommand::DoesPost() {
return true;
}
void ElementToggleCommand::ExecutePost(Response* const response) {
std::string script = base::StringPrintf(
"return (%s).apply(null, arguments);", atoms::TOGGLE);
ListValue args;
args.Append(element.ToValue());
Value* result = NULL;
ErrorCode status = session_->ExecuteScript(script, &args, &result);
response->SetStatus(status);
response->SetValue(result);
}
///////////////////// ElementValueCommand ////////////////////
ElementValueCommand::ElementValueCommand(
const std::vector<std::string>& path_segments,
DictionaryValue* parameters)
: WebElementCommand(path_segments, parameters) {}
ElementValueCommand::~ElementValueCommand() {}
bool ElementValueCommand::DoesGet() {
return true;
}
bool ElementValueCommand::DoesPost() {
return true;
}
void ElementValueCommand::ExecuteGet(Response* const response) {
Value* unscoped_result = NULL;
ListValue args;
std::string script = "return arguments[0]['value']";
args.Append(element.ToValue());
ErrorCode code =
session_->ExecuteScript(script, &args, &unscoped_result);
scoped_ptr<Value> result(unscoped_result);
if (code != kSuccess) {
SET_WEBDRIVER_ERROR(response, "Failed to execute script", code);
return;
}
if (!result->IsType(Value::TYPE_STRING) &&
!result->IsType(Value::TYPE_NULL)) {
SET_WEBDRIVER_ERROR(response,
"Result is not string or null type",
kInternalServerError);
return;
}
response->SetStatus(kSuccess);
response->SetValue(result.release());
}
void ElementValueCommand::ExecutePost(Response* const response) {
ListValue* key_list;
if (!GetListParameter("value", &key_list)) {
SET_WEBDRIVER_ERROR(response,
"Missing or invalid 'value' parameter",
kBadRequest);
return;
}
// Flatten the given array of strings into one.
string16 keys;
for (size_t i = 0; i < key_list->GetSize(); ++i) {
string16 keys_list_part;
key_list->GetString(i, &keys_list_part);
for (size_t j = 0; j < keys_list_part.size(); ++j) {
if (CBU16_IS_SURROGATE(keys_list_part[j])) {
SET_WEBDRIVER_ERROR(
response,
"ChromeDriver only supports characters in the BMP",
kBadRequest);
return;
}
}
keys.append(keys_list_part);
}
ErrorCode code = session_->SendKeys(element, keys);
if (code != kSuccess) {
SET_WEBDRIVER_ERROR(response,
"Internal SendKeys error",
code);
return;
}
response->SetStatus(kSuccess);
}
///////////////////// ElementTextCommand ////////////////////
ElementTextCommand::ElementTextCommand(
const std::vector<std::string>& path_segments,
DictionaryValue* parameters)
: WebElementCommand(path_segments, parameters) {}
ElementTextCommand::~ElementTextCommand() {}
bool ElementTextCommand::DoesGet() {
return true;
}
void ElementTextCommand::ExecuteGet(Response* const response) {
Value* unscoped_result = NULL;
ListValue args;
args.Append(element.ToValue());
std::string script = base::StringPrintf(
"return (%s).apply(null, arguments);", atoms::GET_TEXT);
ErrorCode code = session_->ExecuteScript(script, &args,
&unscoped_result);
scoped_ptr<Value> result(unscoped_result);
if (code != kSuccess) {
SET_WEBDRIVER_ERROR(response, "Failed to execute script", code);
return;
}
if (!result->IsType(Value::TYPE_STRING)) {
SET_WEBDRIVER_ERROR(response,
"Result is not string type",
kInternalServerError);
return;
}
response->SetStatus(kSuccess);
response->SetValue(result.release());
}
} // namespace webdriver