| Index: chrome/test/webdriver/session.cc
|
| diff --git a/chrome/test/webdriver/session.cc b/chrome/test/webdriver/session.cc
|
| index 7249bfa54a25aa8d8619f4e791835ec02e76fe83..14f06ede7b7790ff7f141bc47606221a1f67f916 100644
|
| --- a/chrome/test/webdriver/session.cc
|
| +++ b/chrome/test/webdriver/session.cc
|
| @@ -32,14 +32,12 @@
|
| #include "chrome/common/chrome_constants.h"
|
| #include "chrome/common/chrome_switches.h"
|
| #include "chrome/test/automation/automation_json_requests.h"
|
| -#include "chrome/test/webdriver/webdriver_error.h"
|
| +#include "chrome/test/automation/value_conversion_util.h"
|
| #include "chrome/test/webdriver/session_manager.h"
|
| -#include "chrome/test/webdriver/utility_functions.h"
|
| +#include "chrome/test/webdriver/webdriver_error.h"
|
| #include "chrome/test/webdriver/webdriver_key_converter.h"
|
| +#include "chrome/test/webdriver/webdriver_util.h"
|
| #include "third_party/webdriver/atoms.h"
|
| -#include "ui/gfx/point.h"
|
| -#include "ui/gfx/rect.h"
|
| -#include "ui/gfx/size.h"
|
|
|
| namespace webdriver {
|
|
|
| @@ -115,7 +113,7 @@ Error* Session::ExecuteScript(const FrameId& frame_id,
|
| "[function(){%s\n},%s,true]));",
|
| atoms::EXECUTE_SCRIPT, script.c_str(), args_as_json.c_str());
|
|
|
| - return ExecuteScriptAndParseResponse(frame_id, jscript, value);
|
| + return ExecuteScriptAndParseValue(frame_id, jscript, value);
|
| }
|
|
|
| Error* Session::ExecuteScript(const std::string& script,
|
| @@ -124,6 +122,32 @@ Error* Session::ExecuteScript(const std::string& script,
|
| return ExecuteScript(current_target_, script, args, value);
|
| }
|
|
|
| +Error* Session::ExecuteScriptAndParse(const FrameId& frame_id,
|
| + const std::string& anonymous_func_script,
|
| + const std::string& script_name,
|
| + const ListValue* args,
|
| + const ValueParser* parser) {
|
| + scoped_ptr<const ListValue> scoped_args(args);
|
| + scoped_ptr<const ValueParser> scoped_parser(parser);
|
| + std::string called_script = base::StringPrintf(
|
| + "return (%s).apply(null, arguments);", anonymous_func_script.c_str());
|
| + Value* unscoped_value = NULL;
|
| + Error* error = ExecuteScript(frame_id, called_script, args, &unscoped_value);
|
| + if (error) {
|
| + error->AddDetails(script_name + " execution failed");
|
| + return error;
|
| + }
|
| +
|
| + scoped_ptr<Value> value(unscoped_value);
|
| + std::string error_msg;
|
| + if (!parser->Parse(value.get())) {
|
| + error_msg = base::StringPrintf("%s returned invalid value: %s",
|
| + script_name.c_str(), JsonStringify(value.get()).c_str());
|
| + return new Error(kUnknownError, error_msg);
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| Error* Session::ExecuteAsyncScript(const FrameId& frame_id,
|
| const std::string& script,
|
| const ListValue* const args,
|
| @@ -146,7 +170,7 @@ Error* Session::ExecuteAsyncScript(const FrameId& frame_id,
|
| timeout_ms,
|
| "function(result) {window.domAutomationController.send(result);}");
|
|
|
| - return ExecuteScriptAndParseResponse(frame_id, jscript, value);
|
| + return ExecuteScriptAndParseValue(frame_id, jscript, value);
|
| }
|
|
|
| Error* Session::SendKeys(const WebElementId& element, const string16& keys) {
|
| @@ -165,8 +189,6 @@ Error* Session::SendKeys(const WebElementId& element, const string16& keys) {
|
| if (!is_enabled)
|
| return new Error(kInvalidElementState);
|
|
|
| - ListValue args;
|
| - args.Append(element.ToValue());
|
| // Focus the target element in order to send keys to it.
|
| // First, the currently active element is blurred, if it is different from
|
| // the target element. We do not want to blur an element unnecessarily,
|
| @@ -186,24 +208,27 @@ Error* Session::SendKeys(const WebElementId& element, const string16& keys) {
|
| // - You cannot focus a descendant of a content editable node
|
| // TODO(jleyba): Update this to use the correct atom.
|
| const char* kFocusScript =
|
| - "var elem = arguments[0];"
|
| - "var doc = elem.ownerDocument || elem;"
|
| - "var prevActiveElem = doc.activeElement;"
|
| - "if (elem != prevActiveElem && prevActiveElem)"
|
| - " prevActiveElem.blur();"
|
| - "elem.focus();"
|
| - "if (elem != prevActiveElem && elem.value && elem.value.length &&"
|
| - " elem.setSelectionRange) {"
|
| - " elem.setSelectionRange(elem.value.length, elem.value.length);"
|
| - "}"
|
| - "if (elem != doc.activeElement)"
|
| - " throw new Error('Failed to send keys because cannot focus element.');";
|
| - Value* unscoped_result = NULL;
|
| - error = ExecuteScript(kFocusScript, &args, &unscoped_result);
|
| + "function(elem) {"
|
| + " var doc = elem.ownerDocument || elem;"
|
| + " var prevActiveElem = doc.activeElement;"
|
| + " if (elem != prevActiveElem && prevActiveElem)"
|
| + " prevActiveElem.blur();"
|
| + " elem.focus();"
|
| + " if (elem != prevActiveElem && elem.value && elem.value.length &&"
|
| + " elem.setSelectionRange) {"
|
| + " elem.setSelectionRange(elem.value.length, elem.value.length);"
|
| + " }"
|
| + " if (elem != doc.activeElement)"
|
| + " throw new Error('Failed to send keys because cannot focus element');"
|
| + "}";
|
| + error = ExecuteScriptAndParse(current_target_,
|
| + kFocusScript,
|
| + "focusElement",
|
| + CreateListValueFrom(element),
|
| + CreateDirectValueParser(kSkipParsing));
|
| if (error)
|
| return error;
|
|
|
| - error = NULL;
|
| RunSessionTask(NewRunnableMethod(
|
| this,
|
| &Session::SendKeysOnSessionThread,
|
| @@ -213,7 +238,7 @@ Error* Session::SendKeys(const WebElementId& element, const string16& keys) {
|
| }
|
|
|
| Error* Session::DragAndDropFilePaths(
|
| - const gfx::Point& location,
|
| + const Point& location,
|
| const std::vector<FilePath::StringType>& paths) {
|
| Error* error = NULL;
|
| RunSessionTask(NewRunnableMethod(
|
| @@ -268,44 +293,29 @@ Error* Session::Reload() {
|
| }
|
|
|
| Error* Session::GetURL(std::string* url) {
|
| - ListValue no_args;
|
| - Value* unscoped_value = NULL;
|
| - Error* error = ExecuteScript(current_target_,
|
| - "return document.URL;",
|
| - &no_args,
|
| - &unscoped_value);
|
| - scoped_ptr<Value> value(unscoped_value);
|
| - if (error)
|
| - return error;
|
| - if (!value->GetAsString(url))
|
| - return new Error(kUnknownError, "GetURL Script returned non-string: " +
|
| - JsonStringify(value.get()));
|
| - return NULL;
|
| + return ExecuteScriptAndParse(current_target_,
|
| + "function() { return document.URL }",
|
| + "getUrl",
|
| + new ListValue(),
|
| + CreateDirectValueParser(url));
|
| }
|
|
|
| Error* Session::GetTitle(std::string* tab_title) {
|
| - std::string script =
|
| - "if (document.title)"
|
| - " return document.title;"
|
| - "else"
|
| - " return document.URL;";
|
| -
|
| - ListValue no_args;
|
| - Value* unscoped_value = NULL;
|
| - Error* error = ExecuteScript(current_target_,
|
| - script,
|
| - &no_args,
|
| - &unscoped_value);
|
| - scoped_ptr<Value> value(unscoped_value);
|
| - if (error)
|
| - return error;
|
| - if (!value->GetAsString(tab_title))
|
| - return new Error(kUnknownError, "GetTitle script returned non-string: " +
|
| - JsonStringify(value.get()));
|
| - return NULL;
|
| -}
|
| -
|
| -Error* Session::MouseMoveAndClick(const gfx::Point& location,
|
| + const char* kGetTitleScript =
|
| + "function() {"
|
| + " if (document.title)"
|
| + " return document.title;"
|
| + " else"
|
| + " return document.URL;"
|
| + "}";
|
| + return ExecuteScriptAndParse(current_target_,
|
| + kGetTitleScript,
|
| + "getTitle",
|
| + new ListValue(),
|
| + CreateDirectValueParser(tab_title));
|
| +}
|
| +
|
| +Error* Session::MouseMoveAndClick(const Point& location,
|
| automation::MouseButton button) {
|
| Error* error = NULL;
|
| RunSessionTask(NewRunnableMethod(
|
| @@ -320,7 +330,7 @@ Error* Session::MouseMoveAndClick(const gfx::Point& location,
|
| return error;
|
| }
|
|
|
| -Error* Session::MouseMove(const gfx::Point& location) {
|
| +Error* Session::MouseMove(const Point& location) {
|
| Error* error = NULL;
|
| RunSessionTask(NewRunnableMethod(
|
| automation_.get(),
|
| @@ -333,8 +343,8 @@ Error* Session::MouseMove(const gfx::Point& location) {
|
| return error;
|
| }
|
|
|
| -Error* Session::MouseDrag(const gfx::Point& start,
|
| - const gfx::Point& end) {
|
| +Error* Session::MouseDrag(const Point& start,
|
| + const Point& end) {
|
| Error* error = NULL;
|
| RunSessionTask(NewRunnableMethod(
|
| automation_.get(),
|
| @@ -455,18 +465,16 @@ Error* Session::SwitchToWindow(const std::string& name) {
|
| return error;
|
| // See if any of the window names match |name|.
|
| for (size_t i = 0; i < window_ids.size(); ++i) {
|
| - ListValue empty_list;
|
| - Value* unscoped_name_value = NULL;
|
| std::string window_name;
|
| - Error* error = ExecuteScript(FrameId(window_ids[i], FramePath()),
|
| - "return window.name;",
|
| - &empty_list,
|
| - &unscoped_name_value);
|
| + Error* error = ExecuteScriptAndParse(
|
| + FrameId(window_ids[i], FramePath()),
|
| + "function() { return window.name; }",
|
| + "getWindowName",
|
| + new ListValue(),
|
| + CreateDirectValueParser(&window_name));
|
| if (error)
|
| return error;
|
| - scoped_ptr<Value> name_value(unscoped_name_value);
|
| - if (name_value->GetAsString(&window_name) &&
|
| - name == window_name) {
|
| + if (name == window_name) {
|
| switch_to_id = window_ids[i];
|
| break;
|
| }
|
| @@ -482,21 +490,21 @@ Error* Session::SwitchToWindow(const std::string& name) {
|
|
|
| Error* Session::SwitchToFrameWithNameOrId(const std::string& name_or_id) {
|
| std::string script =
|
| - "var arg = arguments[0];"
|
| - "var xpath = '(/html/body//iframe|/html/frameset/frame)';"
|
| - "var sub = function(s) { return s.replace(/\\$/g, arg); };"
|
| - "xpath += sub('[@name=\"$\" or @id=\"$\"]');"
|
| - "var frame = document.evaluate(xpath, document, null, "
|
| - " XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;"
|
| - "if (!frame) { return null; }"
|
| - "xpath = frame.tagName == 'IFRAME' ? '/html/body//iframe'"
|
| - " : '/html/frameset/frame';"
|
| - "frame_xpath = xpath + "
|
| - " sub('[@' + (frame.id == arg ? 'id' : 'name') + '=\"$\"]');"
|
| - "return [frame, frame_xpath];";
|
| - ListValue args;
|
| - args.Append(new StringValue(name_or_id));
|
| - return SwitchToFrameWithJavaScriptLocatedFrame(script, &args);
|
| + "function(arg) {"
|
| + " var xpath = '(/html/body//iframe|/html/frameset/frame)';"
|
| + " var sub = function(s) { return s.replace(/\\$/g, arg); };"
|
| + " xpath += sub('[@name=\"$\" or @id=\"$\"]');"
|
| + " var frame = document.evaluate(xpath, document, null, "
|
| + " XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;"
|
| + " if (!frame) { return null; }"
|
| + " xpath = frame.tagName == 'IFRAME' ? '/html/body//iframe'"
|
| + " : '/html/frameset/frame';"
|
| + " frame_xpath = xpath + "
|
| + " sub('[@' + (frame.id == arg ? 'id' : 'name') + '=\"$\"]');"
|
| + " return [frame, frame_xpath];"
|
| + "}";
|
| + return SwitchToFrameWithJavaScriptLocatedFrame(
|
| + script, CreateListValueFrom(name_or_id));
|
| }
|
|
|
| Error* Session::SwitchToFrameWithIndex(int index) {
|
| @@ -508,43 +516,39 @@ Error* Session::SwitchToFrameWithIndex(int index) {
|
| // into the list of all IFRAME and FRAME elements on the page - if we find
|
| // something, then that XPath expression can be used as the new frame's XPath.
|
| std::string script =
|
| - "var index = '[' + (arguments[0] + 1) + ']';"
|
| - "var xpath = '(/html/body//iframe|/html/frameset/frame)' + "
|
| - " index;"
|
| - "console.info('searching for frame by xpath: ' + xpath);"
|
| - "var frame = document.evaluate(xpath, document, null, "
|
| - "XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;"
|
| - "console.info(frame == null ? 'found nothing' : frame);"
|
| - "if (!frame) { return null; }"
|
| - "frame_xpath = ((frame.tagName == 'IFRAME' ? "
|
| - " '(/html/body//iframe)' : '/html/frameset/frame') + index);"
|
| - "return [frame, frame_xpath];";
|
| - ListValue args;
|
| - args.Append(Value::CreateIntegerValue(index));
|
| - return SwitchToFrameWithJavaScriptLocatedFrame(script, &args);
|
| + "function(index) {"
|
| + " var xpathIndex = '[' + (index + 1) + ']';"
|
| + " var xpath = '(/html/body//iframe|/html/frameset/frame)' + "
|
| + " xpathIndex;"
|
| + " var frame = document.evaluate(xpath, document, null, "
|
| + " XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;"
|
| + " if (!frame) { return null; }"
|
| + " frame_xpath = ((frame.tagName == 'IFRAME' ? "
|
| + " '(/html/body//iframe)' : '/html/frameset/frame') + xpathIndex);"
|
| + " return [frame, frame_xpath];"
|
| + "}";
|
| + return SwitchToFrameWithJavaScriptLocatedFrame(
|
| + script, CreateListValueFrom(index));
|
| }
|
|
|
| Error* Session::SwitchToFrameWithElement(const WebElementId& element) {
|
| // TODO(jleyba): Extract this, and the other frame switch methods to an atom.
|
| std::string script =
|
| - "var element = arguments[0];"
|
| - "console.info('Attempting to switch to ' + element);"
|
| - "if (element.nodeType != 1 || !/^i?frame$/i.test(element.tagName)) {"
|
| - " console.info('Element is not a frame: ' + element + "
|
| - "' {nodeType:' + element.nodeType + ',tagName:' + element.tagName + '}');"
|
| - " return null;"
|
| - "}"
|
| - "for (var i = 0; i < window.frames.length; i++) {"
|
| - " if (element.contentWindow == window.frames[i]) {"
|
| - " return [element, '(//iframe|//frame)[' + (i + 1) + ']'];"
|
| + "function(elem) {"
|
| + " if (elem.nodeType != 1 || !/^i?frame$/i.test(elem.tagName)) {"
|
| + " console.error('Element is not a frame');"
|
| + " return null;"
|
| " }"
|
| - "}"
|
| - "console.info('Frame is not connected to this DOM tree');"
|
| - "return null;";
|
| -
|
| - ListValue args;
|
| - args.Append(element.ToValue());
|
| - return SwitchToFrameWithJavaScriptLocatedFrame(script, &args);
|
| + " for (var i = 0; i < window.frames.length; i++) {"
|
| + " if (elem.contentWindow == window.frames[i]) {"
|
| + " return [elem, '(//iframe|//frame)[' + (i + 1) + ']'];"
|
| + " }"
|
| + " }"
|
| + " console.info('Frame is not connected to this DOM tree');"
|
| + " return null;"
|
| + "}";
|
| + return SwitchToFrameWithJavaScriptLocatedFrame(
|
| + script, CreateListValueFrom(element));
|
| }
|
|
|
| void Session::SwitchToTopFrame() {
|
| @@ -566,13 +570,12 @@ Error* Session::SwitchToTopFrameIfCurrentFrameInvalid() {
|
| // frame element is valid, otherwise the automation hangs until a timeout.
|
| for (size_t i = 0; i < frame_elements_.size(); ++i) {
|
| FrameId frame_id(current_target_.window_id, frame_path);
|
| - ListValue args;
|
| - args.Append(frame_elements_[i].ToValue());
|
| - Value* unscoped_value = NULL;
|
| - scoped_ptr<Error> error(ExecuteScript(
|
| - frame_id, "", &args, &unscoped_value));
|
| -
|
| - scoped_ptr<Value> value(unscoped_value);
|
| + scoped_ptr<Error> error(ExecuteScriptAndParse(
|
| + frame_id,
|
| + "function(){ }",
|
| + "emptyScript",
|
| + CreateListValueFrom(frame_elements_[i]),
|
| + CreateDirectValueParser(kSkipParsing)));
|
| if (error.get() && error->code() == kStaleElementReference) {
|
| SwitchToTopFrame();
|
| } else if (error.get()) {
|
| @@ -705,25 +708,24 @@ Error* Session::FindElements(const FrameId& frame_id,
|
|
|
| Error* Session::GetElementLocationInView(
|
| const WebElementId& element,
|
| - gfx::Point* location) {
|
| - gfx::Size size;
|
| + Point* location) {
|
| + Size size;
|
| Error* error = GetElementSize(current_target_, element, &size);
|
| if (error)
|
| return error;
|
| return GetElementRegionInView(
|
| - element, gfx::Rect(gfx::Point(0, 0), size),
|
| - false /* center */, location);
|
| + element, Rect(Point(0, 0), size), false /* center */, location);
|
| }
|
|
|
| Error* Session::GetElementRegionInView(
|
| const WebElementId& element,
|
| - const gfx::Rect& region,
|
| + const Rect& region,
|
| bool center,
|
| - gfx::Point* location) {
|
| + Point* location) {
|
| CHECK(element.is_valid());
|
|
|
| - gfx::Point region_offset = region.origin();
|
| - gfx::Size region_size = region.size();
|
| + Point region_offset = region.origin();
|
| + Size region_size = region.size();
|
| Error* error = GetElementRegionInViewHelper(
|
| current_target_, element, region, center, ®ion_offset);
|
| if (error)
|
| @@ -755,7 +757,7 @@ Error* Session::GetElementRegionInView(
|
| region_offset.Offset(border_left, border_top);
|
|
|
| error = GetElementRegionInViewHelper(
|
| - frame_id, frame_element, gfx::Rect(region_offset, region_size),
|
| + frame_id, frame_element, Rect(region_offset, region_size),
|
| center, ®ion_offset);
|
| if (error)
|
| return error;
|
| @@ -766,66 +768,22 @@ Error* Session::GetElementRegionInView(
|
|
|
| Error* Session::GetElementSize(const FrameId& frame_id,
|
| const WebElementId& element,
|
| - gfx::Size* size) {
|
| - std::string script = base::StringPrintf(
|
| - "return (%s).apply(null, arguments);", atoms::GET_SIZE);
|
| - ListValue args;
|
| - args.Append(element.ToValue());
|
| -
|
| - Value* unscoped_result = NULL;
|
| - Error* error = ExecuteScript(frame_id, script, &args, &unscoped_result);
|
| - scoped_ptr<Value> result(unscoped_result);
|
| - if (error)
|
| - return error;
|
| - if (!result->IsType(Value::TYPE_DICTIONARY)) {
|
| - return new Error(kUnknownError, "GetSize atom returned non-dict type: " +
|
| - JsonStringify(result.get()));
|
| - }
|
| - DictionaryValue* dict = static_cast<DictionaryValue*>(result.get());
|
| - int width, height;
|
| - if (!dict->GetInteger("width", &width) ||
|
| - !dict->GetInteger("height", &height)) {
|
| - return new Error(kUnknownError, "GetSize atom returned invalid dict: " +
|
| - JsonStringify(dict));
|
| - }
|
| - *size = gfx::Size(width, height);
|
| - return NULL;
|
| + Size* size) {
|
| + return ExecuteScriptAndParse(frame_id,
|
| + atoms::GET_SIZE,
|
| + "getSize",
|
| + CreateListValueFrom(element),
|
| + CreateDirectValueParser(size));
|
| }
|
|
|
| Error* Session::GetElementFirstClientRect(const FrameId& frame_id,
|
| const WebElementId& element,
|
| - gfx::Rect* rect) {
|
| - std::string script = base::StringPrintf(
|
| - "return (%s).apply(null, arguments);", atoms::GET_FIRST_CLIENT_RECT);
|
| - ListValue args;
|
| - args.Append(element.ToValue());
|
| -
|
| - Value* unscoped_result = NULL;
|
| - Error* error = ExecuteScript(frame_id, script, &args, &unscoped_result);
|
| - scoped_ptr<Value> result(unscoped_result);
|
| - if (error)
|
| - return error;
|
| - if (!result->IsType(Value::TYPE_DICTIONARY)) {
|
| - return new Error(
|
| - kUnknownError,
|
| - "GetFirstClientRect atom returned non-dict type: " +
|
| - JsonStringify(result.get()));
|
| - }
|
| - DictionaryValue* dict = static_cast<DictionaryValue*>(result.get());
|
| - // TODO(kkania): Convert the atom to return integers.
|
| - double left, top, width, height;
|
| - if (!dict->GetDouble("left", &left) ||
|
| - !dict->GetDouble("top", &top) ||
|
| - !dict->GetDouble("width", &width) ||
|
| - !dict->GetDouble("height", &height)) {
|
| - return new Error(
|
| - kUnknownError,
|
| - "GetFirstClientRect atom returned invalid dict: " +
|
| - JsonStringify(dict));
|
| - }
|
| - *rect = gfx::Rect(static_cast<int>(left), static_cast<int>(top),
|
| - static_cast<int>(width), static_cast<int>(height));
|
| - return NULL;
|
| + Rect* rect) {
|
| + return ExecuteScriptAndParse(frame_id,
|
| + atoms::GET_FIRST_CLIENT_RECT,
|
| + "getFirstClientRect",
|
| + CreateListValueFrom(element),
|
| + CreateDirectValueParser(rect));
|
| }
|
|
|
| Error* Session::GetElementEffectiveStyle(
|
| @@ -833,28 +791,11 @@ Error* Session::GetElementEffectiveStyle(
|
| const WebElementId& element,
|
| const std::string& prop,
|
| std::string* value) {
|
| - std::string script = base::StringPrintf(
|
| - "return (%s).apply(null, arguments);", atoms::GET_EFFECTIVE_STYLE);
|
| - ListValue args;
|
| - args.Append(element.ToValue());
|
| - args.Append(Value::CreateStringValue(prop));
|
| - Value* unscoped_result = NULL;
|
| - Error* error = ExecuteScript(
|
| - frame_id, script, &args, &unscoped_result);
|
| - scoped_ptr<Value> result(unscoped_result);
|
| - if (error) {
|
| - error->AddDetails(base::StringPrintf(
|
| - "GetEffectiveStyle atom failed for property (%s)", prop.c_str()));
|
| - return error;
|
| - }
|
| -
|
| - if (!result->GetAsString(value)) {
|
| - std::string context = base::StringPrintf(
|
| - "GetEffectiveStyle atom returned non-string for property (%s): %s",
|
| - prop.c_str(), JsonStringify(result.get()).c_str());
|
| - return new Error(kUnknownError, context);
|
| - }
|
| - return NULL;
|
| + return ExecuteScriptAndParse(frame_id,
|
| + atoms::GET_EFFECTIVE_STYLE,
|
| + "getEffectiveStyle",
|
| + CreateListValueFrom(element, prop),
|
| + CreateDirectValueParser(value));
|
| }
|
|
|
| Error* Session::GetElementBorder(const FrameId& frame_id,
|
| @@ -880,78 +821,45 @@ Error* Session::IsElementDisplayed(const FrameId& frame_id,
|
| const WebElementId& element,
|
| bool ignore_opacity,
|
| bool* is_displayed) {
|
| - std::string script = base::StringPrintf(
|
| - "return (%s).apply(null, arguments);", atoms::IS_DISPLAYED);
|
| - ListValue args;
|
| - args.Append(element.ToValue());
|
| - args.Append(Value::CreateBooleanValue(ignore_opacity));
|
| -
|
| - Value* unscoped_result = NULL;
|
| - Error* error = ExecuteScript(frame_id, script, &args, &unscoped_result);
|
| - scoped_ptr<Value> result(unscoped_result);
|
| - if (error)
|
| - return error;
|
| - if (!result->GetAsBoolean(is_displayed))
|
| - return new Error(kUnknownError, "IsDisplayed atom returned non-boolean: " +
|
| - JsonStringify(result.get()));
|
| - return NULL;
|
| + return ExecuteScriptAndParse(frame_id,
|
| + atoms::IS_DISPLAYED,
|
| + "isDisplayed",
|
| + CreateListValueFrom(element, ignore_opacity),
|
| + CreateDirectValueParser(is_displayed));
|
| }
|
|
|
| Error* Session::IsElementEnabled(const FrameId& frame_id,
|
| const WebElementId& element,
|
| bool* is_enabled) {
|
| - std::string script = base::StringPrintf(
|
| - "return (%s).apply(null, arguments);", atoms::IS_ENABLED);
|
| - ListValue args;
|
| - args.Append(element.ToValue());
|
| -
|
| - Value* unscoped_result = NULL;
|
| - Error* error = ExecuteScript(frame_id, script, &args, &unscoped_result);
|
| - scoped_ptr<Value> result(unscoped_result);
|
| - if (error)
|
| - return error;
|
| - if (!result->GetAsBoolean(is_enabled))
|
| - return new Error(kUnknownError, "IsEnabled atom returned non-boolean: " +
|
| - JsonStringify(result.get()));
|
| - return NULL;
|
| + return ExecuteScriptAndParse(frame_id,
|
| + atoms::IS_ENABLED,
|
| + "isEnabled",
|
| + CreateListValueFrom(element),
|
| + CreateDirectValueParser(is_enabled));
|
| }
|
|
|
| Error* Session::SelectOptionElement(const FrameId& frame_id,
|
| const WebElementId& element) {
|
| - ListValue args;
|
| - args.Append(element.ToValue());
|
| - args.Append(Value::CreateBooleanValue(true));
|
| -
|
| - std::string script = base::StringPrintf(
|
| - "return (%s).apply(null, arguments);", atoms::SET_SELECTED);
|
| -
|
| - Value* unscoped_result = NULL;
|
| - Error* error = ExecuteScript(frame_id, script, &args, &unscoped_result);
|
| - scoped_ptr<Value> result(unscoped_result);
|
| - return error;
|
| + return ExecuteScriptAndParse(frame_id,
|
| + atoms::SET_SELECTED,
|
| + "setSelected",
|
| + CreateListValueFrom(element, true),
|
| + CreateDirectValueParser(kSkipParsing));
|
| }
|
|
|
| Error* Session::GetElementTagName(const FrameId& frame_id,
|
| const WebElementId& element,
|
| std::string* tag_name) {
|
| - ListValue args;
|
| - args.Append(element.ToValue());
|
| -
|
| - std::string script = "return arguments[0].tagName.toLocaleLowerCase();";
|
| -
|
| - Value* unscoped_result = NULL;
|
| - Error* error = ExecuteScript(frame_id, script, &args, &unscoped_result);
|
| - scoped_ptr<Value> result(unscoped_result);
|
| - if (error)
|
| - return error;
|
| - if (!result->GetAsString(tag_name))
|
| - return new Error(kUnknownError, "TagName script returned non-string: " +
|
| - JsonStringify(result.get()));
|
| - return NULL;
|
| + return ExecuteScriptAndParse(
|
| + frame_id,
|
| + "function(elem) { return elem.tagName.toLowerCase() }",
|
| + "getElementTagName",
|
| + CreateListValueFrom(element),
|
| + CreateDirectValueParser(tag_name));
|
| }
|
|
|
| Error* Session::GetClickableLocation(const WebElementId& element,
|
| - gfx::Point* location) {
|
| + Point* location) {
|
| bool is_displayed = false;
|
| Error* error = IsElementDisplayed(
|
| current_target_, element, true /* ignore_opacity */, &is_displayed);
|
| @@ -960,12 +868,13 @@ Error* Session::GetClickableLocation(const WebElementId& element,
|
| if (!is_displayed)
|
| return new Error(kElementNotVisible, "Element must be displayed to click");
|
|
|
| - gfx::Rect rect;
|
| + Rect rect;
|
| error = GetElementFirstClientRect(current_target_, element, &rect);
|
| if (error)
|
| return error;
|
|
|
| - error = GetElementRegionInView(element, rect, true /* center */, location);
|
| + error = GetElementRegionInView(
|
| + element, rect, true /* center */, location);
|
| if (error)
|
| return error;
|
| location->Offset(rect.width() / 2, rect.height() / 2);
|
| @@ -973,20 +882,13 @@ Error* Session::GetClickableLocation(const WebElementId& element,
|
| }
|
|
|
| Error* Session::GetAttribute(const WebElementId& element,
|
| - const std::string& key, Value** value) {
|
| - std::string script = base::StringPrintf(
|
| - "return (%s).apply(null, arguments);", atoms::GET_ATTRIBUTE);
|
| -
|
| - ListValue args;
|
| - args.Append(element.ToValue());
|
| - args.Append(Value::CreateStringValue(key));
|
| -
|
| - Error* error = ExecuteScript(script, &args, value);
|
| - if (error) {
|
| - return error;
|
| - }
|
| -
|
| - return NULL;
|
| + const std::string& key,
|
| + Value** value) {
|
| + return ExecuteScriptAndParse(current_target_,
|
| + atoms::GET_ATTRIBUTE,
|
| + "getAttribute",
|
| + CreateListValueFrom(element, key),
|
| + CreateDirectValueParser(value));
|
| }
|
|
|
| Error* Session::WaitForAllTabsToStopLoading() {
|
| @@ -1040,7 +942,7 @@ bool Session::use_native_events() const {
|
| return use_native_events_;
|
| }
|
|
|
| -const gfx::Point& Session::get_mouse_position() const {
|
| +const Point& Session::get_mouse_position() const {
|
| return mouse_position_;
|
| }
|
|
|
| @@ -1093,9 +995,9 @@ void Session::TerminateOnSessionThread() {
|
| automation_.reset();
|
| }
|
|
|
| -Error* Session::ExecuteScriptAndParseResponse(const FrameId& frame_id,
|
| - const std::string& script,
|
| - Value** script_result) {
|
| +Error* Session::ExecuteScriptAndParseValue(const FrameId& frame_id,
|
| + const std::string& script,
|
| + Value** script_result) {
|
| std::string response_json;
|
| Error* error = NULL;
|
| RunSessionTask(NewRunnableMethod(
|
| @@ -1184,31 +1086,43 @@ void Session::SendKeysOnSessionThread(const string16& keys, Error** error) {
|
|
|
| Error* Session::SwitchToFrameWithJavaScriptLocatedFrame(
|
| const std::string& script, ListValue* args) {
|
| - Value* unscoped_result = NULL;
|
| - Error* error = ExecuteScript(script, args, &unscoped_result);
|
| - scoped_ptr<Value> result(unscoped_result);
|
| + class SwitchFrameValueParser : public ValueParser {
|
| + public:
|
| + SwitchFrameValueParser(
|
| + bool* found_frame, WebElementId* frame, std::string* xpath)
|
| + : found_frame_(found_frame), frame_(frame), xpath_(xpath) { }
|
| +
|
| + virtual ~SwitchFrameValueParser() { }
|
| +
|
| + virtual bool Parse(base::Value* value) const OVERRIDE {
|
| + if (value->IsType(Value::TYPE_NULL)) {
|
| + *found_frame_ = false;
|
| + return true;
|
| + }
|
| + ListValue* list;
|
| + if (!value->GetAsList(&list))
|
| + return false;
|
| + *found_frame_ = true;
|
| + return SetFromListValue(list, frame_, xpath_);
|
| + }
|
| +
|
| + private:
|
| + bool* found_frame_;
|
| + WebElementId* frame_;
|
| + std::string* xpath_;
|
| + };
|
| +
|
| + bool found_frame;
|
| + WebElementId new_frame_element;
|
| + std::string xpath;
|
| + Error* error = ExecuteScriptAndParse(
|
| + current_target_, script, "switchFrame", args,
|
| + new SwitchFrameValueParser(&found_frame, &new_frame_element, &xpath));
|
| if (error)
|
| return error;
|
|
|
| - ListValue* frame_and_xpath_list;
|
| - if (!result->GetAsList(&frame_and_xpath_list))
|
| + if (!found_frame)
|
| return new Error(kNoSuchFrame);
|
| - DictionaryValue* element_dict;
|
| - std::string xpath;
|
| - if (!frame_and_xpath_list->GetDictionary(0, &element_dict) ||
|
| - !frame_and_xpath_list->GetString(1, &xpath)) {
|
| - return new Error(
|
| - kUnknownError,
|
| - "Frame finding script did not return correct type: " +
|
| - JsonStringify(frame_and_xpath_list));
|
| - }
|
| - WebElementId new_frame_element(element_dict);
|
| - if (!new_frame_element.is_valid()) {
|
| - return new Error(
|
| - kUnknownError,
|
| - "Frame finding script did not return a frame element: " +
|
| - JsonStringify(element_dict));
|
| - }
|
|
|
| frame_elements_.push_back(new_frame_element);
|
| current_target_.frame_path = current_target_.frame_path.Append(xpath);
|
| @@ -1277,38 +1191,27 @@ Error* Session::FindElementsHelper(const FrameId& frame_id,
|
|
|
| // Parse the results.
|
| const std::string kInvalidElementDictionaryMessage =
|
| - "Find element script returned invalid element dictionary: " +
|
| + "findElement script returned invalid element dictionary: " +
|
| JsonStringify(value.get());
|
| - if (value->IsType(Value::TYPE_LIST)) {
|
| - ListValue* element_list = static_cast<ListValue*>(value.get());
|
| + if (find_one) {
|
| + WebElementId element;
|
| + if (!SetFromValue(value.get(), &element))
|
| + return new Error(kUnknownError, kInvalidElementDictionaryMessage);
|
| + elements->push_back(element);
|
| + } else {
|
| + ListValue* element_list;
|
| + if (!value->GetAsList(&element_list)) {
|
| + return new Error(
|
| + kUnknownError,
|
| + "findElements script returned unsupported type: " +
|
| + JsonStringify(value.get()));
|
| + }
|
| for (size_t i = 0; i < element_list->GetSize(); ++i) {
|
| - DictionaryValue* element_dict = NULL;
|
| - if (!element_list->GetDictionary(i, &element_dict)) {
|
| - return new Error(
|
| - kUnknownError,
|
| - "Find element script returned non-dictionary: " +
|
| - JsonStringify(element_list));
|
| - }
|
| -
|
| - WebElementId element(element_dict);
|
| - if (!element.is_valid()) {
|
| + WebElementId element;
|
| + if (!SetFromValue(value.get(), &element))
|
| return new Error(kUnknownError, kInvalidElementDictionaryMessage);
|
| - }
|
| elements->push_back(element);
|
| }
|
| - } else if (value->IsType(Value::TYPE_DICTIONARY)) {
|
| - DictionaryValue* element_dict =
|
| - static_cast<DictionaryValue*>(value.get());
|
| - WebElementId element(element_dict);
|
| - if (!element.is_valid()) {
|
| - return new Error(kUnknownError, kInvalidElementDictionaryMessage);
|
| - }
|
| - elements->push_back(element);
|
| - } else {
|
| - return new Error(
|
| - kUnknownError,
|
| - "Find element script returned unsupported type: " +
|
| - JsonStringify(value.get()));
|
| }
|
| return NULL;
|
| }
|
| @@ -1316,43 +1219,14 @@ Error* Session::FindElementsHelper(const FrameId& frame_id,
|
| Error* Session::GetElementRegionInViewHelper(
|
| const FrameId& frame_id,
|
| const WebElementId& element,
|
| - const gfx::Rect& region,
|
| + const Rect& region,
|
| bool center,
|
| - gfx::Point* location) {
|
| - std::string jscript = base::StringPrintf(
|
| - "return (%s).apply(null, arguments);", atoms::GET_LOCATION_IN_VIEW);
|
| - ListValue jscript_args;
|
| - jscript_args.Append(element.ToValue());
|
| - jscript_args.Append(Value::CreateBooleanValue(center));
|
| - DictionaryValue* elem_offset_dict = new DictionaryValue();
|
| - elem_offset_dict->SetInteger("left", region.x());
|
| - elem_offset_dict->SetInteger("top", region.y());
|
| - elem_offset_dict->SetInteger("width", region.width());
|
| - elem_offset_dict->SetInteger("height", region.height());
|
| - jscript_args.Append(elem_offset_dict);
|
| - Value* unscoped_value = NULL;
|
| - Error* error = ExecuteScript(frame_id, jscript, &jscript_args,
|
| - &unscoped_value);
|
| - scoped_ptr<Value> value(unscoped_value);
|
| - if (error)
|
| - return error;
|
| - if (!value->IsType(Value::TYPE_DICTIONARY)) {
|
| - return new Error(
|
| - kUnknownError,
|
| - "Location atom returned non-dictionary type: " +
|
| - JsonStringify(value.get()));
|
| - }
|
| - DictionaryValue* loc_dict = static_cast<DictionaryValue*>(value.get());
|
| - int x = 0, y = 0;
|
| - if (!loc_dict->GetInteger("x", &x) ||
|
| - !loc_dict->GetInteger("y", &y)) {
|
| - return new Error(
|
| - kUnknownError,
|
| - "Location atom returned bad coordinate dictionary: " +
|
| - JsonStringify(loc_dict));
|
| - }
|
| - *location = gfx::Point(x, y);
|
| - return NULL;
|
| + Point* location) {
|
| + return ExecuteScriptAndParse(frame_id,
|
| + atoms::GET_LOCATION_IN_VIEW,
|
| + "getLocationInView",
|
| + CreateListValueFrom(element, center, region),
|
| + CreateDirectValueParser(location));
|
| }
|
|
|
| Error* Session::GetScreenShot(std::string* png) {
|
|
|