Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5137)

Unified Diff: chrome/test/webdriver/session.cc

Issue 7522024: Refactor chromedriver's script execution to reduce amount of custom Value parsing. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/test/webdriver/session.h ('k') | chrome/test/webdriver/utility_functions.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/test/webdriver/session.cc
diff --git a/chrome/test/webdriver/session.cc b/chrome/test/webdriver/session.cc
index bbfdc49428628e5ce2efd86a2bac5126a4557afa..51b2908f342523fc668e36cd224f77cf5ebd8593 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 {
@@ -131,7 +129,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,
@@ -140,6 +138,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,
@@ -162,7 +186,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) {
@@ -181,8 +205,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,
@@ -202,24 +224,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,
@@ -229,7 +254,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(
@@ -293,44 +318,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(
@@ -345,7 +355,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(),
@@ -358,8 +368,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(),
@@ -480,18 +490,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;
}
@@ -507,21 +515,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) {
@@ -533,43 +541,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() {
@@ -591,13 +595,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()) {
@@ -730,26 +733,26 @@ 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),
+ element, Rect(Point(0, 0), size),
false /* center */, false /* verify_clickable_at_middle */, location);
}
Error* Session::GetElementRegionInView(
const WebElementId& element,
- const gfx::Rect& region,
+ const Rect& region,
bool center,
bool verify_clickable_at_middle,
- 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, verify_clickable_at_middle,
&region_offset);
@@ -782,7 +785,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, verify_clickable_at_middle, &region_offset);
if (error)
return error;
@@ -793,66 +796,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(
@@ -860,28 +819,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,
@@ -907,77 +849,42 @@ 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::IsOptionElementSelected(const FrameId& frame_id,
const WebElementId& element,
bool* is_selected) {
- ListValue args;
- args.Append(element.ToValue());
-
- std::string script = base::StringPrintf(
- "return (%s).apply(null, arguments);", atoms::IS_SELECTED);
-
- Value* result = NULL;
- Error* error = ExecuteScript(frame_id, script, &args, &result);
- if (error)
- return error;
- scoped_ptr<Value> scoped_result(result);
- if (!result->GetAsBoolean(is_selected)) {
- return new Error(kUnknownError, "isSelected atom returned non-boolean: " +
- JsonStringify(result));
- }
- return NULL;
+ return ExecuteScriptAndParse(
+ frame_id,
+ atoms::IS_SELECTED,
+ "isSelected",
+ CreateListValueFrom(element),
+ CreateDirectValueParser(is_selected));
}
Error* Session::SetOptionElementSelected(const FrameId& frame_id,
const WebElementId& element,
bool selected) {
- ListValue args;
- args.Append(element.ToValue());
- args.Append(Value::CreateBooleanValue(selected));
-
- 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, selected),
+ CreateDirectValueParser(kSkipParsing));
}
Error* Session::ToggleOptionElement(const FrameId& frame_id,
@@ -993,24 +900,16 @@ Error* Session::ToggleOptionElement(const FrameId& frame_id,
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);
@@ -1019,7 +918,7 @@ 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;
@@ -1034,20 +933,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() {
@@ -1095,7 +987,7 @@ int Session::implicit_wait() const {
return implicit_wait_;
}
-const gfx::Point& Session::get_mouse_position() const {
+const Point& Session::get_mouse_position() const {
return mouse_position_;
}
@@ -1145,9 +1037,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(
@@ -1236,31 +1128,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);
@@ -1274,132 +1178,143 @@ Error* Session::FindElementsHelper(const FrameId& frame_id,
bool find_one,
std::vector<WebElementId>* elements) {
CHECK(root_element.is_valid());
-
- std::string jscript;
- if (find_one) {
- // TODO(jleyba): Write a Chrome-specific find element atom that will
- // correctly throw an error if the element cannot be found.
- jscript = base::StringPrintf(
- "var result = (%s).apply(null, arguments);"
- "if (!result) {"
- "var e = new Error('Unable to locate element');"
- "e.code = %d;"
- "throw e;"
- "} else { return result; }",
- atoms::FIND_ELEMENT, kNoSuchElement);
- } else {
- jscript = base::StringPrintf("return (%s).apply(null, arguments);",
- atoms::FIND_ELEMENTS);
- }
- ListValue jscript_args;
- DictionaryValue* locator_dict = new DictionaryValue();
- locator_dict->SetString(locator, query);
- jscript_args.Append(locator_dict);
- jscript_args.Append(root_element.ToValue());
-
- // The element search needs to loop until at least one element is found or the
- // session's implicit wait timeout expires, whichever occurs first.
base::Time start_time = base::Time::Now();
+ while (true) {
+ std::vector<WebElementId> temp_elements;
+ Error* error = ExecuteFindElementScriptAndParse(
+ frame_id, root_element, locator, query, find_one, &temp_elements);
+ if (error)
+ return error;
- scoped_ptr<Value> value;
- scoped_ptr<Error> error;
- bool done = false;
- while (!done) {
- Value* unscoped_value = NULL;
- error.reset(ExecuteScript(
- frame_id, jscript, &jscript_args, &unscoped_value));
- value.reset(unscoped_value);
- if (!error.get()) {
- // If searching for many elements, make sure we found at least one before
- // stopping.
- done = find_one ||
- (value->GetType() == Value::TYPE_LIST &&
- static_cast<ListValue*>(value.get())->GetSize() > 0);
- } else if (error->code() != kNoSuchElement) {
- return error.release();
+ if (temp_elements.size() > 0u) {
+ elements->swap(temp_elements);
+ break;
+ }
+
+ if ((base::Time::Now() - start_time).InMilliseconds() > implicit_wait_) {
+ if (find_one)
+ return new Error(kNoSuchElement);
+ break;
}
- int64 elapsed_time = (base::Time::Now() - start_time).InMilliseconds();
- done = done || elapsed_time > implicit_wait_;
- if (!done)
- base::PlatformThread::Sleep(50); // Prevent a busy loop.
+ base::PlatformThread::Sleep(50);
}
+ return NULL;
+}
- if (error.get())
- return error.release();
-
- // Parse the results.
- const std::string kInvalidElementDictionaryMessage =
- "Find element script returned invalid element dictionary: " +
- JsonStringify(value.get());
- if (value->IsType(Value::TYPE_LIST)) {
- ListValue* element_list = static_cast<ListValue*>(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));
- }
+Error* Session::ExecuteFindElementScriptAndParse(
+ const FrameId& frame_id,
+ const WebElementId& root_element,
+ const std::string& locator,
+ const std::string& query,
+ bool find_one,
+ std::vector<WebElementId>* elements) {
+ CHECK(root_element.is_valid());
- WebElementId element(element_dict);
- if (!element.is_valid()) {
- return new Error(kUnknownError, kInvalidElementDictionaryMessage);
+ class FindElementsParser : public ValueParser {
+ public:
+ explicit FindElementsParser(std::vector<WebElementId>* elements)
+ : elements_(elements) { }
+
+ virtual ~FindElementsParser() { }
+
+ virtual bool Parse(base::Value* value) const OVERRIDE {
+ if (!value->IsType(Value::TYPE_LIST))
+ return false;
+ ListValue* list = static_cast<ListValue*>(value);
+ for (size_t i = 0; i < list->GetSize(); ++i) {
+ WebElementId element;
+ Value* element_value = NULL;
+ if (!list->Get(i, &element_value))
+ return false;
+ if (!SetFromValue(element_value, &element))
+ return false;
+ elements_->push_back(element);
}
- elements->push_back(element);
+ return true;
}
- } 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);
+ private:
+ std::vector<WebElementId>* elements_;
+ };
+
+ class FindElementParser : public ValueParser {
+ public:
+ explicit FindElementParser(std::vector<WebElementId>* elements)
+ : elements_(elements) { }
+
+ virtual ~FindElementParser() { }
+
+ virtual bool Parse(base::Value* value) const OVERRIDE {
+ if (value->IsType(Value::TYPE_NULL))
+ return true;
+ WebElementId element;
+ bool set = SetFromValue(value, &element);
+ if (set)
+ elements_->push_back(element);
+ return set;
}
- elements->push_back(element);
+ private:
+ std::vector<WebElementId>* elements_;
+ };
+
+ DictionaryValue locator_dict;
+ locator_dict.SetString(locator, query);
+ std::vector<WebElementId> temp_elements;
+ Error* error = NULL;
+ if (find_one) {
+ error = ExecuteScriptAndParse(
+ frame_id,
+ atoms::FIND_ELEMENT,
+ "findElement",
+ CreateListValueFrom(&locator_dict, root_element),
+ new FindElementParser(&temp_elements));
} else {
- return new Error(
- kUnknownError,
- "Find element script returned unsupported type: " +
- JsonStringify(value.get()));
+ error = ExecuteScriptAndParse(
+ frame_id,
+ atoms::FIND_ELEMENTS,
+ "findElements",
+ CreateListValueFrom(&locator_dict, root_element),
+ new FindElementsParser(&temp_elements));
}
- return NULL;
+ if (!error)
+ elements->swap(temp_elements);
+ return error;
}
Error* Session::VerifyElementIsClickable(
const FrameId& frame_id,
const WebElementId& element,
- const gfx::Point& location) {
- std::string jscript = base::StringPrintf(
- "return (%s).apply(null, arguments);", atoms::IS_ELEMENT_CLICKABLE);
- ListValue jscript_args;
- jscript_args.Append(element.ToValue());
- DictionaryValue* location_dict = new DictionaryValue();
- location_dict->SetInteger("x", location.x());
- location_dict->SetInteger("y", location.y());
- jscript_args.Append(location_dict);
- Value* unscoped_value = NULL;
- Error* error = ExecuteScript(frame_id, jscript, &jscript_args,
- &unscoped_value);
+ const Point& location) {
+ class IsElementClickableParser : public ValueParser {
+ public:
+ IsElementClickableParser(bool* clickable, std::string* message)
+ : clickable_(clickable), message_(message) { }
+
+ virtual ~IsElementClickableParser() { }
+
+ virtual bool Parse(base::Value* value) const OVERRIDE {
+ if (!value->IsType(Value::TYPE_DICTIONARY))
+ return false;
+ DictionaryValue* dict = static_cast<DictionaryValue*>(value);
+ dict->GetString("message", message_);
+ return dict->GetBoolean("clickable", clickable_);
+ }
+
+ private:
+ bool* clickable_;
+ std::string* message_;
+ };
+
+ bool clickable;
+ std::string message;
+ Error* error = ExecuteScriptAndParse(
+ frame_id,
+ atoms::IS_ELEMENT_CLICKABLE,
+ "isElementClickable",
+ CreateListValueFrom(element, location),
+ new IsElementClickableParser(&clickable, &message));
if (error)
return error;
- scoped_ptr<Value> value(unscoped_value);
- if (!value->IsType(Value::TYPE_DICTIONARY)) {
- return new Error(
- kUnknownError,
- "isElementClickable atom returned non-dictionary type: " +
- JsonStringify(value.get()));
- }
- DictionaryValue* dict = static_cast<DictionaryValue*>(value.get());
- bool clickable = false;
- if (!dict->GetBoolean("clickable", &clickable)) {
- return new Error(
- kUnknownError,
- "isElementClickable atom returned bad invalid dictionary: " +
- JsonStringify(dict));
- }
- std::string message;
- dict->GetString("message", &message);
if (!clickable) {
if (message.empty())
message = "element is not clickable";
@@ -1414,47 +1329,20 @@ Error* Session::VerifyElementIsClickable(
Error* Session::GetElementRegionInViewHelper(
const FrameId& frame_id,
const WebElementId& element,
- const gfx::Rect& region,
+ const Rect& region,
bool center,
bool verify_clickable_at_middle,
- 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));
- }
- gfx::Point temp_location = gfx::Point(x, y);
+ Point* location) {
+ Point temp_location;
+ Error* error = ExecuteScriptAndParse(
+ frame_id,
+ atoms::GET_LOCATION_IN_VIEW,
+ "getLocationInView",
+ CreateListValueFrom(element, center, region),
+ CreateDirectValueParser(&temp_location));
if (verify_clickable_at_middle) {
- gfx::Point middle_point = temp_location;
+ Point middle_point = temp_location;
middle_point.Offset(region.width() / 2, region.height() / 2);
error = VerifyElementIsClickable(frame_id, element, middle_point);
if (error)
@@ -1487,39 +1375,21 @@ Error* Session::GetScreenShot(std::string* png) {
}
Error* Session::GetBrowserConnectionState(bool* online) {
- std::string jscript = base::StringPrintf(
- "return (%s).apply(null, arguments);", atoms::IS_ONLINE);
- base::ListValue no_args;
- Value* unscoped_value = NULL;
- Error* error = ExecuteScript(jscript,
- &no_args,
- &unscoped_value);
- scoped_ptr<base::Value> value(unscoped_value);
- if (error)
- return error;
- if (!value->GetAsBoolean(online))
- return new Error(kUnknownError,
- "IS_ONLINE script returned non-boolean: " +
- JsonStringify(value.get()));
- return NULL;
+ return ExecuteScriptAndParse(
+ current_target_,
+ atoms::IS_ONLINE,
+ "isOnline",
+ new ListValue(),
+ CreateDirectValueParser(online));
}
Error* Session::GetAppCacheStatus(int* status) {
- std::string jscript = base::StringPrintf(
- "return (%s).apply(null, arguments);", atoms::GET_APPCACHE_STATUS);
- base::ListValue no_args;
- Value* unscoped_value = NULL;
- Error* error = ExecuteScript(jscript,
- &no_args,
- &unscoped_value);
- scoped_ptr<base::Value> value(unscoped_value);
- if (error)
- return error;
- if (!value->GetAsInteger(status))
- return new Error(kUnknownError,
- "GET_APPCACHE_STATUS script returned non-integer: " +
- JsonStringify(value.get()));
- return NULL;
+ return ExecuteScriptAndParse(
+ current_target_,
+ atoms::GET_APPCACHE_STATUS,
+ "getAppcacheStatus",
+ new ListValue(),
+ CreateDirectValueParser(status));
}
} // namespace webdriver
« no previous file with comments | « chrome/test/webdriver/session.h ('k') | chrome/test/webdriver/utility_functions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698