diff options
author | kkania@chromium.org <kkania@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-16 23:10:58 +0000 |
---|---|---|
committer | kkania@chromium.org <kkania@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-16 23:10:58 +0000 |
commit | b56da61e79ee405291e8ea6b260f51a1541928d1 (patch) | |
tree | 21fdef964b8efa4caedea151cdd0867815de528a | |
parent | 938f4ea71a0e2806f4c50b4c6d59c1586f8aa399 (diff) | |
download | chromium_src-b56da61e79ee405291e8ea6b260f51a1541928d1.zip chromium_src-b56da61e79ee405291e8ea6b260f51a1541928d1.tar.gz chromium_src-b56da61e79ee405291e8ea6b260f51a1541928d1.tar.bz2 |
Have ChromeDriver return the correct error code for alerts.
Also, don't throw an alert error in set selected if the selection causes
an alert.
BUG=94959
TEST=none
Review URL: http://codereview.chromium.org/8965008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@114874 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/automation/automation_provider_json.cc | 35 | ||||
-rw-r--r-- | chrome/browser/automation/automation_provider_json.h | 7 | ||||
-rw-r--r-- | chrome/browser/automation/automation_provider_observers.cc | 3 | ||||
-rw-r--r-- | chrome/browser/automation/automation_util.cc | 4 | ||||
-rw-r--r-- | chrome/browser/automation/testing_automation_provider.cc | 25 | ||||
-rw-r--r-- | chrome/common/automation_constants.cc | 40 | ||||
-rw-r--r-- | chrome/common/automation_constants.h | 42 | ||||
-rw-r--r-- | chrome/test/automation/automation_json_requests.cc | 199 | ||||
-rw-r--r-- | chrome/test/automation/automation_json_requests.h | 76 | ||||
-rw-r--r-- | chrome/test/automation/tab_proxy.cc | 7 | ||||
-rw-r--r-- | chrome/test/webdriver/test/chromedriver_tests.py | 12 | ||||
-rw-r--r-- | chrome/test/webdriver/webdriver_automation.cc | 230 | ||||
-rw-r--r-- | chrome/test/webdriver/webdriver_error.cc | 46 | ||||
-rw-r--r-- | chrome/test/webdriver/webdriver_error.h | 8 | ||||
-rw-r--r-- | chrome/test/webdriver/webdriver_session.cc | 18 |
15 files changed, 462 insertions, 290 deletions
diff --git a/chrome/browser/automation/automation_provider_json.cc b/chrome/browser/automation/automation_provider_json.cc index 27c8474a..9a5c57f 100644 --- a/chrome/browser/automation/automation_provider_json.cc +++ b/chrome/browser/automation/automation_provider_json.cc @@ -16,20 +16,8 @@ #include "chrome/common/automation_messages.h" #include "content/browser/tab_contents/tab_contents.h" -namespace { - -// Util for creating a JSON error return string (dict with key -// 'error' and error string value). No need to quote input. -std::string JSONErrorString(const std::string& err) { - std::string prefix = "{\"error\": \""; - std::string no_quote_err; - std::string suffix = "\"}"; - - base::JsonDoubleQuote(err, false, &no_quote_err); - return prefix + no_quote_err + suffix; -} - -} // namespace +using automation::Error; +using automation::ErrorCode; AutomationJSONReply::AutomationJSONReply(AutomationProvider* provider, IPC::Message* reply_message) @@ -53,10 +41,23 @@ void AutomationJSONReply::SendSuccess(const Value* value) { } void AutomationJSONReply::SendError(const std::string& error_message) { + SendErrorInternal(Error(error_message)); +} + +void AutomationJSONReply::SendErrorCode(ErrorCode code) { + SendErrorInternal(Error(code)); +} + +void AutomationJSONReply::SendErrorInternal(const Error& error) { DCHECK(message_) << "Resending reply for JSON automation request"; - std::string json_string = JSONErrorString(error_message); - AutomationMsg_SendJSONRequest::WriteReplyParams( - message_, json_string, false); + + base::DictionaryValue dict; + dict.SetString("error", error.message()); + dict.SetInteger("code", error.code()); + std::string json; + base::JSONWriter::Write(&dict, false /* pretty_print */, &json); + + AutomationMsg_SendJSONRequest::WriteReplyParams(message_, json, false); provider_->Send(message_); message_ = NULL; } diff --git a/chrome/browser/automation/automation_provider_json.h b/chrome/browser/automation/automation_provider_json.h index b7a8674..7b46879 100644 --- a/chrome/browser/automation/automation_provider_json.h +++ b/chrome/browser/automation/automation_provider_json.h @@ -11,6 +11,7 @@ #include <string> #include "base/compiler_specific.h" +#include "chrome/common/automation_constants.h" class AutomationId; class AutomationProvider; @@ -47,7 +48,13 @@ class AutomationJSONReply { // Send an error reply along with error message |error_message|. void SendError(const std::string& error_message); + // Send an error reply along with the specified error code and its + // associated error message. + void SendErrorCode(automation::ErrorCode code); + private: + void SendErrorInternal(const automation::Error& error); + AutomationProvider* provider_; IPC::Message* message_; }; diff --git a/chrome/browser/automation/automation_provider_observers.cc b/chrome/browser/automation/automation_provider_observers.cc index c1d5be9..2435617 100644 --- a/chrome/browser/automation/automation_provider_observers.cc +++ b/chrome/browser/automation/automation_provider_observers.cc @@ -1265,8 +1265,7 @@ void DomOperationMessageSender::OnDomOperationCompleted( void DomOperationMessageSender::OnModalDialogShown() { if (automation_ && use_json_interface_) { AutomationJSONReply(automation_, reply_message_.release()) - .SendError("Could not complete script execution because a modal " - "dialog is active"); + .SendErrorCode(automation::kBlockedByModalDialog); delete this; } } diff --git a/chrome/browser/automation/automation_util.cc b/chrome/browser/automation/automation_util.cc index 07b6909..a092763 100644 --- a/chrome/browser/automation/automation_util.cc +++ b/chrome/browser/automation/automation_util.cc @@ -397,8 +397,8 @@ bool SendErrorIfModalDialogActive(AutomationProvider* provider, IPC::Message* message) { bool active = AppModalDialogQueue::GetInstance()->HasActiveDialog(); if (active) { - AutomationJSONReply(provider, message).SendError( - "Command cannot be performed because a modal dialog is active"); + AutomationJSONReply(provider, message).SendErrorCode( + automation::kBlockedByModalDialog); } return active; } diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc index aa9591f..7068738 100644 --- a/chrome/browser/automation/testing_automation_provider.cc +++ b/chrome/browser/automation/testing_automation_provider.cc @@ -145,6 +145,8 @@ #include "chrome/browser/download/download_shelf.h" #endif +using automation::Error; +using automation::ErrorCode; using automation_util::SendErrorIfModalDialogActive; using content::BrowserThread; using content::ChildProcessHost; @@ -5741,14 +5743,11 @@ namespace { // Gets the active JavaScript modal dialog, or NULL if none. JavaScriptAppModalDialog* GetActiveJavaScriptModalDialog( - std::string* error_msg) { + ErrorCode* error_code) { AppModalDialogQueue* dialog_queue = AppModalDialogQueue::GetInstance(); - if (!dialog_queue->HasActiveDialog()) { - *error_msg = "No modal dialog is showing"; - return NULL; - } - if (!dialog_queue->active_dialog()->IsJavaScriptModalDialog()) { - *error_msg = "No JavaScript modal dialog is showing"; + if (!dialog_queue->HasActiveDialog() || + !dialog_queue->active_dialog()->IsJavaScriptModalDialog()) { + *error_code = automation::kNoJavaScriptModalDialogOpen; return NULL; } return static_cast<JavaScriptAppModalDialog*>(dialog_queue->active_dialog()); @@ -5759,10 +5758,10 @@ JavaScriptAppModalDialog* GetActiveJavaScriptModalDialog( void TestingAutomationProvider::GetAppModalDialogMessage( DictionaryValue* args, IPC::Message* reply_message) { AutomationJSONReply reply(this, reply_message); - std::string error_msg; - JavaScriptAppModalDialog* dialog = GetActiveJavaScriptModalDialog(&error_msg); + ErrorCode code; + JavaScriptAppModalDialog* dialog = GetActiveJavaScriptModalDialog(&code); if (!dialog) { - reply.SendError(error_msg); + reply.SendErrorCode(code); return; } DictionaryValue result_dict; @@ -5779,10 +5778,10 @@ void TestingAutomationProvider::AcceptOrDismissAppModalDialog( return; } - std::string error_msg; - JavaScriptAppModalDialog* dialog = GetActiveJavaScriptModalDialog(&error_msg); + ErrorCode code; + JavaScriptAppModalDialog* dialog = GetActiveJavaScriptModalDialog(&code); if (!dialog) { - reply.SendError(error_msg); + reply.SendErrorCode(code); return; } if (accept) { diff --git a/chrome/common/automation_constants.cc b/chrome/common/automation_constants.cc index f380088..0fbb0de 100644 --- a/chrome/common/automation_constants.cc +++ b/chrome/common/automation_constants.cc @@ -21,4 +21,44 @@ const char kNamedInterfacePrefix[] = "NamedTestingInterface:"; const int kChromeDriverAutomationVersion = 1; +namespace { + +// Returns the string equivalent of the given |ErrorCode|. +const char* DefaultMessageForErrorCode(ErrorCode code) { + switch (code) { + case kUnknownError: + return "Unknown error"; + case kNoJavaScriptModalDialogOpen: + return "No JavaScript modal dialog is open"; + case kBlockedByModalDialog: + return "Command blocked by an open modal dialog"; + default: + return "<unknown>"; + } +} + +} // namespace + +Error::Error() : code_(kUnknownError) { } + +Error::Error(ErrorCode code) + : code_(code), + message_(DefaultMessageForErrorCode(code)) { } + +Error::Error(const std::string& error_msg) + : code_(kUnknownError), message_(error_msg) { } + +Error::Error(ErrorCode code, const std::string& error_msg) + : code_(code), message_(error_msg) { } + +Error::~Error() { } + +ErrorCode Error::code() const { + return code_; +} + +const std::string& Error::message() const { + return message_; +} + } // namespace automation diff --git a/chrome/common/automation_constants.h b/chrome/common/automation_constants.h index 1e2cdb3..3754d43 100644 --- a/chrome/common/automation_constants.h +++ b/chrome/common/automation_constants.h @@ -6,6 +6,8 @@ #define CHROME_COMMON_AUTOMATION_CONSTANTS_H__ #pragma once +#include <string> + namespace automation { // JSON value labels for proxy settings that are passed in via @@ -60,6 +62,46 @@ enum MouseButton { // TODO(kkania): Investigate a better backwards compatible automation solution. extern const int kChromeDriverAutomationVersion; +// Automation error codes. These provide the client a simple way +// to detect certain types of errors it may be interested in handling. +// The error code values must stay consistent across compatible versions. +enum ErrorCode { + // An unknown error occurred. + kUnknownError = 0, + // Trying to operate on a JavaScript modal dialog when none is open. + kNoJavaScriptModalDialogOpen = 1, + // An open modal dialog blocked the operation. The operation may have + // partially completed. + kBlockedByModalDialog = 2, +}; + +// Represents an automation error. Each error has a code and an error message. +class Error { + public: + // Creates an invalid error. + Error(); + + // Creates an error for the given code. A default message for the given code + // will be used as the error message. + explicit Error(ErrorCode code); + + // Creates an error for the given message. The |kUnknownError| type will + // be used. + explicit Error(const std::string& error_msg); + + // Creates an error for the given code and message. + Error(ErrorCode code, const std::string& error_msg); + + virtual ~Error(); + + ErrorCode code() const; + const std::string& message() const; + + private: + ErrorCode code_; + std::string message_; +}; + } // namespace automation // Used by AutomationProxy, declared here so that other headers don't need diff --git a/chrome/test/automation/automation_json_requests.cc b/chrome/test/automation/automation_json_requests.cc index 4dd8478..0c624527 100644 --- a/chrome/test/automation/automation_json_requests.cc +++ b/chrome/test/automation/automation_json_requests.cc @@ -18,6 +18,8 @@ #include "chrome/common/automation_messages.h" #include "chrome/test/automation/automation_proxy.h" +using automation::Error; +using automation::ErrorCode; using base::DictionaryValue; using base::ListValue; @@ -26,7 +28,7 @@ namespace { bool SendAutomationJSONRequest(AutomationMessageSender* sender, const DictionaryValue& request_dict, DictionaryValue* reply_dict, - std::string* error_msg) { + Error* error) { std::string request, reply; base::JSONWriter::Write(&request_dict, false, &request); std::string command; @@ -37,27 +39,29 @@ bool SendAutomationJSONRequest(AutomationMessageSender* sender, bool success = false; if (!SendAutomationJSONRequestWithDefaultTimeout( sender, request, &reply, &success)) { - *error_msg = base::StringPrintf( + *error = Error(base::StringPrintf( "Chrome did not respond to '%s'. Elapsed time was %" PRId64 " ms.", command.c_str(), - (base::Time::Now() - before_sending).InMilliseconds()); + (base::Time::Now() - before_sending).InMilliseconds())); + LOG(INFO) << error->message(); return false; } scoped_ptr<Value> value(base::JSONReader::Read(reply, true)); if (!value.get() || !value->IsType(Value::TYPE_DICTIONARY)) { + *error = Error("JSON request did not return a dictionary"); LOG(ERROR) << "JSON request did not return dict: " << command << "\n"; return false; } DictionaryValue* dict = static_cast<DictionaryValue*>(value.get()); if (!success) { - std::string error; - dict->GetString("error", &error); - *error_msg = base::StringPrintf( - "Internal Chrome error during '%s': (%s).", - command.c_str(), - error.c_str()); - LOG(ERROR) << "JSON request failed: " << command << "\n" - << " with error: " << error; + std::string error_msg; + dict->GetString("error", &error_msg); + int int_code = automation::kUnknownError; + dict->GetInteger("code", &int_code); + ErrorCode code = static_cast<ErrorCode>(int_code); + *error = Error(code, error_msg); + LOG(INFO) << "JSON request failed: " << command << "\n" + << " with error: " << error_msg; return false; } reply_dict->MergeDictionary(dict); @@ -203,12 +207,12 @@ bool SendGetIndicesFromTabIdJSONRequest( int tab_id, int* browser_index, int* tab_index, - std::string* error_msg) { + Error* error) { DictionaryValue request_dict; request_dict.SetString("command", "GetIndicesFromTab"); request_dict.SetInteger("tab_id", tab_id); DictionaryValue reply_dict; - if (!SendAutomationJSONRequest(sender, request_dict, &reply_dict, error_msg)) + if (!SendAutomationJSONRequest(sender, request_dict, &reply_dict, error)) return false; if (!reply_dict.GetInteger("windex", browser_index)) return false; @@ -222,12 +226,12 @@ bool SendGetIndicesFromTabHandleJSONRequest( int tab_handle, int* browser_index, int* tab_index, - std::string* error_msg) { + Error* error) { DictionaryValue request_dict; request_dict.SetString("command", "GetIndicesFromTab"); request_dict.SetInteger("tab_handle", tab_handle); DictionaryValue reply_dict; - if (!SendAutomationJSONRequest(sender, request_dict, &reply_dict, error_msg)) + if (!SendAutomationJSONRequest(sender, request_dict, &reply_dict, error)) return false; if (!reply_dict.GetInteger("windex", browser_index)) return false; @@ -242,14 +246,14 @@ bool SendNavigateToURLJSONRequest( const std::string& url, int navigation_count, AutomationMsg_NavigationResponseValues* nav_response, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "NavigateToURL"); locator.UpdateDictionary(&dict, "auto_id"); dict.SetString("url", url); dict.SetInteger("navigation_count", navigation_count); DictionaryValue reply_dict; - if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg)) + if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error)) return false; int response = 0; if (!reply_dict.GetInteger("result", &response)) @@ -264,14 +268,14 @@ bool SendExecuteJavascriptJSONRequest( const std::string& frame_xpath, const std::string& javascript, Value** result, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "ExecuteJavascript"); locator.UpdateDictionary(&dict, "auto_id"); dict.SetString("frame_xpath", frame_xpath); dict.SetString("javascript", javascript); DictionaryValue reply_dict; - if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg)) + if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error)) return false; std::string json; @@ -297,60 +301,60 @@ bool SendExecuteJavascriptJSONRequest( bool SendGoForwardJSONRequest( AutomationMessageSender* sender, const WebViewLocator& locator, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "GoForward"); locator.UpdateDictionary(&dict, "auto_id"); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendGoBackJSONRequest( AutomationMessageSender* sender, const WebViewLocator& locator, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "GoBack"); locator.UpdateDictionary(&dict, "auto_id"); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendReloadJSONRequest( AutomationMessageSender* sender, const WebViewLocator& locator, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "Reload"); locator.UpdateDictionary(&dict, "auto_id"); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendCaptureEntirePageJSONRequest( AutomationMessageSender* sender, const WebViewLocator& locator, const FilePath& path, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "CaptureEntirePage"); locator.UpdateDictionary(&dict, "auto_id"); dict.SetString("path", path.value()); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendGetCookiesJSONRequest( AutomationMessageSender* sender, const std::string& url, ListValue** cookies, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "GetCookies"); dict.SetString("url", url); DictionaryValue reply_dict; - if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg)) + if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error)) return false; Value* cookies_unscoped_value; if (!reply_dict.Remove("cookies", &cookies_unscoped_value)) @@ -366,43 +370,43 @@ bool SendDeleteCookieJSONRequest( AutomationMessageSender* sender, const std::string& url, const std::string& cookie_name, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "DeleteCookie"); dict.SetString("url", url); dict.SetString("name", cookie_name); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendSetCookieJSONRequest( AutomationMessageSender* sender, const std::string& url, DictionaryValue* cookie_dict, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "SetCookie"); dict.SetString("url", url); dict.Set("cookie", cookie_dict->DeepCopy()); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendGetTabIdsJSONRequest( AutomationMessageSender* sender, std::vector<WebViewInfo>* views, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "GetTabIds"); DictionaryValue reply_dict; - if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg)) + if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error)) return false; ListValue* id_list; if (reply_dict.GetList("ids", &id_list)) { for (size_t i = 0; i < id_list->GetSize(); ++i) { int id; if (!id_list->GetInteger(i, &id)) { - *error_msg = "Returned id in 'tab_ids' is not an integer"; + *error = Error("Returned id in 'tab_ids' is not an integer"); return false; } views->push_back(WebViewInfo( @@ -415,27 +419,30 @@ bool SendGetTabIdsJSONRequest( bool SendGetWebViewsJSONRequest( AutomationMessageSender* sender, std::vector<WebViewInfo>* views, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "GetViews"); DictionaryValue reply_dict; - if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg)) + if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error)) return false; ListValue* views_list; if (!reply_dict.GetList("views", &views_list)) { - *error_msg = "Returned 'views' key is missing or invalid"; + *error = Error("Returned 'views' key is missing or invalid"); return false; } for (size_t i = 0; i < views_list->GetSize(); ++i) { DictionaryValue* view_dict; if (!views_list->GetDictionary(i, &view_dict)) { - *error_msg = "Returned 'views' key contains non-dictionary values"; + *error = Error("Returned 'views' key contains non-dictionary values"); return false; } AutomationId view_id; + std::string error_msg; if (!AutomationId::FromValueInDictionary( - view_dict, "auto_id", &view_id, error_msg)) + view_dict, "auto_id", &view_id, &error_msg)) { + *error = Error(error_msg); return false; + } std::string extension_id; view_dict->GetString("extension_id", &extension_id); views->push_back(WebViewInfo( @@ -448,12 +455,12 @@ bool SendIsTabIdValidJSONRequest( AutomationMessageSender* sender, const WebViewId& view_id, bool* is_valid, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "IsTabIdValid"); view_id.UpdateDictionary(&dict, "tab_id"); DictionaryValue reply_dict; - if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg)) + if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error)) return false; return reply_dict.GetBoolean("is_valid", is_valid); } @@ -462,12 +469,12 @@ bool SendDoesAutomationObjectExistJSONRequest( AutomationMessageSender* sender, const WebViewId& view_id, bool* does_exist, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "DoesAutomationObjectExist"); view_id.UpdateDictionary(&dict, "auto_id"); DictionaryValue reply_dict; - if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg)) + if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error)) return false; return reply_dict.GetBoolean("does_exist", does_exist); } @@ -475,12 +482,12 @@ bool SendDoesAutomationObjectExistJSONRequest( bool SendCloseViewJSONRequest( AutomationMessageSender* sender, const WebViewLocator& locator, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "CloseTab"); locator.UpdateDictionary(&dict, "auto_id"); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendMouseMoveJSONRequest( @@ -488,14 +495,14 @@ bool SendMouseMoveJSONRequest( const WebViewLocator& locator, int x, int y, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "WebkitMouseMove"); locator.UpdateDictionary(&dict, "auto_id"); dict.SetInteger("x", x); dict.SetInteger("y", y); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendMouseClickJSONRequest( @@ -504,7 +511,7 @@ bool SendMouseClickJSONRequest( automation::MouseButton button, int x, int y, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "WebkitMouseClick"); locator.UpdateDictionary(&dict, "auto_id"); @@ -512,7 +519,7 @@ bool SendMouseClickJSONRequest( dict.SetInteger("x", x); dict.SetInteger("y", y); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendMouseDragJSONRequest( @@ -522,7 +529,7 @@ bool SendMouseDragJSONRequest( int start_y, int end_x, int end_y, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "WebkitMouseDrag"); locator.UpdateDictionary(&dict, "auto_id"); @@ -531,7 +538,7 @@ bool SendMouseDragJSONRequest( dict.SetInteger("end_x", end_x); dict.SetInteger("end_y", end_y); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendMouseButtonDownJSONRequest( @@ -539,14 +546,14 @@ bool SendMouseButtonDownJSONRequest( const WebViewLocator& locator, int x, int y, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "WebkitMouseButtonDown"); locator.UpdateDictionary(&dict, "auto_id"); dict.SetInteger("x", x); dict.SetInteger("y", y); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendMouseButtonUpJSONRequest( @@ -554,14 +561,14 @@ bool SendMouseButtonUpJSONRequest( const WebViewLocator& locator, int x, int y, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "WebkitMouseButtonUp"); locator.UpdateDictionary(&dict, "auto_id"); dict.SetInteger("x", x); dict.SetInteger("y", y); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendMouseDoubleClickJSONRequest( @@ -569,21 +576,21 @@ bool SendMouseDoubleClickJSONRequest( const WebViewLocator& locator, int x, int y, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "WebkitMouseDoubleClick"); locator.UpdateDictionary(&dict, "auto_id"); dict.SetInteger("x", x); dict.SetInteger("y", y); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendWebKeyEventJSONRequest( AutomationMessageSender* sender, const WebViewLocator& locator, const WebKeyEvent& key_event, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "SendWebkitKeyEvent"); locator.UpdateDictionary(&dict, "auto_id"); @@ -595,7 +602,7 @@ bool SendWebKeyEventJSONRequest( dict.SetInteger("modifiers", key_event.modifiers); dict.SetBoolean("isSystemKey", false); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendNativeKeyEventJSONRequest( @@ -603,14 +610,14 @@ bool SendNativeKeyEventJSONRequest( const WebViewLocator& locator, ui::KeyboardCode key_code, int modifiers, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "SendOSLevelKeyEventToTab"); locator.UpdateDictionary(&dict, "auto_id"); dict.SetInteger("keyCode", key_code); dict.SetInteger("modifiers", modifiers); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendDragAndDropFilePathsJSONRequest( @@ -619,7 +626,7 @@ bool SendDragAndDropFilePathsJSONRequest( int x, int y, const std::vector<FilePath::StringType>& paths, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "DragAndDropFilePaths"); locator.UpdateDictionary(&dict, "auto_id"); @@ -633,17 +640,17 @@ bool SendDragAndDropFilePathsJSONRequest( dict.Set("paths", list_value); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendGetAppModalDialogMessageJSONRequest( AutomationMessageSender* sender, std::string* message, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "GetAppModalDialogMessage"); DictionaryValue reply_dict; - if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg)) + if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error)) return false; return reply_dict.GetString("message", message); } @@ -651,43 +658,43 @@ bool SendGetAppModalDialogMessageJSONRequest( bool SendAcceptOrDismissAppModalDialogJSONRequest( AutomationMessageSender* sender, bool accept, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "AcceptOrDismissAppModalDialog"); dict.SetBoolean("accept", accept); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendAcceptPromptAppModalDialogJSONRequest( AutomationMessageSender* sender, const std::string& prompt_text, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "AcceptOrDismissAppModalDialog"); dict.SetBoolean("accept", true); dict.SetString("prompt_text", prompt_text); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendWaitForAllViewsToStopLoadingJSONRequest( AutomationMessageSender* sender, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "WaitForAllTabsToStopLoading"); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendGetChromeDriverAutomationVersion( AutomationMessageSender* sender, int* version, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "GetChromeDriverAutomationVersion"); DictionaryValue reply_dict; - if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg)) + if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error)) return false; return reply_dict.GetInteger("version", version); } @@ -697,16 +704,16 @@ bool SendInstallExtensionJSONRequest( const FilePath& path, bool with_ui, std::string* extension_id, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "InstallExtension"); dict.SetString("path", path.value()); dict.SetBoolean("with_ui", with_ui); DictionaryValue reply_dict; - if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg)) + if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error)) return false; if (!reply_dict.GetString("id", extension_id)) { - *error_msg = "Missing or invalid 'id'"; + *error = Error("Missing or invalid 'id'"); return false; } return true; @@ -715,15 +722,15 @@ bool SendInstallExtensionJSONRequest( bool SendGetExtensionsInfoJSONRequest( AutomationMessageSender* sender, ListValue* extensions_list, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "GetExtensionsInfo"); DictionaryValue reply_dict; - if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg)) + if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error)) return false; ListValue* extensions_list_swap; if (!reply_dict.GetList("extensions", &extensions_list_swap)) { - *error_msg = "Missing or invalid 'extensions'"; + *error = Error("Missing or invalid 'extensions'"); return false; } extensions_list->Swap(extensions_list_swap); @@ -735,16 +742,16 @@ bool SendIsPageActionVisibleJSONRequest( const WebViewId& tab_id, const std::string& extension_id, bool* is_visible, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "IsPageActionVisible"); tab_id.UpdateDictionary(&dict, "auto_id"); dict.SetString("extension_id", extension_id); DictionaryValue reply_dict; - if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg)) + if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error)) return false; if (!reply_dict.GetBoolean("is_visible", is_visible)) { - *error_msg = "Missing or invalid 'is_visible'"; + *error = Error("Missing or invalid 'is_visible'"); return false; } return true; @@ -755,21 +762,21 @@ bool SendSetExtensionStateJSONRequest( const std::string& extension_id, bool enable, bool allow_in_incognito, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "SetExtensionStateById"); dict.SetString("id", extension_id); dict.SetBoolean("enable", enable); dict.SetBoolean("allow_in_incognito", allow_in_incognito); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendClickExtensionButtonJSONRequest( AutomationMessageSender* sender, const std::string& extension_id, bool browser_action, - std::string* error_msg) { + Error* error) { DictionaryValue dict; if (browser_action) dict.SetString("command", "TriggerBrowserActionById"); @@ -779,26 +786,26 @@ bool SendClickExtensionButtonJSONRequest( dict.SetInteger("windex", 0); dict.SetInteger("tab_index", 0); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendUninstallExtensionJSONRequest( AutomationMessageSender* sender, const std::string& extension_id, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "UninstallExtensionById"); dict.SetString("id", extension_id); DictionaryValue reply_dict; - if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg)) + if (!SendAutomationJSONRequest(sender, dict, &reply_dict, error)) return false; bool success; if (!reply_dict.GetBoolean("success", &success)) { - *error_msg = "Missing or invalid 'success'"; + *error = Error("Missing or invalid 'success'"); return false; } if (!success) { - *error_msg = "Extension uninstall not permitted"; + *error = Error("Extension uninstall not permitted"); return false; } return true; @@ -808,25 +815,25 @@ bool SendSetLocalStatePreferenceJSONRequest( AutomationMessageSender* sender, const std::string& pref, base::Value* value, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "SetLocalStatePrefs"); dict.SetString("path", pref); dict.Set("value", value); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } bool SendSetPreferenceJSONRequest( AutomationMessageSender* sender, const std::string& pref, base::Value* value, - std::string* error_msg) { + Error* error) { DictionaryValue dict; dict.SetString("command", "SetPrefs"); dict.SetInteger("windex", 0); dict.SetString("path", pref); dict.Set("value", value); DictionaryValue reply_dict; - return SendAutomationJSONRequest(sender, dict, &reply_dict, error_msg); + return SendAutomationJSONRequest(sender, dict, &reply_dict, error); } diff --git a/chrome/test/automation/automation_json_requests.h b/chrome/test/automation/automation_json_requests.h index 89b1072..4d855b1 100644 --- a/chrome/test/automation/automation_json_requests.h +++ b/chrome/test/automation/automation_json_requests.h @@ -170,7 +170,7 @@ bool SendGetIndicesFromTabIdJSONRequest( int tab_id, int* browser_index, int* tab_index, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests the current browser and tab indices for the given |TabProxy| // handle. Returns true on success. @@ -179,7 +179,7 @@ bool SendGetIndicesFromTabHandleJSONRequest( int tab_proxy_handle, int* browser_index, int* tab_index, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests to navigate to the given url and wait for the given number of // navigations to complete. Returns true on success. @@ -189,7 +189,7 @@ bool SendNavigateToURLJSONRequest( const std::string& url, int navigation_count, AutomationMsg_NavigationResponseValues* nav_response, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests the given javascript to be executed in the frame specified by the // given xpath. Returns true on success. If true, |result| will be set to the @@ -200,28 +200,28 @@ bool SendExecuteJavascriptJSONRequest( const std::string& frame_xpath, const std::string& javascript, base::Value** result, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests the specified view to go forward. Waits for the load to complete. // Returns true on success. bool SendGoForwardJSONRequest( AutomationMessageSender* sender, const WebViewLocator& locator, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests the specified view to go back. Waits for the load to complete. // Returns true on success. bool SendGoBackJSONRequest( AutomationMessageSender* sender, const WebViewLocator& locator, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests the specified view to reload. Waits for the load to complete. // Returns true on success. bool SendReloadJSONRequest( AutomationMessageSender* sender, const WebViewLocator& locator, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests a snapshot of the entire page to be saved to the given path // in PNG format. @@ -230,7 +230,7 @@ bool SendCaptureEntirePageJSONRequest( AutomationMessageSender* sender, const WebViewLocator& locator, const FilePath& path, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests all the cookies for the given URL. On success returns true and // caller takes ownership of |cookies|, which is a list of all the cookies in @@ -239,7 +239,7 @@ bool SendGetCookiesJSONRequest( AutomationMessageSender* sender, const std::string& url, base::ListValue** cookies, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests deletion of the cookie with the given name and URL. Returns true // on success. @@ -247,7 +247,7 @@ bool SendDeleteCookieJSONRequest( AutomationMessageSender* sender, const std::string& url, const std::string& cookie_name, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests setting the given cookie for the given URL. Returns true on // success. The caller retains ownership of |cookie_dict|. @@ -255,26 +255,26 @@ bool SendSetCookieJSONRequest( AutomationMessageSender* sender, const std::string& url, base::DictionaryValue* cookie_dict, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests the IDs for all open tabs. Returns true on success. bool SendGetTabIdsJSONRequest( AutomationMessageSender* sender, std::vector<WebViewInfo>* views, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests info for all open views. Returns true on success. bool SendGetWebViewsJSONRequest( AutomationMessageSender* sender, std::vector<WebViewInfo>* views, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests whether the given tab ID is valid. Returns true on success. bool SendIsTabIdValidJSONRequest( AutomationMessageSender* sender, const WebViewId& view_id, bool* is_valid, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests whether the given automation ID refers to an actual automation // object. Returns true on success. @@ -282,13 +282,13 @@ bool SendDoesAutomationObjectExistJSONRequest( AutomationMessageSender* sender, const WebViewId& view_id, bool* does_exist, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests to close the given view. Returns true on success. bool SendCloseViewJSONRequest( AutomationMessageSender* sender, const WebViewLocator& locator, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests to send the WebKit event for a mouse move to the given // coordinate in the specified view. Returns true on success. @@ -297,7 +297,7 @@ bool SendMouseMoveJSONRequest( const WebViewLocator& locator, int x, int y, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests to send the WebKit events for a mouse click at the given // coordinate in the specified view. Returns true on success. @@ -307,7 +307,7 @@ bool SendMouseClickJSONRequest( automation::MouseButton button, int x, int y, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests to send the WebKit events for a mouse drag from the start to end // coordinates given in the specified view. Returns true on success. @@ -318,7 +318,7 @@ bool SendMouseDragJSONRequest( int start_y, int end_x, int end_y, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests to send the WebKit event for a mouse button down at the given // coordinate in the specified view. Returns true on success. @@ -327,7 +327,7 @@ bool SendMouseButtonDownJSONRequest( const WebViewLocator& locator, int x, int y, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests to send the WebKit event for a mouse button up at the given // coordinate in the specified view. Returns true on success. @@ -336,7 +336,7 @@ bool SendMouseButtonUpJSONRequest( const WebViewLocator& locator, int x, int y, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests to send the WebKit event for a mouse double click at the given // coordinate in the specified view. Returns true on success. @@ -345,7 +345,7 @@ bool SendMouseDoubleClickJSONRequest( const WebViewLocator& locator, int x, int y, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests to send the WebKit event for the given |WebKeyEvent| in a // specified view. Returns true on success. @@ -353,7 +353,7 @@ bool SendWebKeyEventJSONRequest( AutomationMessageSender* sender, const WebViewLocator& locator, const WebKeyEvent& key_event, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests to send the key event for the given keycode+modifiers to a // browser window containing the specified view. Returns true on success. @@ -362,7 +362,7 @@ bool SendNativeKeyEventJSONRequest( const WebViewLocator& locator, ui::KeyboardCode key_code, int modifiers, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests to drag and drop the file paths at the given coordinate in the // specified view. Returns true on success. @@ -372,40 +372,40 @@ bool SendDragAndDropFilePathsJSONRequest( int x, int y, const std::vector<FilePath::StringType>& paths, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests to get the active JavaScript modal dialog's message. Returns true // on success. bool SendGetAppModalDialogMessageJSONRequest( AutomationMessageSender* sender, std::string* message, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests to accept or dismiss the active JavaScript modal dialog. // Returns true on success. bool SendAcceptOrDismissAppModalDialogJSONRequest( AutomationMessageSender* sender, bool accept, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests to accept the active JavaScript modal dialog with the given prompt // text. Returns true on success. bool SendAcceptPromptAppModalDialogJSONRequest( AutomationMessageSender* sender, const std::string& prompt_text, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests to wait for all views to stop loading. Returns true on success. bool SendWaitForAllViewsToStopLoadingJSONRequest( AutomationMessageSender* sender, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests the version of ChromeDriver automation supported by the automation // server. Returns true on success. bool SendGetChromeDriverAutomationVersion( AutomationMessageSender* sender, int* version, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests that the given extension be installed. If |with_ui| is false, // the extension will be installed silently. Returns true on success. @@ -414,13 +414,13 @@ bool SendInstallExtensionJSONRequest( const FilePath& path, bool with_ui, std::string* extension_id, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests info about all installed extensions. Returns true on success. bool SendGetExtensionsInfoJSONRequest( AutomationMessageSender* sender, base::ListValue* extensions_list, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests whether the given extension's page action is visible in the // given tab. @@ -429,7 +429,7 @@ bool SendIsPageActionVisibleJSONRequest( const WebViewId& tab_id, const std::string& extension_id, bool* is_visible, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests a modification of the given extension state. Returns true on // success. @@ -438,7 +438,7 @@ bool SendSetExtensionStateJSONRequest( const std::string& extension_id, bool enable, bool allow_in_incognito, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests the given extension's action button be pressed. Returns true on // success. @@ -446,13 +446,13 @@ bool SendClickExtensionButtonJSONRequest( AutomationMessageSender* sender, const std::string& extension_id, bool browser_action, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests the given extension be uninstalled. Returns true on success. bool SendUninstallExtensionJSONRequest( AutomationMessageSender* sender, const std::string& extension_id, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests the local state preference to be set to the given value. // Ownership of |value| is taken by this function. Returns true on success. @@ -460,7 +460,7 @@ bool SendSetLocalStatePreferenceJSONRequest( AutomationMessageSender* sender, const std::string& pref, base::Value* value, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; // Requests the user preference to be set to the given value. // Ownership of |value| is taken by this function. Returns true on success. @@ -468,6 +468,6 @@ bool SendSetPreferenceJSONRequest( AutomationMessageSender* sender, const std::string& pref, base::Value* value, - std::string* error_msg) WARN_UNUSED_RESULT; + automation::Error* error) WARN_UNUSED_RESULT; #endif // CHROME_TEST_AUTOMATION_AUTOMATION_JSON_REQUESTS_H_ diff --git a/chrome/test/automation/tab_proxy.cc b/chrome/test/automation/tab_proxy.cc index b24c23c..094fee3 100644 --- a/chrome/test/automation/tab_proxy.cc +++ b/chrome/test/automation/tab_proxy.cc @@ -11,6 +11,7 @@ #include "base/string16.h" #include "base/threading/platform_thread.h" #include "base/utf_string_conversions.h" +#include "chrome/common/automation_constants.h" #include "chrome/common/automation_messages.h" #include "chrome/test/automation/automation_json_requests.h" #include "chrome/test/automation/automation_proxy.h" @@ -723,15 +724,15 @@ bool TabProxy::CaptureEntirePageAsPNG(const FilePath& path) { return false; int browser_index, tab_index; - std::string error_msg; + automation::Error error; if (!SendGetIndicesFromTabHandleJSONRequest( - sender_, handle_, &browser_index, &tab_index, &error_msg)) { + sender_, handle_, &browser_index, &tab_index, &error)) { return false; } return SendCaptureEntirePageJSONRequest( sender_, WebViewLocator::ForIndexPair(browser_index, tab_index), - path, &error_msg); + path, &error); } #if defined(OS_WIN) && !defined(USE_AURA) diff --git a/chrome/test/webdriver/test/chromedriver_tests.py b/chrome/test/webdriver/test/chromedriver_tests.py index cae9772..1666f5a 100644 --- a/chrome/test/webdriver/test/chromedriver_tests.py +++ b/chrome/test/webdriver/test/chromedriver_tests.py @@ -815,6 +815,18 @@ class AlertTest(ChromeDriverTest): driver.get(self.GetTestDataUrl() + '/alerts.html') self.assertRaises(WebDriverException, driver.execute_script, 'alert("ok")') + # See http://code.google.com/p/selenium/issues/detail?id=2671. + def testCanPerformJSBasedActionsThatCauseAlertsAtTheEnd(self): + driver = self.GetNewDriver() + driver.execute_script( + 'var select = document.createElement("select");' + + 'select.innerHTML = "<option>1</option><option>2</option>";' + + 'select.addEventListener("change", function() { alert("hi"); });' + + 'document.body.appendChild(select);') + + # Shouldn't throw an exception, even though an alert appears mid-script. + driver.find_elements_by_tag_name('option')[-1].click() + def testMustHandleAlertFirst(self): driver = self.GetNewDriver() driver.get(self.GetTestDataUrl() + '/alerts.html') diff --git a/chrome/test/webdriver/webdriver_automation.cc b/chrome/test/webdriver/webdriver_automation.cc index 7334c16..80e25c5 100644 --- a/chrome/test/webdriver/webdriver_automation.cc +++ b/chrome/test/webdriver/webdriver_automation.cc @@ -286,10 +286,10 @@ void Automation::Init(const BrowserOptions& options, Error** error) { // Check the version of Chrome is compatible with this ChromeDriver. chrome_details += ", version (" + automation()->server_version() + ")"; int version = 0; - std::string error_msg; + automation::Error auto_error; if (!SendGetChromeDriverAutomationVersion( - automation(), &version, &error_msg)) { - *error = new Error(kUnknownError, error_msg + " " + chrome_details); + automation(), &version, &auto_error)) { + *error = Error::FromAutomationError(auto_error); return; } if (version > automation::kChromeDriverAutomationVersion) { @@ -335,11 +335,11 @@ void Automation::ExecuteScript(const WebViewId& view_id, return; Value* unscoped_value; - std::string error_msg; + automation::Error auto_error; if (!SendExecuteJavascriptJSONRequest(automation(), view_locator, frame_path.value(), script, - &unscoped_value, &error_msg)) { - *error = new Error(kUnknownError, error_msg); + &unscoped_value, &auto_error)) { + *error = Error::FromAutomationError(auto_error); return; } scoped_ptr<Value> value(unscoped_value); @@ -355,11 +355,11 @@ void Automation::MouseMove(const WebViewId& view_id, if (*error) return; - std::string error_msg; + automation::Error auto_error; if (!SendMouseMoveJSONRequest( automation(), view_locator, p.rounded_x(), p.rounded_y(), - &error_msg)) { - *error = new Error(kUnknownError, error_msg); + &auto_error)) { + *error = Error::FromAutomationError(auto_error); } } @@ -372,11 +372,11 @@ void Automation::MouseClick(const WebViewId& view_id, if (*error) return; - std::string error_msg; + automation::Error auto_error; if (!SendMouseClickJSONRequest( automation(), view_locator, button, p.rounded_x(), - p.rounded_y(), &error_msg)) { - *error = new Error(kUnknownError, error_msg); + p.rounded_y(), &auto_error)) { + *error = Error::FromAutomationError(auto_error); } } @@ -389,11 +389,11 @@ void Automation::MouseDrag(const WebViewId& view_id, if (*error) return; - std::string error_msg; + automation::Error auto_error; if (!SendMouseDragJSONRequest( automation(), view_locator, start.rounded_x(), start.rounded_y(), - end.rounded_x(), end.rounded_y(), &error_msg)) { - *error = new Error(kUnknownError, error_msg); + end.rounded_x(), end.rounded_y(), &auto_error)) { + *error = Error::FromAutomationError(auto_error); } } @@ -409,11 +409,11 @@ void Automation::MouseButtonUp(const WebViewId& view_id, if (*error) return; - std::string error_msg; + automation::Error auto_error; if (!SendMouseButtonUpJSONRequest( automation(), view_locator, p.rounded_x(), p.rounded_y(), - &error_msg)) { - *error = new Error(kUnknownError, error_msg); + &auto_error)) { + *error = Error::FromAutomationError(auto_error); } } @@ -429,11 +429,11 @@ void Automation::MouseButtonDown(const WebViewId& view_id, if (*error) return; - std::string error_msg; + automation::Error auto_error; if (!SendMouseButtonDownJSONRequest( automation(), view_locator, p.rounded_x(), p.rounded_y(), - &error_msg)) { - *error = new Error(kUnknownError, error_msg); + &auto_error)) { + *error = Error::FromAutomationError(auto_error); } } @@ -449,11 +449,11 @@ void Automation::MouseDoubleClick(const WebViewId& view_id, if (*error) return; - std::string error_msg; + automation::Error auto_error; if (!SendMouseDoubleClickJSONRequest( automation(), view_locator, p.rounded_x(), p.rounded_y(), - &error_msg)) { - *error = new Error(kUnknownError, error_msg); + &auto_error)) { + *error = Error::FromAutomationError(auto_error); } } @@ -466,11 +466,11 @@ void Automation::DragAndDropFilePaths( return; } - std::string error_msg; + automation::Error auto_error; if (!SendDragAndDropFilePathsJSONRequest( automation(), view_locator, location.rounded_x(), - location.rounded_y(), paths, &error_msg)) { - *error = new Error(kUnknownError, error_msg); + location.rounded_y(), paths, &auto_error)) { + *error = Error::FromAutomationError(auto_error); } } @@ -482,10 +482,10 @@ void Automation::SendWebKeyEvent(const WebViewId& view_id, if (*error) return; - std::string error_msg; + automation::Error auto_error; if (!SendWebKeyEventJSONRequest( - automation(), view_locator, key_event, &error_msg)) { - *error = new Error(kUnknownError, error_msg); + automation(), view_locator, key_event, &auto_error)) { + *error = Error::FromAutomationError(auto_error); } } @@ -498,10 +498,10 @@ void Automation::SendNativeKeyEvent(const WebViewId& view_id, if (*error) return; - std::string error_msg; + automation::Error auto_error; if (!SendNativeKeyEventJSONRequest( - automation(), view_locator, key_code, modifiers, &error_msg)) { - *error = new Error(kUnknownError, error_msg); + automation(), view_locator, key_code, modifiers, &auto_error)) { + *error = Error::FromAutomationError(auto_error); } } @@ -513,10 +513,10 @@ void Automation::CaptureEntirePageAsPNG(const WebViewId& view_id, if (*error) return; - std::string error_msg; + automation::Error auto_error; if (!SendCaptureEntirePageJSONRequest( - automation(), view_locator, path, &error_msg)) { - *error = new Error(kUnknownError, error_msg); + automation(), view_locator, path, &auto_error)) { + *error = Error::FromAutomationError(auto_error); } } @@ -529,11 +529,11 @@ void Automation::NavigateToURL(const WebViewId& view_id, return; AutomationMsg_NavigationResponseValues navigate_response; - std::string error_msg; + automation::Error auto_error; if (!SendNavigateToURLJSONRequest(automation(), view_locator, url, 1, &navigate_response, - &error_msg)) { - *error = new Error(kUnknownError, error_msg); + &auto_error)) { + *error = Error::FromAutomationError(auto_error); return; } // TODO(kkania): Do not rely on this enum. @@ -549,12 +549,12 @@ void Automation::NavigateToURLAsync(const WebViewId& view_id, if (*error) return; - std::string error_msg; + automation::Error auto_error; if (!view_id.old_style()) { AutomationMsg_NavigationResponseValues navigate_response; if (!SendNavigateToURLJSONRequest(automation(), view_locator, url, - 0, &navigate_response, &error_msg)) { - *error = new Error(kUnknownError, error_msg); + 0, &navigate_response, &auto_error)) { + *error = Error::FromAutomationError(auto_error); return; } } else { @@ -582,10 +582,10 @@ void Automation::GoForward(const WebViewId& view_id, Error** error) { if (*error) return; - std::string error_msg; + automation::Error auto_error; if (!SendGoForwardJSONRequest( - automation(), view_locator, &error_msg)) { - *error = new Error(kUnknownError, error_msg); + automation(), view_locator, &auto_error)) { + *error = Error::FromAutomationError(auto_error); } } @@ -595,9 +595,9 @@ void Automation::GoBack(const WebViewId& view_id, Error** error) { if (*error) return; - std::string error_msg; - if (!SendGoBackJSONRequest(automation(), view_locator, &error_msg)) - *error = new Error(kUnknownError, error_msg); + automation::Error auto_error; + if (!SendGoBackJSONRequest(automation(), view_locator, &auto_error)) + *error = Error::FromAutomationError(auto_error); } void Automation::Reload(const WebViewId& view_id, Error** error) { @@ -606,35 +606,35 @@ void Automation::Reload(const WebViewId& view_id, Error** error) { if (*error) return; - std::string error_msg; - if (!SendReloadJSONRequest(automation(), view_locator, &error_msg)) - *error = new Error(kUnknownError, error_msg); + automation::Error auto_error; + if (!SendReloadJSONRequest(automation(), view_locator, &auto_error)) + *error = Error::FromAutomationError(auto_error); } void Automation::GetCookies(const std::string& url, ListValue** cookies, Error** error) { - std::string error_msg; - if (!SendGetCookiesJSONRequest(automation(), url, cookies, &error_msg)) - *error = new Error(kUnknownError, error_msg); + automation::Error auto_error; + if (!SendGetCookiesJSONRequest(automation(), url, cookies, &auto_error)) + *error = Error::FromAutomationError(auto_error); } void Automation::DeleteCookie(const std::string& url, const std::string& cookie_name, Error** error) { - std::string error_msg; + automation::Error auto_error; if (!SendDeleteCookieJSONRequest( - automation(), url, cookie_name, &error_msg)) { - *error = new Error(kUnknownError, error_msg); + automation(), url, cookie_name, &auto_error)) { + *error = Error::FromAutomationError(auto_error); } } void Automation::SetCookie(const std::string& url, DictionaryValue* cookie_dict, Error** error) { - std::string error_msg; - if (!SendSetCookieJSONRequest(automation(), url, cookie_dict, &error_msg)) - *error = new Error(kUnknownError, error_msg); + automation::Error auto_error; + if (!SendSetCookieJSONRequest(automation(), url, cookie_dict, &auto_error)) + *error = Error::FromAutomationError(auto_error); } void Automation::GetViews(std::vector<WebViewInfo>* views, @@ -644,27 +644,27 @@ void Automation::GetViews(std::vector<WebViewInfo>* views, if (*error) return; - std::string error_msg; + automation::Error auto_error; if (has_views) { - if (!SendGetWebViewsJSONRequest(automation(), views, &error_msg)) - *error = new Error(kUnknownError, error_msg); + if (!SendGetWebViewsJSONRequest(automation(), views, &auto_error)) + *error = Error::FromAutomationError(auto_error); } else { - if (!SendGetTabIdsJSONRequest(automation(), views, &error_msg)) - *error = new Error(kUnknownError, error_msg); + if (!SendGetTabIdsJSONRequest(automation(), views, &auto_error)) + *error = Error::FromAutomationError(auto_error); } } void Automation::DoesViewExist( const WebViewId& view_id, bool* does_exist, Error** error) { - std::string error_msg; + automation::Error auto_error; if (view_id.old_style()) { if (!SendIsTabIdValidJSONRequest( - automation(), view_id, does_exist, &error_msg)) - *error = new Error(kUnknownError, error_msg); + automation(), view_id, does_exist, &auto_error)) + *error = Error::FromAutomationError(auto_error); } else { if (!SendDoesAutomationObjectExistJSONRequest( - automation(), view_id, does_exist, &error_msg)) - *error = new Error(kUnknownError, error_msg); + automation(), view_id, does_exist, &auto_error)) + *error = Error::FromAutomationError(auto_error); } } @@ -674,9 +674,9 @@ void Automation::CloseView(const WebViewId& view_id, Error** error) { if (*error) return; - std::string error_msg; - if (!SendCloseViewJSONRequest(automation(), view_locator, &error_msg)) - *error = new Error(kUnknownError, error_msg); + automation::Error auto_error; + if (!SendCloseViewJSONRequest(automation(), view_locator, &auto_error)) + *error = Error::FromAutomationError(auto_error); } void Automation::GetAppModalDialogMessage(std::string* message, Error** error) { @@ -684,10 +684,10 @@ void Automation::GetAppModalDialogMessage(std::string* message, Error** error) { if (*error) return; - std::string error_msg; + automation::Error auto_error; if (!SendGetAppModalDialogMessageJSONRequest( - automation(), message, &error_msg)) { - *error = new Error(kUnknownError, error_msg); + automation(), message, &auto_error)) { + *error = Error::FromAutomationError(auto_error); } } @@ -696,10 +696,10 @@ void Automation::AcceptOrDismissAppModalDialog(bool accept, Error** error) { if (*error) return; - std::string error_msg; + automation::Error auto_error; if (!SendAcceptOrDismissAppModalDialogJSONRequest( - automation(), accept, &error_msg)) { - *error = new Error(kUnknownError, error_msg); + automation(), accept, &auto_error)) { + *error = Error::FromAutomationError(auto_error); } } @@ -709,10 +709,10 @@ void Automation::AcceptPromptAppModalDialog(const std::string& prompt_text, if (*error) return; - std::string error_msg; + automation::Error auto_error; if (!SendAcceptPromptAppModalDialogJSONRequest( - automation(), prompt_text, &error_msg)) { - *error = new Error(kUnknownError, error_msg); + automation(), prompt_text, &auto_error)) { + *error = Error::FromAutomationError(auto_error); } } @@ -721,15 +721,15 @@ void Automation::GetBrowserVersion(std::string* version) { } void Automation::GetChromeDriverAutomationVersion(int* version, Error** error) { - std::string error_msg; - if (!SendGetChromeDriverAutomationVersion(automation(), version, &error_msg)) - *error = new Error(kUnknownError, error_msg); + automation::Error auto_error; + if (!SendGetChromeDriverAutomationVersion(automation(), version, &auto_error)) + *error = Error::FromAutomationError(auto_error); } void Automation::WaitForAllViewsToStopLoading(Error** error) { - std::string error_msg; - if (!SendWaitForAllViewsToStopLoadingJSONRequest(automation(), &error_msg)) - *error = new Error(kUnknownError, error_msg); + automation::Error auto_error; + if (!SendWaitForAllViewsToStopLoadingJSONRequest(automation(), &auto_error)) + *error = Error::FromAutomationError(auto_error); } void Automation::InstallExtensionDeprecated( @@ -744,11 +744,11 @@ void Automation::InstallExtension( if (*error) return; - std::string error_msg; + automation::Error auto_error; if (!SendInstallExtensionJSONRequest( automation(), path, false /* with_ui */, extension_id, - &error_msg)) - *error = new Error(kUnknownError, error_msg); + &auto_error)) + *error = Error::FromAutomationError(auto_error); } void Automation::GetExtensionsInfo( @@ -757,10 +757,10 @@ void Automation::GetExtensionsInfo( if (*error) return; - std::string error_msg; + automation::Error auto_error; if (!SendGetExtensionsInfoJSONRequest( - automation(), extensions_list, &error_msg)) - *error = new Error(kUnknownError, error_msg); + automation(), extensions_list, &auto_error)) + *error = Error::FromAutomationError(auto_error); } void Automation::IsPageActionVisible( @@ -772,10 +772,10 @@ void Automation::IsPageActionVisible( if (*error) return; - std::string error_msg; + automation::Error auto_error; if (!SendIsPageActionVisibleJSONRequest( - automation(), tab_id, extension_id, is_visible, &error_msg)) - *error = new Error(kUnknownError, error_msg); + automation(), tab_id, extension_id, is_visible, &auto_error)) + *error = Error::FromAutomationError(auto_error); } void Automation::SetExtensionState( @@ -786,21 +786,21 @@ void Automation::SetExtensionState( if (*error) return; - std::string error_msg; + automation::Error auto_error; if (!SendSetExtensionStateJSONRequest( automation(), extension_id, enable /* enable */, - false /* allow_in_incognito */, &error_msg)) - *error = new Error(kUnknownError, error_msg); + false /* allow_in_incognito */, &auto_error)) + *error = Error::FromAutomationError(auto_error); } void Automation::ClickExtensionButton( const std::string& extension_id, bool browser_action, Error** error) { - std::string error_msg; + automation::Error auto_error; if (!SendClickExtensionButtonJSONRequest( - automation(), extension_id, browser_action, &error_msg)) - *error = new Error(kUnknownError, error_msg); + automation(), extension_id, browser_action, &auto_error)) + *error = Error::FromAutomationError(auto_error); } void Automation::UninstallExtension( @@ -809,10 +809,10 @@ void Automation::UninstallExtension( if (*error) return; - std::string error_msg; + automation::Error auto_error; if (!SendUninstallExtensionJSONRequest( - automation(), extension_id, &error_msg)) - *error = new Error(kUnknownError, error_msg); + automation(), extension_id, &auto_error)) + *error = Error::FromAutomationError(auto_error); } void Automation::SetLocalStatePreference(const std::string& pref, @@ -827,10 +827,10 @@ void Automation::SetLocalStatePreference(const std::string& pref, return; if (has_new_local_state_api) { - std::string error_msg; + automation::Error auto_error; if (!SendSetLocalStatePreferenceJSONRequest( - automation(), pref, scoped_value.release(), &error_msg)) - *error = new Error(kUnknownError, error_msg); + automation(), pref, scoped_value.release(), &auto_error)) + *error = Error::FromAutomationError(auto_error); } else { std::string request, response; DictionaryValue request_dict; @@ -858,10 +858,10 @@ void Automation::SetPreference(const std::string& pref, return; if (has_new_pref_api) { - std::string error_msg; + automation::Error auto_error; if (!SendSetPreferenceJSONRequest( - automation(), pref, scoped_value.release(), &error_msg)) - *error = new Error(kUnknownError, error_msg); + automation(), pref, scoped_value.release(), &auto_error)) + *error = Error::FromAutomationError(auto_error); } else { std::string request, response; DictionaryValue request_dict; @@ -886,11 +886,11 @@ Error* Automation::ConvertViewIdToLocator( const WebViewId& view_id, WebViewLocator* view_locator) { if (view_id.old_style()) { int browser_index, tab_index; - std::string error_msg; + automation::Error auto_error; if (!SendGetIndicesFromTabIdJSONRequest( automation(), view_id.tab_id(), &browser_index, &tab_index, - &error_msg)) - return new Error(kUnknownError, error_msg); + &auto_error)) + return Error::FromAutomationError(auto_error); *view_locator = WebViewLocator::ForIndexPair(browser_index, tab_index); } else { *view_locator = WebViewLocator::ForViewId(view_id.GetId()); diff --git a/chrome/test/webdriver/webdriver_error.cc b/chrome/test/webdriver/webdriver_error.cc index 200d797..0884e10 100644 --- a/chrome/test/webdriver/webdriver_error.cc +++ b/chrome/test/webdriver/webdriver_error.cc @@ -6,6 +6,8 @@ #include <sstream> +#include "chrome/common/automation_constants.h" + namespace webdriver { namespace { @@ -39,6 +41,10 @@ const char* DefaultMessageForErrorCode(ErrorCode code) { return "The cookie domain is invalid"; case kUnableToSetCookie: return "Unable to set cookie"; + case kUnexpectedAlertOpen: + return "An open modal dialog blocked the operation"; + case kNoAlertOpenError: + return "No JavaScript modal dialog is open"; default: return "<unknown>"; } @@ -46,6 +52,46 @@ const char* DefaultMessageForErrorCode(ErrorCode code) { } // namespace +// static +Error* Error::FromAutomationError(const automation::Error& error) { + ErrorCode code = kUnknownError; + switch (error.code()) { + case automation::kNoJavaScriptModalDialogOpen: + code = kNoAlertOpenError; + break; + case automation::kBlockedByModalDialog: + code = kUnexpectedAlertOpen; + break; + default: + break; + } + + // In Chrome 17 and before, the automation error was just a string. + // Compare against some strings that correspond to webdriver errors. + // TODO(kkania): Remove these comparisons when Chrome 17 is unsupported. + if (code == kUnknownError) { + if (error.message() == + "Command cannot be performed because a modal dialog is active" || + error.message() == + "Could not complete script execution because a modal " + "dialog is active") { + code = kUnexpectedAlertOpen; + } else if (error.message() == "No modal dialog is showing" || + error.message() == "No JavaScript modal dialog is showing") { + code = kNoAlertOpenError; + } + } + + // If the automation error code did not refer to a webdriver error code + // (besides unknown), include the error message from chrome. Otherwise, + // include the webdriver error code and the webdriver error message. + if (code == kUnknownError) { + return new Error(code, error.message()); + } else { + return new Error(code); + } +} + Error::Error(ErrorCode code) : code_(code), details_(DefaultMessageForErrorCode(code)) { diff --git a/chrome/test/webdriver/webdriver_error.h b/chrome/test/webdriver/webdriver_error.h index 0ed0c51..dbc7229d 100644 --- a/chrome/test/webdriver/webdriver_error.h +++ b/chrome/test/webdriver/webdriver_error.h @@ -10,6 +10,10 @@ #include "base/basictypes.h" +namespace automation { +class Error; +} + namespace webdriver { // Error codes defined by the WebDriver wire protcol. @@ -28,6 +32,8 @@ enum ErrorCode { kNoSuchWindow = 23, kInvalidCookieDomain = 24, kUnableToSetCookie = 25, + kUnexpectedAlertOpen = 26, + kNoAlertOpenError = 27, // HTTP status codes. kSeeOther = 303, @@ -40,6 +46,8 @@ enum ErrorCode { // Represents a WebDriver error and the context within which the error occurred. class Error { public: + static Error* FromAutomationError(const automation::Error& error); + explicit Error(ErrorCode code); Error(ErrorCode code, const std::string& details); diff --git a/chrome/test/webdriver/webdriver_session.cc b/chrome/test/webdriver/webdriver_session.cc index e1a25c6..c5b1c16 100644 --- a/chrome/test/webdriver/webdriver_session.cc +++ b/chrome/test/webdriver/webdriver_session.cc @@ -921,12 +921,22 @@ Error* Session::IsOptionElementSelected(const FrameId& frame_id, Error* Session::SetOptionElementSelected(const FrameId& frame_id, const ElementId& element, bool selected) { - return ExecuteScriptAndParse( + // This wrapper ensures the script is started successfully and + // allows for an alert to happen when the option selection occurs. + // See selenium bug 2671. + const char kSetSelectedWrapper[] = + "var args = [].slice.apply(arguments);" + "args[args.length - 1]();" + "return (%s).apply(null, args.slice(0, args.length - 1));"; + Value* value = NULL; + Error* error = ExecuteAsyncScript( frame_id, - atoms::asString(atoms::SET_SELECTED), - "setSelected", + base::StringPrintf(kSetSelectedWrapper, + atoms::asString(atoms::SET_SELECTED).c_str()), CreateListValueFrom(element, selected), - CreateDirectValueParser(kSkipParsing)); + &value); + scoped_ptr<Value> scoped_value(value); + return error; } Error* Session::ToggleOptionElement(const FrameId& frame_id, |