diff options
author | kkania@chromium.org <kkania@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-16 15:20:01 +0000 |
---|---|---|
committer | kkania@chromium.org <kkania@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-16 15:20:01 +0000 |
commit | 3e981b2931608892407246bd2823a36097df16f4 (patch) | |
tree | 7ca1f69c2cc09d7240ad0bec7a1ce10ea7cbf08e /chrome/test/webdriver | |
parent | 21d6745575eabb50da11d49c76173fbaf28c8b1c (diff) | |
download | chromium_src-3e981b2931608892407246bd2823a36097df16f4.zip chromium_src-3e981b2931608892407246bd2823a36097df16f4.tar.gz chromium_src-3e981b2931608892407246bd2823a36097df16f4.tar.bz2 |
Refactor chromedriver's script execution to reduce amount of custom Value parsing.
Also, rename utility_functions to webdriver_util and alphabetize gyp target.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/7522024
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@96945 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/test/webdriver')
17 files changed, 873 insertions, 620 deletions
diff --git a/chrome/test/webdriver/automation.cc b/chrome/test/webdriver/automation.cc index acca8e8..87dd8d3 100644 --- a/chrome/test/webdriver/automation.cc +++ b/chrome/test/webdriver/automation.cc @@ -35,9 +35,9 @@ #include "chrome/test/automation/proxy_launcher.h" #include "chrome/test/automation/tab_proxy.h" #include "chrome/test/webdriver/frame_path.h" -#include "chrome/test/webdriver/utility_functions.h" +#include "chrome/test/webdriver/webdriver_basic_types.h" #include "chrome/test/webdriver/webdriver_error.h" -#include "ui/gfx/point.h" +#include "chrome/test/webdriver/webdriver_util.h" #if defined(OS_WIN) #include "base/win/registry.h" @@ -302,7 +302,7 @@ void Automation::ExecuteScript(int tab_id, } void Automation::MouseMove(int tab_id, - const gfx::Point& p, + const Point& p, Error** error) { int windex = 0, tab_index = 0; *error = GetIndicesForTab(tab_id, &windex, &tab_index); @@ -311,13 +311,14 @@ void Automation::MouseMove(int tab_id, std::string error_msg; if (!SendMouseMoveJSONRequest( - automation(), windex, tab_index, p.x(), p.y(), &error_msg)) { + automation(), windex, tab_index, p.rounded_x(), p.rounded_y(), + &error_msg)) { *error = new Error(kUnknownError, error_msg); } } void Automation::MouseClick(int tab_id, - const gfx::Point& p, + const Point& p, automation::MouseButton button, Error** error) { int windex = 0, tab_index = 0; @@ -327,14 +328,15 @@ void Automation::MouseClick(int tab_id, std::string error_msg; if (!SendMouseClickJSONRequest( - automation(), windex, tab_index, button, p.x(), p.y(), &error_msg)) { + automation(), windex, tab_index, button, p.rounded_x(), + p.rounded_y(), &error_msg)) { *error = new Error(kUnknownError, error_msg); } } void Automation::MouseDrag(int tab_id, - const gfx::Point& start, - const gfx::Point& end, + const Point& start, + const Point& end, Error** error) { int windex = 0, tab_index = 0; *error = GetIndicesForTab(tab_id, &windex, &tab_index); @@ -342,14 +344,15 @@ void Automation::MouseDrag(int tab_id, return; std::string error_msg; - if (!SendMouseDragJSONRequest(automation(), windex, tab_index, start.x(), - start.y(), end.x(), end.y(), &error_msg)) { + if (!SendMouseDragJSONRequest( + automation(), windex, tab_index, start.rounded_x(), start.rounded_y(), + end.rounded_x(), end.rounded_y(), &error_msg)) { *error = new Error(kUnknownError, error_msg); } } void Automation::MouseButtonUp(int tab_id, - const gfx::Point& p, + const Point& p, Error** error) { *error = CheckAdvancedInteractionsSupported(); if (*error) @@ -362,13 +365,14 @@ void Automation::MouseButtonUp(int tab_id, std::string error_msg; if (!SendMouseButtonUpJSONRequest( - automation(), windex, tab_index, p.x(), p.y(), &error_msg)) { + automation(), windex, tab_index, p.rounded_x(), p.rounded_y(), + &error_msg)) { *error = new Error(kUnknownError, error_msg); } } void Automation::MouseButtonDown(int tab_id, - const gfx::Point& p, + const Point& p, Error** error) { *error = CheckAdvancedInteractionsSupported(); if (*error) @@ -381,13 +385,14 @@ void Automation::MouseButtonDown(int tab_id, std::string error_msg; if (!SendMouseButtonDownJSONRequest( - automation(), windex, tab_index, p.x(), p.y(), &error_msg)) { + automation(), windex, tab_index, p.rounded_x(), p.rounded_y(), + &error_msg)) { *error = new Error(kUnknownError, error_msg); } } void Automation::MouseDoubleClick(int tab_id, - const gfx::Point& p, + const Point& p, Error** error) { *error = CheckAdvancedInteractionsSupported(); if (*error) @@ -400,13 +405,14 @@ void Automation::MouseDoubleClick(int tab_id, std::string error_msg; if (!SendMouseDoubleClickJSONRequest( - automation(), windex, tab_index, p.x(), p.y(), &error_msg)) { + automation(), windex, tab_index, p.rounded_x(), p.rounded_y(), + &error_msg)) { *error = new Error(kUnknownError, error_msg); } } void Automation::DragAndDropFilePaths( - int tab_id, const gfx::Point& location, + int tab_id, const Point& location, const std::vector<FilePath::StringType>& paths, Error** error) { int windex = 0, tab_index = 0; *error = GetIndicesForTab(tab_id, &windex, &tab_index); @@ -416,8 +422,8 @@ void Automation::DragAndDropFilePaths( std::string error_msg; if (!SendDragAndDropFilePathsJSONRequest( - automation(), windex, tab_index, location.x(), location.y(), paths, - &error_msg)) { + automation(), windex, tab_index, location.rounded_x(), + location.rounded_y(), paths, &error_msg)) { *error = new Error(kUnknownError, error_msg); } } diff --git a/chrome/test/webdriver/automation.h b/chrome/test/webdriver/automation.h index dcb6dba..3886c94 100644 --- a/chrome/test/webdriver/automation.h +++ b/chrome/test/webdriver/automation.h @@ -26,14 +26,11 @@ class DictionaryValue; class ListValue; } -namespace gfx { -class Point; -} - namespace webdriver { class Error; class FramePath; +class Point; // Creates and controls the Chrome instance. // This class should be created and accessed on a single thread. @@ -83,7 +80,7 @@ class Automation { // Drag and drop the file paths to the given location. void DragAndDropFilePaths(int tab_id, - const gfx::Point& location, + const Point& location, const std::vector<FilePath::StringType>& paths, Error** error); @@ -108,18 +105,18 @@ class Automation { base::DictionaryValue* cookie_dict, Error** error); - void MouseMove(int tab_id, const gfx::Point& p, Error** error); + void MouseMove(int tab_id, const Point& p, Error** error); void MouseClick(int tab_id, - const gfx::Point& p, + const Point& p, automation::MouseButton button, Error** error); void MouseDrag(int tab_id, - const gfx::Point& start, - const gfx::Point& end, + const Point& start, + const Point& end, Error** error); - void MouseButtonDown(int tab_id, const gfx::Point& p, Error** error); - void MouseButtonUp(int tab_id, const gfx::Point& p, Error** error); - void MouseDoubleClick(int tab_id, const gfx::Point& p, Error** error); + void MouseButtonDown(int tab_id, const Point& p, Error** error); + void MouseButtonUp(int tab_id, const Point& p, Error** error); + void MouseDoubleClick(int tab_id, const Point& p, Error** error); // Get persistent IDs for all the tabs currently open. These IDs can be used // to identify the tab as long as the tab exists. diff --git a/chrome/test/webdriver/commands/mouse_commands.cc b/chrome/test/webdriver/commands/mouse_commands.cc index 70339b8..288ebcb 100644 --- a/chrome/test/webdriver/commands/mouse_commands.cc +++ b/chrome/test/webdriver/commands/mouse_commands.cc @@ -6,13 +6,13 @@ #include "base/values.h" #include "chrome/common/automation_constants.h" +#include "chrome/test/automation/value_conversion_util.h" #include "chrome/test/webdriver/commands/response.h" #include "chrome/test/webdriver/session.h" -#include "chrome/test/webdriver/utility_functions.h" #include "chrome/test/webdriver/web_element_id.h" +#include "chrome/test/webdriver/webdriver_basic_types.h" #include "chrome/test/webdriver/webdriver_error.h" -#include "ui/gfx/point.h" -#include "ui/gfx/size.h" +#include "chrome/test/webdriver/webdriver_util.h" namespace { @@ -46,29 +46,23 @@ void MoveAndClickCommand::ExecutePost(Response* response) { if (tag_name == "option") { const char* kCanOptionBeToggledScript = - "return (function(option) {" + "function(option) {" " var select = option.parentElement;" " if (!select || select.tagName.toLowerCase() != 'select')" " throw new Error('Option element is not in a select');" " return select.multiple;" - "}).apply(null, arguments);"; - ListValue args; - args.Append(element.ToValue()); - Value* value = NULL; - error = session_->ExecuteScript( - session_->current_target(), kCanOptionBeToggledScript, &args, &value); + "}"; + bool can_be_toggled; + error = session_->ExecuteScriptAndParse( + session_->current_target(), + kCanOptionBeToggledScript, + "canOptionBeToggled", + CreateListValueFrom(element), + CreateDirectValueParser(&can_be_toggled)); if (error) { response->SetError(error); return; } - scoped_ptr<Value> scoped_value(value); - bool can_be_toggled; - if (!value->GetAsBoolean(&can_be_toggled)) { - response->SetError( - new Error(kUnknownError, "canOptionBeToggled returned non-boolean: " + - JsonStringify(value))); - return; - } if (can_be_toggled) { error = session_->ToggleOptionElement( @@ -78,7 +72,7 @@ void MoveAndClickCommand::ExecutePost(Response* response) { session_->current_target(), element, true); } } else { - gfx::Point location; + Point location; error = session_->GetClickableLocation(element, &location); if (!error) error = session_->MouseMoveAndClick(location, automation::kLeftButton); @@ -101,7 +95,7 @@ bool HoverCommand::DoesPost() { void HoverCommand::ExecutePost(Response* response) { Error* error = NULL; - gfx::Point location; + Point location; error = session_->GetClickableLocation(element, &location); if (!error) error = session_->MouseMove(location); @@ -136,14 +130,14 @@ bool DragCommand::DoesPost() { void DragCommand::ExecutePost(Response* response) { Error* error = NULL; - gfx::Point drag_from; + Point drag_from; error = session_->GetClickableLocation(element, &drag_from); if (error) { response->SetError(error); return; } - gfx::Point drag_to(drag_from); + Point drag_to(drag_from); drag_to.Offset(drag_x_, drag_y_); if (drag_to.x() < 0 || drag_to.y() < 0) error = new Error(kBadRequest, "Invalid (x,y) coordinates"); @@ -199,7 +193,7 @@ bool MoveToCommand::Init(Response* const response) { } void MoveToCommand::ExecutePost(Response* const response) { - gfx::Point location; + Point location; Error* error; if (has_element_) { @@ -221,7 +215,7 @@ void MoveToCommand::ExecutePost(Response* const response) { DCHECK(has_element_); // If not, calculate the half of the element size and translate by it. - gfx::Size size; + Size size; error = session_->GetElementSize(session_->current_target(), element_, &size); if (error) { diff --git a/chrome/test/webdriver/commands/webelement_commands.cc b/chrome/test/webdriver/commands/webelement_commands.cc index c76c66b..05a8b66 100644 --- a/chrome/test/webdriver/commands/webelement_commands.cc +++ b/chrome/test/webdriver/commands/webelement_commands.cc @@ -13,10 +13,9 @@ #include "base/values.h" #include "chrome/test/webdriver/commands/response.h" #include "chrome/test/webdriver/session.h" +#include "chrome/test/webdriver/webdriver_basic_types.h" #include "chrome/test/webdriver/webdriver_error.h" #include "third_party/webdriver/atoms.h" -#include "ui/gfx/point.h" -#include "ui/gfx/size.h" namespace webdriver { @@ -280,7 +279,7 @@ bool ElementLocationInViewCommand::DoesGet() { } void ElementLocationInViewCommand::ExecuteGet(Response* const response) { - gfx::Point location; + Point location; Error* error = session_->GetElementLocationInView(element, &location); if (error) { response->SetError(error); @@ -367,7 +366,7 @@ bool ElementSizeCommand::DoesGet() { } void ElementSizeCommand::ExecuteGet(Response* const response) { - gfx::Size size; + Size size; Error* error = session_->GetElementSize( session_->current_target(), element, &size); if (error) { @@ -565,7 +564,7 @@ Error* ElementValueCommand::DragAndDropFilePaths() const { paths.push_back(path); } - gfx::Point location; + Point location; error = session_->GetClickableLocation(element, &location); if (error) { return error; diff --git a/chrome/test/webdriver/dispatch.cc b/chrome/test/webdriver/dispatch.cc index 306aeb9..3d80bfc 100644 --- a/chrome/test/webdriver/dispatch.cc +++ b/chrome/test/webdriver/dispatch.cc @@ -21,8 +21,8 @@ #include "chrome/test/webdriver/http_response.h" #include "chrome/test/webdriver/commands/command.h" #include "chrome/test/webdriver/session_manager.h" -#include "chrome/test/webdriver/utility_functions.h" #include "chrome/test/webdriver/webdriver_logging.h" +#include "chrome/test/webdriver/webdriver_util.h" namespace webdriver { diff --git a/chrome/test/webdriver/server.cc b/chrome/test/webdriver/server.cc index e71134a..9efa533 100644 --- a/chrome/test/webdriver/server.cc +++ b/chrome/test/webdriver/server.cc @@ -48,8 +48,8 @@ #include "chrome/test/webdriver/commands/webelement_commands.h" #include "chrome/test/webdriver/dispatch.h" #include "chrome/test/webdriver/session_manager.h" -#include "chrome/test/webdriver/utility_functions.h" #include "chrome/test/webdriver/webdriver_logging.h" +#include "chrome/test/webdriver/webdriver_util.h" #include "third_party/mongoose/mongoose.h" #if defined(OS_WIN) diff --git a/chrome/test/webdriver/session.cc b/chrome/test/webdriver/session.cc index bbfdc49..51b2908 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, ®ion_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, ®ion_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 diff --git a/chrome/test/webdriver/session.h b/chrome/test/webdriver/session.h index b1018f2..1cc625f 100644 --- a/chrome/test/webdriver/session.h +++ b/chrome/test/webdriver/session.h @@ -17,7 +17,7 @@ #include "chrome/test/webdriver/automation.h" #include "chrome/test/webdriver/frame_path.h" #include "chrome/test/webdriver/web_element_id.h" -#include "ui/gfx/point.h" +#include "chrome/test/webdriver/webdriver_basic_types.h" class CommandLine; class FilePath; @@ -29,14 +29,10 @@ class Value; class WaitableEvent; } -namespace gfx { -class Rect; -class Size; -} - namespace webdriver { class Error; +class ValueParser; // A window ID and frame path combination that uniquely identifies a specific // frame within a session. @@ -103,6 +99,16 @@ class Session { const base::ListValue* const args, base::Value** value); + // Executes the given script in the context of the given frame and parses + // the value with the given parser. The script should be in the form of an + // anonymous function. |script_name| is only used when creating error + // messages. This function takes ownership of |args| and |parser|. + Error* ExecuteScriptAndParse(const FrameId& frame_id, + const std::string& anonymous_func_script, + const std::string& script_name, + const base::ListValue* args, + const ValueParser* parser); + // Executes given |script| in the context of the given frame. // The |script| should be in the form of a function body // (e.g. "return arguments[0]"), where |args| is the list of arguments to @@ -118,14 +124,14 @@ class Session { Error* SendKeys(const WebElementId& element, const string16& keys); // Sets the file paths to the file upload control under the given location. - Error* DragAndDropFilePaths(const gfx::Point& location, + Error* DragAndDropFilePaths(const Point& location, const std::vector<FilePath::StringType>& paths); // Clicks the mouse at the given location using the given button. - Error* MouseMoveAndClick(const gfx::Point& location, + Error* MouseMoveAndClick(const Point& location, automation::MouseButton button); - Error* MouseMove(const gfx::Point& location); - Error* MouseDrag(const gfx::Point& start, const gfx::Point& end); + Error* MouseMove(const Point& location); + Error* MouseDrag(const Point& start, const Point& end); Error* MouseClick(automation::MouseButton button); Error* MouseButtonDown(); Error* MouseButtonUp(); @@ -214,7 +220,7 @@ class Session { // the client's viewport. Error* GetElementLocationInView( const WebElementId& element, - gfx::Point* location); + Point* location); // Scroll the element's region into view and get its location relative to // the client's viewport. If |center| is true, the element will be centered @@ -223,22 +229,22 @@ class Session { // of the given region. Error* GetElementRegionInView( const WebElementId& element, - const gfx::Rect& region, + const Rect& region, bool center, bool verify_clickable_at_middle, - gfx::Point* location); + Point* location); // Gets the size of the element from the given window and frame, even if // its display is none. Error* GetElementSize(const FrameId& frame_id, const WebElementId& element, - gfx::Size* size); + Size* size); // Gets the size of the element's first client rect. If the element has // no client rects, this will return an error. Error* GetElementFirstClientRect(const FrameId& frame_id, const WebElementId& element, - gfx::Rect* rect); + Rect* rect); // Gets the element's effective style for the given property. Error* GetElementEffectiveStyle( @@ -289,7 +295,7 @@ class Session { // location of the element. If the element is not clickable, or if the // location cannot be determined, an error will be returned. Error* GetClickableLocation(const WebElementId& element, - gfx::Point* location); + Point* location); // Gets the attribute of the given element. If there are no errors, the // function sets |value| and the caller takes ownership. @@ -312,7 +318,7 @@ class Session { void set_implicit_wait(int timeout_ms); int implicit_wait() const; - const gfx::Point& get_mouse_position() const; + const Point& get_mouse_position() const; const Options& options() const; @@ -334,9 +340,9 @@ class Session { // Executes the given |script| in the context of the given frame. // Waits for script to finish and parses the response. // The caller is responsible for the script result |value|. - Error* ExecuteScriptAndParseResponse(const FrameId& frame_id, - const std::string& script, - base::Value** value); + Error* ExecuteScriptAndParseValue(const FrameId& frame_id, + const std::string& script, + base::Value** value); void SendKeysOnSessionThread(const string16& keys, Error** error); Error* SwitchToFrameWithJavaScriptLocatedFrame( @@ -348,18 +354,24 @@ class Session { const std::string& query, bool find_one, std::vector<WebElementId>* elements); + Error* ExecuteFindElementScriptAndParse(const FrameId& frame_id, + const WebElementId& root_element, + const std::string& locator, + const std::string& query, + bool find_one, + std::vector<WebElementId>* elements); // Returns an error if the element is not clickable. Error* VerifyElementIsClickable( const FrameId& frame_id, const WebElementId& element, - const gfx::Point& location); + const Point& location); Error* 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); + Point* location); const std::string id_; FrameId current_target_; @@ -379,7 +391,7 @@ class Session { std::vector<WebElementId> frame_elements_; // Last mouse position. Advanced APIs need this value. - gfx::Point mouse_position_; + Point mouse_position_; // Chrome does not have an individual method for setting the prompt text // of an alert. Instead, when the WebDriver client wants to set the text, diff --git a/chrome/test/webdriver/utility_functions.h b/chrome/test/webdriver/utility_functions.h deleted file mode 100644 index e42b8f7..0000000 --- a/chrome/test/webdriver/utility_functions.h +++ /dev/null @@ -1,32 +0,0 @@ -// 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. - -#ifndef CHROME_TEST_WEBDRIVER_UTILITY_FUNCTIONS_H_ -#define CHROME_TEST_WEBDRIVER_UTILITY_FUNCTIONS_H_ - -#include <string> -#include <vector> - -class FilePath; - -namespace base { -class Value; -} - -namespace webdriver { - -// Generates a random, 32-character hexidecimal ID. -std::string GenerateRandomID(); - -// Returns the equivalent JSON string for the given value. -std::string JsonStringify(const base::Value* value); - -#if defined(OS_MACOSX) -// Gets the paths to the user and local application directory. -void GetApplicationDirs(std::vector<FilePath>* app_dirs); -#endif - -} // namespace webdriver - -#endif // CHROME_TEST_WEBDRIVER_UTILITY_FUNCTIONS_H_ diff --git a/chrome/test/webdriver/web_element_id.cc b/chrome/test/webdriver/web_element_id.cc index 833cb27..0344ab0 100644 --- a/chrome/test/webdriver/web_element_id.cc +++ b/chrome/test/webdriver/web_element_id.cc @@ -6,6 +6,7 @@ #include "base/logging.h" #include "base/values.h" +#include "chrome/test/automation/javascript_message_utils.h" namespace { @@ -30,10 +31,10 @@ WebElementId::WebElementId() : is_valid_(false) {} WebElementId::WebElementId(const std::string& id) : id_(id), is_valid_(true) {} -WebElementId::WebElementId(Value* value) { +WebElementId::WebElementId(const Value* value) { is_valid_ = false; if (value->IsType(Value::TYPE_DICTIONARY)) { - is_valid_ = static_cast<DictionaryValue*>(value)-> + is_valid_ = static_cast<const DictionaryValue*>(value)-> GetString(kWebElementKey, &id_); } } @@ -54,3 +55,22 @@ bool WebElementId::is_valid() const { } } // namespace webdriver + +base::Value* ValueConversionTraits<webdriver::WebElementId>::CreateValueFrom( + const webdriver::WebElementId& t) { + return t.ToValue(); +} + +bool ValueConversionTraits<webdriver::WebElementId>::SetFromValue( + const base::Value* value, webdriver::WebElementId* t) { + webdriver::WebElementId id(value); + if (id.is_valid()) + *t = id; + return id.is_valid(); +} + +bool ValueConversionTraits<webdriver::WebElementId>::CanConvert( + const base::Value* value) { + webdriver::WebElementId t; + return SetFromValue(value, &t); +} diff --git a/chrome/test/webdriver/web_element_id.h b/chrome/test/webdriver/web_element_id.h index 037f633..05716f5e 100644 --- a/chrome/test/webdriver/web_element_id.h +++ b/chrome/test/webdriver/web_element_id.h @@ -8,6 +8,8 @@ #include <string> +#include "chrome/test/automation/value_conversion_traits.h" + namespace base { class Value; } @@ -27,7 +29,7 @@ class WebElementId { // Creates a |WebElementId| from an element dictionary returned by a WebDriver // atom. It will be valid iff the dictionary is correctly constructed. - explicit WebElementId(base::Value* value); + explicit WebElementId(const base::Value* value); ~WebElementId(); @@ -60,4 +62,12 @@ struct LocatorType { } // namespace webdriver +template <> +struct ValueConversionTraits<webdriver::WebElementId> { + static base::Value* CreateValueFrom(const webdriver::WebElementId& t); + static bool SetFromValue( + const base::Value* value, webdriver::WebElementId* t); + static bool CanConvert(const base::Value* value); +}; + #endif // CHROME_TEST_WEBDRIVER_WEB_ELEMENT_ID_H_ diff --git a/chrome/test/webdriver/webdriver_basic_types.cc b/chrome/test/webdriver/webdriver_basic_types.cc new file mode 100644 index 0000000..c72948c --- /dev/null +++ b/chrome/test/webdriver/webdriver_basic_types.cc @@ -0,0 +1,184 @@ +// 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/webdriver_basic_types.h" + +#include <cmath> + +#include "base/values.h" + +using base::Value; + +namespace webdriver { + +Point::Point() { } + +Point::Point(double x, double y) : x_(x), y_(y) { } + +Point::~Point() { } + +void Point::Offset(double x, double y) { + x_ += x; + y_ += y; +} + +double Point::x() const { + return x_; +} + +double Point::y() const { + return y_; +} + +int Point::rounded_x() const { + int truncated = static_cast<int>(x_); + if (std::abs(x_ - truncated) < 0.5) + return truncated; + return truncated + 1; +} + +int Point::rounded_y() const { + int truncated = static_cast<int>(y_); + if (std::abs(y_ - truncated) < 0.5) + return truncated; + return truncated + 1; +} + +Size::Size() { } + +Size::Size(double width, double height) : width_(width), height_(height) { } + +Size::~Size() { } + +double Size::width() const { + return width_; +} + +double Size::height() const { + return height_; +} + +Rect::Rect() { } + +Rect::Rect(double x, double y, double width, double height) + : origin_(x, y), size_(width, height) { } + +Rect::Rect(const Point& origin, const Size& size) + : origin_(origin), size_(size) { } + +Rect::~Rect() { } + +const Point& Rect::origin() const { + return origin_; +} + +const Size& Rect::size() const { + return size_; +} + +double Rect::x() const { + return origin_.x(); +} + +double Rect::y() const { + return origin_.y(); +} + +double Rect::width() const { + return size_.width(); +} + +double Rect::height() const { + return size_.height(); +} + +} // namespace webdriver + +Value* ValueConversionTraits<webdriver::Point>::CreateValueFrom( + const webdriver::Point& t) { + DictionaryValue* value = new DictionaryValue(); + value->SetDouble("x", t.x()); + value->SetDouble("y", t.y()); + return value; +} + +bool ValueConversionTraits<webdriver::Point>::SetFromValue( + const Value* value, webdriver::Point* t) { + if (!value->IsType(Value::TYPE_DICTIONARY)) + return false; + + const DictionaryValue* dict_value = + static_cast<const DictionaryValue*>(value); + double x, y; + if (!dict_value->GetDouble("x", &x) || + !dict_value->GetDouble("y", &y)) + return false; + *t = webdriver::Point(x, y); + return true; +} + +bool ValueConversionTraits<webdriver::Point>::CanConvert(const Value* value) { + webdriver::Point t; + return SetFromValue(value, &t); +} + +Value* ValueConversionTraits<webdriver::Size>::CreateValueFrom( + const webdriver::Size& t) { + DictionaryValue* value = new DictionaryValue(); + value->SetDouble("width", t.width()); + value->SetDouble("height", t.height()); + return value; +} + +bool ValueConversionTraits<webdriver::Size>::SetFromValue( + const Value* value, webdriver::Size* t) { + if (!value->IsType(Value::TYPE_DICTIONARY)) + return false; + + const DictionaryValue* dict_value = + static_cast<const DictionaryValue*>(value); + double width, height; + if (!dict_value->GetDouble("width", &width) || + !dict_value->GetDouble("height", &height)) + return false; + *t = webdriver::Size(width, height); + return true; +} + +bool ValueConversionTraits<webdriver::Size>::CanConvert(const Value* value) { + webdriver::Size t; + return SetFromValue(value, &t); +} + +Value* ValueConversionTraits<webdriver::Rect>::CreateValueFrom( + const webdriver::Rect& t) { + DictionaryValue* value = new DictionaryValue(); + value->SetDouble("left", t.x()); + value->SetDouble("top", t.y()); + value->SetDouble("width", t.width()); + value->SetDouble("height", t.height()); + return value; +} + +bool ValueConversionTraits<webdriver::Rect>::SetFromValue( + const Value* value, webdriver::Rect* t) { + if (!value->IsType(Value::TYPE_DICTIONARY)) + return false; + + const DictionaryValue* dict_value = + static_cast<const DictionaryValue*>(value); + double x, y, width, height; + if (!dict_value->GetDouble("left", &x) || + !dict_value->GetDouble("top", &y) || + !dict_value->GetDouble("width", &width) || + !dict_value->GetDouble("height", &height)) + return false; + *t = webdriver::Rect(x, y, width, height); + return true; +} + +bool ValueConversionTraits<webdriver::Rect>::CanConvert(const Value* value) { + webdriver::Rect t; + return SetFromValue(value, &t); +} diff --git a/chrome/test/webdriver/webdriver_basic_types.h b/chrome/test/webdriver/webdriver_basic_types.h new file mode 100644 index 0000000..c96fcfb --- /dev/null +++ b/chrome/test/webdriver/webdriver_basic_types.h @@ -0,0 +1,89 @@ +// 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. + +#ifndef CHROME_TEST_WEBDRIVER_WEBDRIVER_BASIC_TYPES_H_ +#define CHROME_TEST_WEBDRIVER_WEBDRIVER_BASIC_TYPES_H_ +#pragma once + +#include "chrome/test/automation/value_conversion_traits.h" + +namespace base { +class Value; +} + +namespace webdriver { + +class Point { + public: + Point(); + Point(double x, double y); + ~Point(); + + void Offset(double x, double y); + + double x() const; + double y() const; + int rounded_x() const; + int rounded_y() const; + + private: + double x_, y_; +}; + +class Size { + public: + Size(); + Size(double width, double height); + ~Size(); + + double width() const; + double height() const; + + private: + double width_, height_; +}; + +class Rect { + public: + Rect(); + Rect(double x, double y, double width, double height); + Rect(const Point& origin, const Size& size); + ~Rect(); + + const Point& origin() const; + const Size& size() const; + double x() const; + double y() const; + double width() const; + double height() const; + + private: + Point origin_; + Size size_; +}; + +} // namespace webdriver + +template <> +struct ValueConversionTraits<webdriver::Point> { + static base::Value* CreateValueFrom(const webdriver::Point& t); + static bool SetFromValue(const base::Value* value, webdriver::Point* t); + static bool CanConvert(const base::Value* value); +}; + +template <> +struct ValueConversionTraits<webdriver::Size> { + static base::Value* CreateValueFrom(const webdriver::Size& t); + static bool SetFromValue(const base::Value* value, webdriver::Size* t); + static bool CanConvert(const base::Value* value); +}; + +template <> +struct ValueConversionTraits<webdriver::Rect> { + static base::Value* CreateValueFrom(const webdriver::Rect& t); + static bool SetFromValue(const base::Value* value, webdriver::Rect* t); + static bool CanConvert(const base::Value* value); +}; + +#endif // CHROME_TEST_WEBDRIVER_WEBDRIVER_BASIC_TYPES_H_ diff --git a/chrome/test/webdriver/utility_functions.cc b/chrome/test/webdriver/webdriver_util.cc index b6af918..45e080f 100644 --- a/chrome/test/webdriver/utility_functions.cc +++ b/chrome/test/webdriver/webdriver_util.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/test/webdriver/utility_functions.h" +#include "chrome/test/webdriver/webdriver_util.h" #include "base/basictypes.h" #include "base/format_macros.h" @@ -13,6 +13,8 @@ namespace webdriver { +SkipParsing* kSkipParsing = NULL; + std::string GenerateRandomID() { uint64 msb = base::RandUint64(); uint64 lsb = base::RandUint64(); @@ -25,4 +27,18 @@ std::string JsonStringify(const Value* value) { return json; } +ValueParser::ValueParser() { } + +ValueParser::~ValueParser() { } + } // namespace webdriver + +bool ValueConversionTraits<webdriver::SkipParsing>::SetFromValue( + const base::Value* value, const webdriver::SkipParsing* t) { + return true; +} + +bool ValueConversionTraits<webdriver::SkipParsing>::CanConvert( + const base::Value* value) { + return true; +} diff --git a/chrome/test/webdriver/webdriver_util.h b/chrome/test/webdriver/webdriver_util.h new file mode 100644 index 0000000..e36bdb7 --- /dev/null +++ b/chrome/test/webdriver/webdriver_util.h @@ -0,0 +1,88 @@ +// 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. + +#ifndef CHROME_TEST_WEBDRIVER_WEBDRIVER_UTIL_H_ +#define CHROME_TEST_WEBDRIVER_WEBDRIVER_UTIL_H_ +#pragma once + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "chrome/test/automation/value_conversion_traits.h" + +class FilePath; + +namespace base { +class Value; +} + +namespace webdriver { + +// Generates a random, 32-character hexidecimal ID. +std::string GenerateRandomID(); + +// Returns the equivalent JSON string for the given value. +std::string JsonStringify(const base::Value* value); + +#if defined(OS_MACOSX) +// Gets the paths to the user and local application directory. +void GetApplicationDirs(std::vector<FilePath>* app_dirs); +#endif + +// Parses a given value. +class ValueParser { + public: + virtual ~ValueParser(); + virtual bool Parse(base::Value* value) const = 0; + + protected: + ValueParser(); + + private: + DISALLOW_COPY_AND_ASSIGN(ValueParser); +}; + +// Define a special type and constant that allows users to skip parsing a value. +// Useful when wanting to skip parsing for one value out of many in a list. +enum SkipParsing { }; +extern SkipParsing* kSkipParsing; + +// Parses a given value using the |ValueConversionTraits| to the appropriate +// type. This assumes that a direct conversion can be performed without +// pulling the value out of a dictionary or list. +template <typename T> +class DirectValueParser : public ValueParser { + public: + explicit DirectValueParser(T* t) : t_(t) { } + + virtual ~DirectValueParser() { } + + virtual bool Parse(base::Value* value) const OVERRIDE { + return ValueConversionTraits<T>::SetFromValue(value, t_); + } + + private: + T* t_; + DISALLOW_COPY_AND_ASSIGN(DirectValueParser); +}; + +// Convenience function for creating a DirectValueParser. +template <typename T> +DirectValueParser<T>* CreateDirectValueParser(T* t) { + return new DirectValueParser<T>(t); +} + +} // namespace webdriver + +// Value conversion traits for SkipParsing, which just return true. +template <> +struct ValueConversionTraits<webdriver::SkipParsing> { + static bool SetFromValue(const base::Value* value, + const webdriver::SkipParsing* t); + static bool CanConvert(const base::Value* value); +}; + +#endif // CHROME_TEST_WEBDRIVER_WEBDRIVER_UTIL_H_ diff --git a/chrome/test/webdriver/utility_functions_mac.mm b/chrome/test/webdriver/webdriver_util_mac.mm index 0db48f0..dd3ee6f 100644 --- a/chrome/test/webdriver/utility_functions_mac.mm +++ b/chrome/test/webdriver/webdriver_util_mac.mm @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/test/webdriver/utility_functions.h" +#include "chrome/test/webdriver/webdriver_util.h" #import <Foundation/Foundation.h> diff --git a/chrome/test/webdriver/utility_functions_unittest.cc b/chrome/test/webdriver/webdriver_util_unittest.cc index 2563905..c80a3d7 100644 --- a/chrome/test/webdriver/utility_functions_unittest.cc +++ b/chrome/test/webdriver/webdriver_util_unittest.cc @@ -5,7 +5,7 @@ #include <set> #include <string> -#include "chrome/test/webdriver/utility_functions.h" +#include "chrome/test/webdriver/webdriver_util.h" #include "testing/gtest/include/gtest/gtest.h" TEST(RandomIDTest, CanGenerateSufficientlyRandomIDs) { |