Index: chrome/test/webdriver/webdriver_session.cc |
diff --git a/chrome/test/webdriver/webdriver_session.cc b/chrome/test/webdriver/webdriver_session.cc |
deleted file mode 100644 |
index d60c77a09972065e28a99eadc531fe2908b64af4..0000000000000000000000000000000000000000 |
--- a/chrome/test/webdriver/webdriver_session.cc |
+++ /dev/null |
@@ -1,1947 +0,0 @@ |
-// Copyright (c) 2012 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_session.h" |
- |
-#include <sstream> |
-#include <vector> |
- |
-#include "base/bind.h" |
-#include "base/callback.h" |
-#include "base/command_line.h" |
-#include "base/file_util.h" |
-#include "base/files/file_path.h" |
-#include "base/json/json_reader.h" |
-#include "base/json/json_writer.h" |
-#include "base/memory/scoped_ptr.h" |
-#include "base/message_loop/message_loop_proxy.h" |
-#include "base/process/process.h" |
-#include "base/strings/string_number_conversions.h" |
-#include "base/strings/string_split.h" |
-#include "base/strings/string_util.h" |
-#include "base/strings/stringprintf.h" |
-#include "base/strings/utf_string_conversions.h" |
-#include "base/synchronization/waitable_event.h" |
-#include "base/test/test_timeouts.h" |
-#include "base/threading/platform_thread.h" |
-#include "base/time/time.h" |
-#include "base/values.h" |
-#include "chrome/app/chrome_command_ids.h" |
-#include "chrome/common/chrome_constants.h" |
-#include "chrome/common/chrome_switches.h" |
-#include "chrome/test/automation/automation_json_requests.h" |
-#include "chrome/test/automation/value_conversion_util.h" |
-#include "chrome/test/webdriver/webdriver_capabilities_parser.h" |
-#include "chrome/test/webdriver/webdriver_error.h" |
-#include "chrome/test/webdriver/webdriver_key_converter.h" |
-#include "chrome/test/webdriver/webdriver_logging.h" |
-#include "chrome/test/webdriver/webdriver_session_manager.h" |
-#include "chrome/test/webdriver/webdriver_util.h" |
-#include "third_party/webdriver/atoms.h" |
- |
-using automation::kLeftButton; |
-using automation::kMouseDown; |
-using automation::kMouseMove; |
-using automation::kMouseUp; |
-using automation::kNoButton; |
- |
-namespace webdriver { |
- |
-namespace { |
-// This is the minimum version of chrome that supports the new mouse API. |
-const int kNewMouseAPIMinVersion = 1002; |
-} |
- |
-FrameId::FrameId() {} |
- |
-FrameId::FrameId(const WebViewId& view_id, const FramePath& frame_path) |
- : view_id(view_id), |
- frame_path(frame_path) { |
-} |
- |
-Session::Session() |
- : session_log_(new InMemoryLog()), |
- logger_(kAllLogLevel), |
- id_(GenerateRandomID()), |
- current_target_(FrameId(WebViewId(), FramePath())), |
- thread_(id_.c_str()), |
- async_script_timeout_(0), |
- implicit_wait_(0), |
- has_alert_prompt_text_(false), |
- sticky_modifiers_(0), |
- build_no_(0) { |
- SessionManager::GetInstance()->Add(this); |
- logger_.AddHandler(session_log_.get()); |
- if (FileLog::Get()) |
- logger_.AddHandler(FileLog::Get()); |
-} |
- |
-Session::~Session() { |
- SessionManager::GetInstance()->Remove(id_); |
-} |
- |
-Error* Session::Init(const base::DictionaryValue* capabilities_dict) { |
- if (!thread_.Start()) { |
- delete this; |
- return new Error(kUnknownError, "Cannot start session thread"); |
- } |
- if (!temp_dir_.CreateUniqueTempDir()) { |
- delete this; |
- return new Error( |
- kUnknownError, "Unable to create temp directory for unpacking"); |
- } |
- logger_.Log(kFineLogLevel, |
- "Initializing session with capabilities " + |
- JsonStringifyForDisplay(capabilities_dict)); |
- CapabilitiesParser parser( |
- capabilities_dict, temp_dir_.path(), logger_, &capabilities_); |
- Error* error = parser.Parse(); |
- if (error) { |
- delete this; |
- return error; |
- } |
- logger_.set_min_log_level(capabilities_.log_levels[LogType::kDriver]); |
- |
- Automation::BrowserOptions browser_options; |
- browser_options.command = capabilities_.command; |
- browser_options.channel_id = capabilities_.channel; |
- browser_options.detach_process = capabilities_.detach; |
- browser_options.user_data_dir = capabilities_.profile; |
- browser_options.exclude_switches = capabilities_.exclude_switches; |
- if (!capabilities_.no_website_testing_defaults) { |
- browser_options.ignore_certificate_errors = true; |
- } |
- RunSessionTask(base::Bind( |
- &Session::InitOnSessionThread, |
- base::Unretained(this), |
- browser_options, |
- &build_no_, |
- &error)); |
- if (!error) |
- error = PostBrowserStartInit(); |
- |
- if (error) |
- Terminate(); |
- return error; |
-} |
- |
-Error* Session::BeforeExecuteCommand() { |
- Error* error = AfterExecuteCommand(); |
- if (!error) { |
- scoped_ptr<Error> switch_error(SwitchToTopFrameIfCurrentFrameInvalid()); |
- if (switch_error.get()) { |
- std::string text; |
- scoped_ptr<Error> alert_error(GetAlertMessage(&text)); |
- if (alert_error.get()) { |
- // Only return a frame checking error if a modal dialog is not present. |
- // TODO(kkania): This is ugly. Fix. |
- return switch_error.release(); |
- } |
- } |
- } |
- return error; |
-} |
- |
-Error* Session::AfterExecuteCommand() { |
- Error* error = NULL; |
- if (!capabilities_.load_async) { |
- error = WaitForAllViewsToStopLoading(); |
- } |
- return error; |
-} |
- |
-void Session::Terminate() { |
- RunSessionTask(base::Bind( |
- &Session::TerminateOnSessionThread, |
- base::Unretained(this))); |
- delete this; |
-} |
- |
-Error* Session::ExecuteScript(const FrameId& frame_id, |
- const std::string& script, |
- const base::ListValue* const args, |
- base::Value** value) { |
- std::string args_as_json; |
- base::JSONWriter::Write(static_cast<const base::Value* const>(args), |
- &args_as_json); |
- |
- // Every injected script is fed through the executeScript atom. This atom |
- // will catch any errors that are thrown and convert them to the |
- // appropriate JSON structure. |
- std::string jscript = base::StringPrintf( |
- "window.domAutomationController.send((%s).apply(null," |
- "[function(){%s\n},%s,true]));", |
- atoms::asString(atoms::EXECUTE_SCRIPT).c_str(), script.c_str(), |
- args_as_json.c_str()); |
- |
- return ExecuteScriptAndParseValue(frame_id, jscript, value); |
-} |
- |
-Error* Session::ExecuteScript(const std::string& script, |
- const base::ListValue* const args, |
- base::Value** value) { |
- 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 base::ListValue* args, |
- const ValueParser* parser) { |
- scoped_ptr<const base::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()); |
- base::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<base::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 base::ListValue* const args, |
- base::Value** value) { |
- std::string args_as_json; |
- base::JSONWriter::Write(static_cast<const base::Value* const>(args), |
- &args_as_json); |
- |
- int timeout_ms = async_script_timeout(); |
- |
- // Every injected script is fed through the executeScript atom. This atom |
- // will catch any errors that are thrown and convert them to the |
- // appropriate JSON structure. |
- std::string jscript = base::StringPrintf( |
- "(%s).apply(null, [function(){%s},%s,%d,%s,true]);", |
- atoms::asString(atoms::EXECUTE_ASYNC_SCRIPT).c_str(), |
- script.c_str(), |
- args_as_json.c_str(), |
- timeout_ms, |
- "function(result) {window.domAutomationController.send(result);}"); |
- |
- return ExecuteScriptAndParseValue(frame_id, jscript, value); |
-} |
- |
-Error* Session::SendKeys(const ElementId& element, const string16& keys) { |
- bool is_displayed = false; |
- Error* error = IsElementDisplayed( |
- current_target_, element, true /* ignore_opacity */, &is_displayed); |
- if (error) |
- return error; |
- if (!is_displayed) |
- return new Error(kElementNotVisible); |
- |
- bool is_enabled = false; |
- error = IsElementEnabled(current_target_, element, &is_enabled); |
- if (error) |
- return error; |
- if (!is_enabled) |
- return new Error(kInvalidElementState); |
- |
- // 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, |
- // because this may cause us to lose the current cursor position in the |
- // element. |
- // Secondly, we focus the target element. |
- // Thirdly, if the target element is newly focused and is a text input, we |
- // set the cursor position at the end. |
- // Fourthly, we check if the new active element is the target element. If not, |
- // we throw an error. |
- // Additional notes: |
- // - |document.activeElement| is the currently focused element, or body if |
- // no element is focused |
- // - Even if |document.hasFocus()| returns true and the active element is |
- // the body, sometimes we still need to focus the body element for send |
- // keys to work. Not sure why |
- // - You cannot focus a descendant of a content editable node |
- // - V8 throws a TypeError when calling setSelectionRange for a non-text |
- // input, which still have setSelectionRange defined. |
- // TODO(jleyba): Update this to use the correct atom. |
- const char* kFocusScript = |
- "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) {" |
- " try {" |
- " elem.setSelectionRange(elem.value.length, elem.value.length);" |
- " } catch (error) {" |
- " if (!(error instanceof TypeError)) {" |
- " throw error;" |
- " }" |
- " }" |
- " }" |
- " 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; |
- |
- RunSessionTask(base::Bind( |
- &Session::SendKeysOnSessionThread, |
- base::Unretained(this), |
- keys, |
- true /* release_modifiers */, |
- &error)); |
- return error; |
-} |
- |
-Error* Session::SendKeys(const string16& keys) { |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Session::SendKeysOnSessionThread, |
- base::Unretained(this), |
- keys, |
- false /* release_modifiers */, |
- &error)); |
- return error; |
-} |
- |
-Error* Session::DragAndDropFilePaths( |
- const Point& location, |
- const std::vector<base::FilePath::StringType>& paths) { |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::DragAndDropFilePaths, |
- base::Unretained(automation_.get()), |
- current_target_.view_id, |
- location, |
- paths, |
- &error)); |
- return error; |
-} |
- |
-Error* Session::NavigateToURL(const std::string& url) { |
- if (!current_target_.view_id.IsTab()) { |
- return new Error(kUnknownError, |
- "The current target does not support navigation"); |
- } |
- Error* error = NULL; |
- if (capabilities_.load_async) { |
- RunSessionTask(base::Bind( |
- &Automation::NavigateToURLAsync, |
- base::Unretained(automation_.get()), |
- current_target_.view_id, |
- url, |
- &error)); |
- } else { |
- RunSessionTask(base::Bind( |
- &Automation::NavigateToURL, |
- base::Unretained(automation_.get()), |
- current_target_.view_id, |
- url, |
- &error)); |
- } |
- return error; |
-} |
- |
-Error* Session::GoForward() { |
- if (!current_target_.view_id.IsTab()) { |
- return new Error(kUnknownError, |
- "The current target does not support navigation"); |
- } |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::GoForward, |
- base::Unretained(automation_.get()), |
- current_target_.view_id, |
- &error)); |
- return error; |
-} |
- |
-Error* Session::GoBack() { |
- if (!current_target_.view_id.IsTab()) { |
- return new Error(kUnknownError, |
- "The current target does not support navigation"); |
- } |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::GoBack, |
- base::Unretained(automation_.get()), |
- current_target_.view_id, |
- &error)); |
- return error; |
-} |
- |
-Error* Session::Reload() { |
- if (!current_target_.view_id.IsTab()) { |
- return new Error(kUnknownError, |
- "The current target does not support navigation"); |
- } |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::Reload, |
- base::Unretained(automation_.get()), |
- current_target_.view_id, |
- &error)); |
- return error; |
-} |
- |
-Error* Session::GetURL(std::string* url) { |
- return ExecuteScriptAndParse(current_target_, |
- "function() { return document.URL }", |
- "getUrl", |
- new base::ListValue(), |
- CreateDirectValueParser(url)); |
-} |
- |
-Error* Session::GetTitle(std::string* tab_title) { |
- const char* kGetTitleScript = |
- "function() {" |
- " if (document.title)" |
- " return document.title;" |
- " else" |
- " return document.URL;" |
- "}"; |
- return ExecuteScriptAndParse(FrameId(current_target_.view_id, FramePath()), |
- kGetTitleScript, |
- "getTitle", |
- new base::ListValue(), |
- CreateDirectValueParser(tab_title)); |
-} |
- |
-Error* Session::MouseMoveAndClick(const Point& location, |
- automation::MouseButton button) { |
- Error* error = NULL; |
- if (build_no_ >= kNewMouseAPIMinVersion) { |
- std::vector<WebMouseEvent> events; |
- events.push_back(CreateWebMouseEvent(kMouseMove, kNoButton, location, 0)); |
- events.push_back(CreateWebMouseEvent(kMouseDown, button, location, 1)); |
- events.push_back(CreateWebMouseEvent(kMouseUp, button, location, 1)); |
- error = ProcessWebMouseEvents(events); |
- } else { |
- RunSessionTask(base::Bind( |
- &Automation::MouseClickDeprecated, |
- base::Unretained(automation_.get()), |
- current_target_.view_id, |
- location, |
- button, |
- &error)); |
- } |
- if (!error) |
- mouse_position_ = location; |
- return error; |
-} |
- |
-Error* Session::MouseMove(const Point& location) { |
- Error* error = NULL; |
- if (build_no_ >= kNewMouseAPIMinVersion) { |
- std::vector<WebMouseEvent> events; |
- events.push_back(CreateWebMouseEvent(kMouseMove, kNoButton, location, 0)); |
- error = ProcessWebMouseEvents(events); |
- } else { |
- RunSessionTask(base::Bind( |
- &Automation::MouseMoveDeprecated, |
- base::Unretained(automation_.get()), |
- current_target_.view_id, |
- location, |
- &error)); |
- } |
- if (!error) |
- mouse_position_ = location; |
- return error; |
-} |
- |
-Error* Session::MouseDrag(const Point& start, |
- const Point& end) { |
- Error* error = NULL; |
- if (build_no_ >= kNewMouseAPIMinVersion) { |
- std::vector<WebMouseEvent> events; |
- events.push_back(CreateWebMouseEvent(kMouseMove, kNoButton, start, 0)); |
- events.push_back(CreateWebMouseEvent(kMouseDown, kLeftButton, start, 1)); |
- events.push_back(CreateWebMouseEvent(kMouseMove, kLeftButton, end, 0)); |
- events.push_back(CreateWebMouseEvent(kMouseUp, kLeftButton, end, 1)); |
- error = ProcessWebMouseEvents(events); |
- } else { |
- RunSessionTask(base::Bind( |
- &Automation::MouseDragDeprecated, |
- base::Unretained(automation_.get()), |
- current_target_.view_id, |
- start, |
- end, |
- &error)); |
- } |
- if (!error) |
- mouse_position_ = end; |
- return error; |
-} |
- |
-Error* Session::MouseClick(automation::MouseButton button) { |
- if (build_no_ >= kNewMouseAPIMinVersion) { |
- std::vector<WebMouseEvent> events; |
- events.push_back(CreateWebMouseEvent( |
- kMouseDown, button, mouse_position_, 1)); |
- events.push_back(CreateWebMouseEvent( |
- kMouseUp, button, mouse_position_, 1)); |
- return ProcessWebMouseEvents(events); |
- } else { |
- return MouseMoveAndClick(mouse_position_, button); |
- } |
-} |
- |
-Error* Session::MouseButtonDown() { |
- Error* error = NULL; |
- if (build_no_ >= kNewMouseAPIMinVersion) { |
- std::vector<WebMouseEvent> events; |
- events.push_back(CreateWebMouseEvent( |
- kMouseDown, kLeftButton, mouse_position_, 1)); |
- error = ProcessWebMouseEvents(events); |
- } else { |
- RunSessionTask(base::Bind( |
- &Automation::MouseButtonDownDeprecated, |
- base::Unretained(automation_.get()), |
- current_target_.view_id, |
- mouse_position_, |
- &error)); |
- } |
- return error; |
-} |
- |
-Error* Session::MouseButtonUp() { |
- Error* error = NULL; |
- if (build_no_ >= kNewMouseAPIMinVersion) { |
- std::vector<WebMouseEvent> events; |
- events.push_back(CreateWebMouseEvent( |
- kMouseUp, kLeftButton, mouse_position_, 1)); |
- error = ProcessWebMouseEvents(events); |
- } else { |
- RunSessionTask(base::Bind( |
- &Automation::MouseButtonUpDeprecated, |
- base::Unretained(automation_.get()), |
- current_target_.view_id, |
- mouse_position_, |
- &error)); |
- } |
- return error; |
-} |
- |
-Error* Session::MouseDoubleClick() { |
- Error* error = NULL; |
- if (build_no_ >= kNewMouseAPIMinVersion) { |
- std::vector<WebMouseEvent> events; |
- events.push_back(CreateWebMouseEvent( |
- kMouseDown, kLeftButton, mouse_position_, 1)); |
- events.push_back(CreateWebMouseEvent( |
- kMouseUp, kLeftButton, mouse_position_, 1)); |
- events.push_back(CreateWebMouseEvent( |
- kMouseDown, kLeftButton, mouse_position_, 2)); |
- events.push_back(CreateWebMouseEvent( |
- kMouseUp, kLeftButton, mouse_position_, 2)); |
- error = ProcessWebMouseEvents(events); |
- } else { |
- RunSessionTask(base::Bind( |
- &Automation::MouseDoubleClickDeprecated, |
- base::Unretained(automation_.get()), |
- current_target_.view_id, |
- mouse_position_, |
- &error)); |
- } |
- return error; |
-} |
- |
-Error* Session::GetCookies(const std::string& url, |
- scoped_ptr<base::ListValue>* cookies) { |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::GetCookies, |
- base::Unretained(automation_.get()), |
- url, |
- cookies, |
- &error)); |
- return error; |
-} |
- |
-Error* Session::DeleteCookie(const std::string& url, |
- const std::string& cookie_name) { |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::DeleteCookie, |
- base::Unretained(automation_.get()), |
- url, |
- cookie_name, |
- &error)); |
- return error; |
-} |
- |
-// Note that when this is called from CookieCommand::ExecutePost then |
-// |cookie_dict| is destroyed as soon as the caller finishes. Therefore |
-// it is essential that RunSessionTask executes synchronously. |
-Error* Session::SetCookie(const std::string& url, |
- base::DictionaryValue* cookie_dict) { |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::SetCookie, |
- base::Unretained(automation_.get()), |
- url, |
- cookie_dict, |
- &error)); |
- return error; |
-} |
- |
-Error* Session::GetViews(std::vector<WebViewInfo>* views) { |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::GetViews, |
- base::Unretained(automation_.get()), |
- views, |
- &error)); |
- return error; |
-} |
- |
-Error* Session::SwitchToView(const std::string& id_or_name) { |
- Error* error = NULL; |
- bool does_exist = false; |
- |
- WebViewId new_view; |
- StringToWebViewId(id_or_name, &new_view); |
- if (new_view.IsValid()) { |
- RunSessionTask(base::Bind( |
- &Automation::DoesViewExist, |
- base::Unretained(automation_.get()), |
- new_view, |
- &does_exist, |
- &error)); |
- if (error) |
- return error; |
- } |
- |
- if (!does_exist) { |
- // See if any of the tab window names match |name|. |
- std::vector<WebViewInfo> views; |
- Error* error = GetViews(&views); |
- if (error) |
- return error; |
- for (size_t i = 0; i < views.size(); ++i) { |
- if (!views[i].view_id.IsTab()) |
- continue; |
- std::string window_name; |
- Error* error = ExecuteScriptAndParse( |
- FrameId(views[i].view_id, FramePath()), |
- "function() { return window.name; }", |
- "getWindowName", |
- new base::ListValue(), |
- CreateDirectValueParser(&window_name)); |
- if (error) |
- return error; |
- if (id_or_name == window_name) { |
- new_view = views[i].view_id; |
- does_exist = true; |
- break; |
- } |
- } |
- } |
- |
- if (!does_exist) |
- return new Error(kNoSuchWindow); |
- frame_elements_.clear(); |
- current_target_ = FrameId(new_view, FramePath()); |
- return NULL; |
-} |
- |
-Error* Session::SwitchToFrameWithNameOrId(const std::string& name_or_id) { |
- std::string script = |
- "function(arg) {" |
- " var xpath = '(/html/body//iframe|/html/frameset/frame)';" |
- " var sub = function(s) { return s.replace(/\\$/g, arg); };" |
- " xpath += sub('[@name=\"$\" or @id=\"$\"]');" |
- " return document.evaluate(xpath, document, null, " |
- " XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;" |
- "}"; |
- return SwitchToFrameWithJavaScriptLocatedFrame( |
- script, CreateListValueFrom(name_or_id)); |
-} |
- |
-Error* Session::SwitchToFrameWithIndex(int index) { |
- // We cannot simply index into window.frames because we need to know the |
- // tagName of the frameElement. If child frame N is from another domain, then |
- // the following will run afoul of the same origin policy: |
- // window.frames[N].frameElement; |
- // Instead of indexing window.frames, we use an XPath expression to 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 = |
- "function(index) {" |
- " var xpathIndex = '[' + (index + 1) + ']';" |
- " var xpath = '(/html/body//iframe|/html/frameset/frame)' + " |
- " xpathIndex;" |
- " return document.evaluate(xpath, document, null, " |
- " XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;" |
- "}"; |
- return SwitchToFrameWithJavaScriptLocatedFrame( |
- script, CreateListValueFrom(index)); |
-} |
- |
-Error* Session::SwitchToFrameWithElement(const ElementId& element) { |
- // TODO(jleyba): Extract this, and the other frame switch methods to an atom. |
- std::string script = |
- "function(elem) {" |
- " if (elem.nodeType != 1 || !/^i?frame$/i.test(elem.tagName)) {" |
- " console.error('Element is not a frame');" |
- " return null;" |
- " }" |
- " for (var i = 0; i < window.frames.length; i++) {" |
- " if (elem.contentWindow == window.frames[i]) {" |
- " return elem;" |
- " }" |
- " }" |
- " console.info('Frame is not connected to this DOM tree');" |
- " return null;" |
- "}"; |
- return SwitchToFrameWithJavaScriptLocatedFrame( |
- script, CreateListValueFrom(element)); |
-} |
- |
-void Session::SwitchToTopFrame() { |
- frame_elements_.clear(); |
- current_target_.frame_path = FramePath(); |
-} |
- |
-Error* Session::SwitchToTopFrameIfCurrentFrameInvalid() { |
- std::vector<std::string> components; |
- current_target_.frame_path.GetComponents(&components); |
- if (frame_elements_.size() != components.size()) { |
- return new Error(kUnknownError, |
- "Frame element vector out of sync with frame path"); |
- } |
- FramePath frame_path; |
- // Start from the root path and check that each frame element that makes |
- // up the current frame target is valid by executing an empty script. |
- // This code should not execute script in any frame before making sure the |
- // 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_.view_id, frame_path); |
- 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()) { |
- return error.release(); |
- } |
- frame_path = frame_path.Append(components[i]); |
- } |
- return NULL; |
-} |
- |
-Error* Session::CloseWindow() { |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::CloseView, |
- base::Unretained(automation_.get()), |
- current_target_.view_id, |
- &error)); |
- |
- if (!error) { |
- std::vector<WebViewInfo> views; |
- scoped_ptr<Error> error(GetViews(&views)); |
- if (error.get() || views.empty()) { |
- // The automation connection will soon be closed, if not already, |
- // because we supposedly just closed the last window. Terminate the |
- // session. |
- // TODO(kkania): This will cause us problems if GetWindowIds fails for a |
- // reason other than the channel is disconnected. Look into having |
- // |GetWindowIds| tell us if it just closed the last window. |
- Terminate(); |
- } |
- } |
- return error; |
-} |
- |
-Error* Session::GetWindowBounds(const WebViewId& window, Rect* bounds) { |
- const char* kGetWindowBoundsScript = |
- "function() {" |
- " return {" |
- " 'left': window.screenX," |
- " 'top': window.screenY," |
- " 'width': window.outerWidth," |
- " 'height': window.outerHeight" |
- " }" |
- "}"; |
- return ExecuteScriptAndParse( |
- FrameId(window, FramePath()), |
- kGetWindowBoundsScript, |
- "getWindowBoundsScript", |
- new base::ListValue(), |
- CreateDirectValueParser(bounds)); |
-} |
- |
-Error* Session::SetWindowBounds( |
- const WebViewId& window, |
- const Rect& bounds) { |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::SetViewBounds, |
- base::Unretained(automation_.get()), |
- window, |
- bounds, |
- &error)); |
- return error; |
-} |
- |
-Error* Session::MaximizeWindow(const WebViewId& window) { |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::MaximizeView, |
- base::Unretained(automation_.get()), |
- window, |
- &error)); |
- return error; |
-} |
- |
-Error* Session::GetAlertMessage(std::string* text) { |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::GetAppModalDialogMessage, |
- base::Unretained(automation_.get()), |
- text, |
- &error)); |
- return error; |
-} |
- |
-Error* Session::SetAlertPromptText(const std::string& alert_prompt_text) { |
- std::string message_text; |
- // Only set the alert prompt text if an alert is actually active. |
- Error* error = GetAlertMessage(&message_text); |
- if (!error) { |
- has_alert_prompt_text_ = true; |
- alert_prompt_text_ = alert_prompt_text; |
- } |
- return error; |
-} |
- |
-Error* Session::AcceptOrDismissAlert(bool accept) { |
- Error* error = NULL; |
- if (accept && has_alert_prompt_text_) { |
- RunSessionTask(base::Bind( |
- &Automation::AcceptPromptAppModalDialog, |
- base::Unretained(automation_.get()), |
- alert_prompt_text_, |
- &error)); |
- } else { |
- RunSessionTask(base::Bind( |
- &Automation::AcceptOrDismissAppModalDialog, |
- base::Unretained(automation_.get()), |
- accept, |
- &error)); |
- } |
- has_alert_prompt_text_ = false; |
- return error; |
-} |
- |
-std::string Session::GetBrowserVersion() { |
- std::string version; |
- RunSessionTask(base::Bind( |
- &Automation::GetBrowserVersion, |
- base::Unretained(automation_.get()), |
- &version)); |
- return version; |
-} |
- |
-Error* Session::CompareBrowserVersion(int client_build_no, |
- int client_patch_no, |
- bool* is_newer_or_equal) { |
- std::string version = GetBrowserVersion(); |
- std::vector<std::string> split_version; |
- base::SplitString(version, '.', &split_version); |
- if (split_version.size() != 4) { |
- return new Error( |
- kUnknownError, "Browser version has unrecognized format: " + version); |
- } |
- int build_no, patch_no; |
- if (!base::StringToInt(split_version[2], &build_no) || |
- !base::StringToInt(split_version[3], &patch_no)) { |
- return new Error( |
- kUnknownError, "Browser version has unrecognized format: " + version); |
- } |
- if (build_no < client_build_no) |
- *is_newer_or_equal = false; |
- else if (build_no > client_build_no) |
- *is_newer_or_equal = true; |
- else |
- *is_newer_or_equal = patch_no >= client_patch_no; |
- return NULL; |
-} |
- |
-Error* Session::FindElement(const FrameId& frame_id, |
- const ElementId& root_element, |
- const std::string& locator, |
- const std::string& query, |
- ElementId* element) { |
- std::vector<ElementId> elements; |
- Error* error = FindElementsHelper( |
- frame_id, root_element, locator, query, true, &elements); |
- if (!error) |
- *element = elements[0]; |
- return error; |
-} |
- |
-Error* Session::FindElements(const FrameId& frame_id, |
- const ElementId& root_element, |
- const std::string& locator, |
- const std::string& query, |
- std::vector<ElementId>* elements) { |
- return FindElementsHelper( |
- frame_id, root_element, locator, query, false, elements); |
-} |
- |
-Error* Session::GetElementLocationInView( |
- const ElementId& element, |
- Point* location) { |
- Size size; |
- Error* error = GetElementSize(current_target_, element, &size); |
- if (error) |
- return error; |
- return GetElementRegionInView( |
- element, Rect(Point(0, 0), size), |
- false /* center */, false /* verify_clickable_at_middle */, location); |
-} |
- |
-Error* Session::GetElementRegionInView( |
- const ElementId& element, |
- const Rect& region, |
- bool center, |
- bool verify_clickable_at_middle, |
- Point* location) { |
- CHECK(element.is_valid()); |
- |
- Point region_offset = region.origin(); |
- Size region_size = region.size(); |
- Error* error = GetElementRegionInViewHelper( |
- current_target_, element, region, center, verify_clickable_at_middle, |
- ®ion_offset); |
- if (error) |
- return error; |
- |
- for (FramePath frame_path = current_target_.frame_path; |
- frame_path.IsSubframe(); |
- frame_path = frame_path.Parent()) { |
- // Find the frame element for the current frame path. |
- FrameId frame_id(current_target_.view_id, frame_path.Parent()); |
- ElementId frame_element; |
- error = FindElement(frame_id, |
- ElementId(std::string()), |
- LocatorType::kXpath, |
- frame_path.BaseName().value(), |
- &frame_element); |
- if (error) { |
- std::string context = base::StringPrintf( |
- "Could not find frame element (%s) in frame (%s)", |
- frame_path.BaseName().value().c_str(), |
- frame_path.Parent().value().c_str()); |
- error->AddDetails(context); |
- return error; |
- } |
- // Modify |region_offset| by the frame's border. |
- int border_left, border_top; |
- error = GetElementBorder( |
- frame_id, frame_element, &border_left, &border_top); |
- if (error) |
- return error; |
- region_offset.Offset(border_left, border_top); |
- |
- error = GetElementRegionInViewHelper( |
- frame_id, frame_element, Rect(region_offset, region_size), |
- center, verify_clickable_at_middle, ®ion_offset); |
- if (error) |
- return error; |
- } |
- *location = region_offset; |
- return NULL; |
-} |
- |
-Error* Session::GetElementSize(const FrameId& frame_id, |
- const ElementId& element, |
- Size* size) { |
- return ExecuteScriptAndParse( |
- frame_id, |
- atoms::asString(atoms::GET_SIZE), |
- "getSize", |
- CreateListValueFrom(element), |
- CreateDirectValueParser(size)); |
-} |
- |
-Error* Session::GetElementFirstClientRect(const FrameId& frame_id, |
- const ElementId& element, |
- Rect* rect) { |
- return ExecuteScriptAndParse( |
- frame_id, |
- atoms::asString(atoms::GET_FIRST_CLIENT_RECT), |
- "getFirstClientRect", |
- CreateListValueFrom(element), |
- CreateDirectValueParser(rect)); |
-} |
- |
-Error* Session::GetElementEffectiveStyle( |
- const FrameId& frame_id, |
- const ElementId& element, |
- const std::string& prop, |
- std::string* value) { |
- return ExecuteScriptAndParse( |
- frame_id, |
- atoms::asString(atoms::GET_EFFECTIVE_STYLE), |
- "getEffectiveStyle", |
- CreateListValueFrom(element, prop), |
- CreateDirectValueParser(value)); |
-} |
- |
-Error* Session::GetElementBorder(const FrameId& frame_id, |
- const ElementId& element, |
- int* border_left, |
- int* border_top) { |
- std::string border_left_str, border_top_str; |
- Error* error = GetElementEffectiveStyle( |
- frame_id, element, "border-left-width", &border_left_str); |
- if (error) |
- return error; |
- error = GetElementEffectiveStyle( |
- frame_id, element, "border-top-width", &border_top_str); |
- if (error) |
- return error; |
- |
- base::StringToInt(border_left_str, border_left); |
- base::StringToInt(border_top_str, border_top); |
- return NULL; |
-} |
- |
-Error* Session::IsElementDisplayed(const FrameId& frame_id, |
- const ElementId& element, |
- bool ignore_opacity, |
- bool* is_displayed) { |
- return ExecuteScriptAndParse( |
- frame_id, |
- atoms::asString(atoms::IS_DISPLAYED), |
- "isDisplayed", |
- CreateListValueFrom(element, ignore_opacity), |
- CreateDirectValueParser(is_displayed)); |
-} |
- |
-Error* Session::IsElementEnabled(const FrameId& frame_id, |
- const ElementId& element, |
- bool* is_enabled) { |
- return ExecuteScriptAndParse( |
- frame_id, |
- atoms::asString(atoms::IS_ENABLED), |
- "isEnabled", |
- CreateListValueFrom(element), |
- CreateDirectValueParser(is_enabled)); |
-} |
- |
-Error* Session::IsOptionElementSelected(const FrameId& frame_id, |
- const ElementId& element, |
- bool* is_selected) { |
- return ExecuteScriptAndParse( |
- frame_id, |
- atoms::asString(atoms::IS_SELECTED), |
- "isSelected", |
- CreateListValueFrom(element), |
- CreateDirectValueParser(is_selected)); |
-} |
- |
-Error* Session::SetOptionElementSelected(const FrameId& frame_id, |
- const ElementId& element, |
- bool selected) { |
- // 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));"; |
- base::Value* value = NULL; |
- Error* error = ExecuteAsyncScript( |
- frame_id, |
- base::StringPrintf(kSetSelectedWrapper, |
- atoms::asString(atoms::CLICK).c_str()), |
- CreateListValueFrom(element, selected), |
- &value); |
- scoped_ptr<base::Value> scoped_value(value); |
- return error; |
-} |
- |
-Error* Session::ToggleOptionElement(const FrameId& frame_id, |
- const ElementId& element) { |
- bool is_selected; |
- Error* error = IsOptionElementSelected(frame_id, element, &is_selected); |
- if (error) |
- return error; |
- |
- return SetOptionElementSelected(frame_id, element, !is_selected); |
-} |
- |
-Error* Session::GetElementTagName(const FrameId& frame_id, |
- const ElementId& element, |
- std::string* tag_name) { |
- return ExecuteScriptAndParse( |
- frame_id, |
- "function(elem) { return elem.tagName.toLowerCase() }", |
- "getElementTagName", |
- CreateListValueFrom(element), |
- CreateDirectValueParser(tag_name)); |
-} |
- |
-Error* Session::GetClickableLocation(const ElementId& element, |
- Point* location) { |
- bool is_displayed = false; |
- Error* error = IsElementDisplayed( |
- current_target_, element, true /* ignore_opacity */, &is_displayed); |
- if (error) |
- return error; |
- if (!is_displayed) |
- return new Error(kElementNotVisible, "Element must be displayed to click"); |
- |
- // We try 3 methods to determine clickable location. This mostly follows |
- // what FirefoxDriver does. Try the first client rect, then the bounding |
- // client rect, and lastly the size of the element (via closure). |
- // SVG is one case that doesn't have a first client rect. |
- Rect rect; |
- scoped_ptr<Error> ignore_error( |
- GetElementFirstClientRect(current_target_, element, &rect)); |
- if (ignore_error.get()) { |
- Rect client_rect; |
- ignore_error.reset(ExecuteScriptAndParse( |
- current_target_, |
- "function(elem) { return elem.getBoundingClientRect() }", |
- "getBoundingClientRect", |
- CreateListValueFrom(element), |
- CreateDirectValueParser(&client_rect))); |
- rect = Rect(0, 0, client_rect.width(), client_rect.height()); |
- } |
- if (ignore_error.get()) { |
- Size size; |
- ignore_error.reset(GetElementSize(current_target_, element, &size)); |
- rect = Rect(0, 0, size.width(), size.height()); |
- } |
- if (ignore_error.get()) { |
- return new Error(kUnknownError, |
- "Unable to determine clickable location of element"); |
- } |
- |
- error = GetElementRegionInView( |
- element, rect, true /* center */, true /* verify_clickable_at_middle */, |
- location); |
- if (error) |
- return error; |
- location->Offset(rect.width() / 2, rect.height() / 2); |
- return NULL; |
-} |
- |
-Error* Session::GetAttribute(const ElementId& element, |
- const std::string& key, |
- base::Value** value) { |
- return ExecuteScriptAndParse( |
- current_target_, |
- atoms::asString(atoms::GET_ATTRIBUTE), |
- "getAttribute", |
- CreateListValueFrom(element, key), |
- CreateDirectValueParser(value)); |
-} |
- |
-Error* Session::WaitForAllViewsToStopLoading() { |
- if (!automation_.get()) |
- return NULL; |
- |
- logger_.Log(kFinerLogLevel, "Waiting for all views to stop loading..."); |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::WaitForAllViewsToStopLoading, |
- base::Unretained(automation_.get()), |
- &error)); |
- logger_.Log(kFinerLogLevel, "Done waiting for all views to stop loading"); |
- return error; |
-} |
- |
-Error* Session::InstallExtension( |
- const base::FilePath& path, std::string* extension_id) { |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::InstallExtension, |
- base::Unretained(automation_.get()), |
- path, |
- extension_id, |
- &error)); |
- return error; |
-} |
- |
-Error* Session::GetExtensionsInfo(base::ListValue* extensions_list) { |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::GetExtensionsInfo, |
- base::Unretained(automation_.get()), |
- extensions_list, |
- &error)); |
- return error; |
-} |
- |
-Error* Session::IsPageActionVisible( |
- const WebViewId& tab_id, |
- const std::string& extension_id, |
- bool* is_visible) { |
- if (!tab_id.IsTab()) { |
- return new Error( |
- kUnknownError, |
- "The current target does not support page actions. Switch to a tab."); |
- } |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::IsPageActionVisible, |
- base::Unretained(automation_.get()), |
- tab_id, |
- extension_id, |
- is_visible, |
- &error)); |
- return error; |
-} |
- |
-Error* Session::SetExtensionState( |
- const std::string& extension_id, bool enable) { |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::SetExtensionState, |
- base::Unretained(automation_.get()), |
- extension_id, |
- enable, |
- &error)); |
- return error; |
-} |
- |
-Error* Session::ClickExtensionButton( |
- const std::string& extension_id, bool browser_action) { |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::ClickExtensionButton, |
- base::Unretained(automation_.get()), |
- extension_id, |
- browser_action, |
- &error)); |
- return error; |
-} |
- |
-Error* Session::UninstallExtension(const std::string& extension_id) { |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::UninstallExtension, |
- base::Unretained(automation_.get()), |
- extension_id, |
- &error)); |
- return error; |
-} |
- |
-Error* Session::SetPreference( |
- const std::string& pref, |
- bool is_user_pref, |
- base::Value* value) { |
- Error* error = NULL; |
- if (is_user_pref) { |
- RunSessionTask(base::Bind( |
- &Automation::SetPreference, |
- base::Unretained(automation_.get()), |
- pref, |
- value, |
- &error)); |
- if (error) |
- error->AddDetails("Failed to set user pref '" + pref + "'"); |
- } else { |
- RunSessionTask(base::Bind( |
- &Automation::SetLocalStatePreference, |
- base::Unretained(automation_.get()), |
- pref, |
- value, |
- &error)); |
- if (error) |
- error->AddDetails("Failed to set local state pref '" + pref + "'"); |
- } |
- return error; |
-} |
- |
-base::ListValue* Session::GetLog() const { |
- return session_log_->entries_list()->DeepCopy(); |
-} |
- |
-Error* Session::GetBrowserConnectionState(bool* online) { |
- return ExecuteScriptAndParse( |
- current_target_, |
- atoms::asString(atoms::IS_ONLINE), |
- "isOnline", |
- new base::ListValue(), |
- CreateDirectValueParser(online)); |
-} |
- |
-Error* Session::GetAppCacheStatus(int* status) { |
- return ExecuteScriptAndParse( |
- current_target_, |
- atoms::asString(atoms::GET_APPCACHE_STATUS), |
- "getAppcacheStatus", |
- new base::ListValue(), |
- CreateDirectValueParser(status)); |
-} |
- |
-Error* Session::GetStorageSize(StorageType type, int* size) { |
- std::string js = atoms::asString( |
- type == kLocalStorageType ? atoms::GET_LOCAL_STORAGE_SIZE |
- : atoms::GET_SESSION_STORAGE_SIZE); |
- return ExecuteScriptAndParse( |
- current_target_, |
- js, |
- "getStorageSize", |
- new base::ListValue(), |
- CreateDirectValueParser(size)); |
-} |
- |
-Error* Session::SetStorageItem(StorageType type, |
- const std::string& key, |
- const std::string& value) { |
- std::string js = atoms::asString( |
- type == kLocalStorageType ? atoms::SET_LOCAL_STORAGE_ITEM |
- : atoms::SET_SESSION_STORAGE_ITEM); |
- return ExecuteScriptAndParse( |
- current_target_, |
- js, |
- "setStorageItem", |
- CreateListValueFrom(key, value), |
- CreateDirectValueParser(kSkipParsing)); |
-} |
- |
-Error* Session::ClearStorage(StorageType type) { |
- std::string js = atoms::asString( |
- type == kLocalStorageType ? atoms::CLEAR_LOCAL_STORAGE |
- : atoms::CLEAR_SESSION_STORAGE); |
- return ExecuteScriptAndParse( |
- current_target_, |
- js, |
- "clearStorage", |
- new base::ListValue(), |
- CreateDirectValueParser(kSkipParsing)); |
-} |
- |
-Error* Session::GetStorageKeys(StorageType type, base::ListValue** keys) { |
- std::string js = atoms::asString( |
- type == kLocalStorageType ? atoms::GET_LOCAL_STORAGE_KEYS |
- : atoms::GET_SESSION_STORAGE_KEYS); |
- return ExecuteScriptAndParse( |
- current_target_, |
- js, |
- "getStorageKeys", |
- new base::ListValue(), |
- CreateDirectValueParser(keys)); |
-} |
- |
-Error* Session::GetStorageItem(StorageType type, |
- const std::string& key, |
- std::string* value) { |
- std::string js = atoms::asString( |
- type == kLocalStorageType ? atoms::GET_LOCAL_STORAGE_ITEM |
- : atoms::GET_SESSION_STORAGE_ITEM); |
- return ExecuteScriptAndParse( |
- current_target_, |
- js, |
- "getStorageItem", |
- CreateListValueFrom(key), |
- CreateDirectValueParser(value)); |
-} |
- |
-Error* Session::RemoveStorageItem(StorageType type, |
- const std::string& key, |
- std::string* value) { |
- std::string js = atoms::asString( |
- type == kLocalStorageType ? atoms::REMOVE_LOCAL_STORAGE_ITEM |
- : atoms::REMOVE_SESSION_STORAGE_ITEM); |
- return ExecuteScriptAndParse( |
- current_target_, |
- js, |
- "removeStorageItem", |
- CreateListValueFrom(key), |
- CreateDirectValueParser(value)); |
-} |
- |
-Error* Session::GetGeolocation( |
- scoped_ptr<base::DictionaryValue>* geolocation) { |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::GetGeolocation, |
- base::Unretained(automation_.get()), |
- geolocation, |
- &error)); |
- return error; |
-} |
- |
-Error* Session::OverrideGeolocation(const base::DictionaryValue* geolocation) { |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::OverrideGeolocation, |
- base::Unretained(automation_.get()), |
- geolocation, |
- &error)); |
- return error; |
-} |
- |
-const std::string& Session::id() const { |
- return id_; |
-} |
- |
-const FrameId& Session::current_target() const { |
- return current_target_; |
-} |
- |
-void Session::set_async_script_timeout(int timeout_ms) { |
- async_script_timeout_ = timeout_ms; |
-} |
- |
-int Session::async_script_timeout() const { |
- return async_script_timeout_; |
-} |
- |
-void Session::set_implicit_wait(int timeout_ms) { |
- implicit_wait_ = timeout_ms; |
-} |
- |
-int Session::implicit_wait() const { |
- return implicit_wait_; |
-} |
- |
-const Point& Session::get_mouse_position() const { |
- return mouse_position_; |
-} |
- |
-const Logger& Session::logger() const { |
- return logger_; |
-} |
- |
-const base::FilePath& Session::temp_dir() const { |
- return temp_dir_.path(); |
-} |
- |
-const Capabilities& Session::capabilities() const { |
- return capabilities_; |
-} |
- |
-void Session::RunSessionTask(const base::Closure& task) { |
- base::WaitableEvent done_event(false, false); |
- thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind( |
- &Session::RunClosureOnSessionThread, |
- base::Unretained(this), |
- task, |
- &done_event)); |
- // See SetCookie for why it is essential that we wait here. |
- done_event.Wait(); |
-} |
- |
-void Session::RunClosureOnSessionThread(const base::Closure& task, |
- base::WaitableEvent* done_event) { |
- task.Run(); |
- done_event->Signal(); |
-} |
- |
-void Session::InitOnSessionThread(const Automation::BrowserOptions& options, |
- int* build_no, |
- Error** error) { |
- automation_.reset(new Automation(logger_)); |
- automation_->Init(options, build_no, error); |
- if (*error) |
- return; |
- |
- std::vector<WebViewInfo> views; |
- automation_->GetViews(&views, error); |
- if (*error) |
- return; |
- if (views.empty()) { |
- *error = new Error(kUnknownError, "No view ids after initialization"); |
- return; |
- } |
- current_target_ = FrameId(views[0].view_id, FramePath()); |
-} |
- |
-void Session::TerminateOnSessionThread() { |
- if (automation_.get()) |
- automation_->Terminate(); |
- automation_.reset(); |
-} |
- |
-Error* Session::ExecuteScriptAndParseValue(const FrameId& frame_id, |
- const std::string& script, |
- base::Value** script_result) { |
- std::string response_json; |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::ExecuteScript, |
- base::Unretained(automation_.get()), |
- frame_id.view_id, |
- frame_id.frame_path, |
- script, |
- &response_json, |
- &error)); |
- if (error) |
- return error; |
- |
- scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError( |
- response_json, base::JSON_ALLOW_TRAILING_COMMAS, NULL, NULL)); |
- if (!value.get()) |
- return new Error(kUnknownError, "Failed to parse script result"); |
- if (value->GetType() != base::Value::TYPE_DICTIONARY) |
- return new Error(kUnknownError, "Execute script returned non-dict: " + |
- JsonStringify(value.get())); |
- base::DictionaryValue* result_dict = |
- static_cast<base::DictionaryValue*>(value.get()); |
- |
- int status; |
- if (!result_dict->GetInteger("status", &status)) |
- return new Error(kUnknownError, "Execute script did not return status: " + |
- JsonStringify(result_dict)); |
- ErrorCode code = static_cast<ErrorCode>(status); |
- if (code != kSuccess) { |
- base::DictionaryValue* error_dict; |
- std::string error_msg; |
- if (result_dict->GetDictionary("value", &error_dict)) |
- error_dict->GetString("message", &error_msg); |
- if (error_msg.empty()) |
- error_msg = "Script failed with error code: " + base::IntToString(code); |
- return new Error(code, error_msg); |
- } |
- |
- base::Value* tmp; |
- if (result_dict->Get("value", &tmp)) { |
- *script_result= tmp->DeepCopy(); |
- } else { |
- // "value" was not defined in the returned dictionary; set to null. |
- *script_result= base::Value::CreateNullValue(); |
- } |
- return NULL; |
-} |
- |
-void Session::SendKeysOnSessionThread(const string16& keys, |
- bool release_modifiers, Error** error) { |
- std::vector<WebKeyEvent> key_events; |
- std::string error_msg; |
- if (!ConvertKeysToWebKeyEvents(keys, logger_, release_modifiers, |
- &sticky_modifiers_, &key_events, &error_msg)) { |
- *error = new Error(kUnknownError, error_msg); |
- return; |
- } |
- for (size_t i = 0; i < key_events.size(); ++i) { |
- automation_->SendWebKeyEvent( |
- current_target_.view_id, |
- key_events[i], error); |
- if (*error) { |
- std::string details = base::StringPrintf( |
- "Failed to send key event. Event details:\n" |
- "Type: %d, KeyCode: %d, UnmodifiedText: %s, ModifiedText: %s, " |
- "Modifiers: %d", |
- key_events[i].type, |
- key_events[i].key_code, |
- key_events[i].unmodified_text.c_str(), |
- key_events[i].modified_text.c_str(), |
- key_events[i].modifiers); |
- (*error)->AddDetails(details); |
- return; |
- } |
- } |
-} |
- |
-Error* Session::ProcessWebMouseEvents( |
- const std::vector<WebMouseEvent>& events) { |
- for (size_t i = 0; i < events.size(); ++i) { |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::SendWebMouseEvent, |
- base::Unretained(automation_.get()), |
- current_target_.view_id, |
- events[i], |
- &error)); |
- if (error) |
- return error; |
- mouse_position_ = Point(events[i].x, events[i].y); |
- } |
- return NULL; |
-} |
- |
-WebMouseEvent Session::CreateWebMouseEvent( |
- automation::MouseEventType type, |
- automation::MouseButton button, |
- const Point& point, |
- int click_count) { |
- return WebMouseEvent(type, button, point.rounded_x(), point.rounded_y(), |
- click_count, sticky_modifiers_); |
-} |
- |
-Error* Session::SwitchToFrameWithJavaScriptLocatedFrame( |
- const std::string& script, base::ListValue* args) { |
- class SwitchFrameValueParser : public ValueParser { |
- public: |
- SwitchFrameValueParser( |
- bool* found_frame, ElementId* frame) |
- : found_frame_(found_frame), frame_(frame) { } |
- |
- virtual ~SwitchFrameValueParser() { } |
- |
- virtual bool Parse(base::Value* value) const OVERRIDE { |
- if (value->IsType(base::Value::TYPE_NULL)) { |
- *found_frame_ = false; |
- return true; |
- } |
- ElementId id(value); |
- if (!id.is_valid()) { |
- return false; |
- } |
- *frame_ = id; |
- *found_frame_ = true; |
- return true; |
- } |
- |
- private: |
- bool* found_frame_; |
- ElementId* frame_; |
- }; |
- |
- bool found_frame; |
- ElementId new_frame_element; |
- Error* error = ExecuteScriptAndParse( |
- current_target_, script, "switchFrame", args, |
- new SwitchFrameValueParser(&found_frame, &new_frame_element)); |
- if (error) |
- return error; |
- |
- if (!found_frame) |
- return new Error(kNoSuchFrame); |
- |
- std::string frame_id = GenerateRandomID(); |
- error = ExecuteScriptAndParse( |
- current_target_, |
- "function(elem, id) { elem.setAttribute('wd_frame_id_', id); }", |
- "setFrameId", |
- CreateListValueFrom(new_frame_element, frame_id), |
- CreateDirectValueParser(kSkipParsing)); |
- if (error) |
- return error; |
- |
- frame_elements_.push_back(new_frame_element); |
- current_target_.frame_path = current_target_.frame_path.Append( |
- base::StringPrintf("//*[@wd_frame_id_ = '%s']", frame_id.c_str())); |
- return NULL; |
-} |
- |
-Error* Session::FindElementsHelper(const FrameId& frame_id, |
- const ElementId& root_element, |
- const std::string& locator, |
- const std::string& query, |
- bool find_one, |
- std::vector<ElementId>* elements) { |
- CHECK(root_element.is_valid()); |
- base::Time start_time = base::Time::Now(); |
- while (true) { |
- std::vector<ElementId> temp_elements; |
- Error* error = ExecuteFindElementScriptAndParse( |
- frame_id, root_element, locator, query, find_one, &temp_elements); |
- if (error) |
- return error; |
- |
- 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; |
- } |
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50)); |
- } |
- return NULL; |
-} |
- |
-Error* Session::ExecuteFindElementScriptAndParse( |
- const FrameId& frame_id, |
- const ElementId& root_element, |
- const std::string& locator, |
- const std::string& query, |
- bool find_one, |
- std::vector<ElementId>* elements) { |
- CHECK(root_element.is_valid()); |
- |
- class FindElementsParser : public ValueParser { |
- public: |
- explicit FindElementsParser(std::vector<ElementId>* elements) |
- : elements_(elements) { } |
- |
- virtual ~FindElementsParser() { } |
- |
- virtual bool Parse(base::Value* value) const OVERRIDE { |
- if (!value->IsType(base::Value::TYPE_LIST)) |
- return false; |
- base::ListValue* list = static_cast<base::ListValue*>(value); |
- for (size_t i = 0; i < list->GetSize(); ++i) { |
- ElementId element; |
- base::Value* element_value = NULL; |
- if (!list->Get(i, &element_value)) |
- return false; |
- if (!SetFromValue(element_value, &element)) |
- return false; |
- elements_->push_back(element); |
- } |
- return true; |
- } |
- private: |
- std::vector<ElementId>* elements_; |
- }; |
- |
- class FindElementParser : public ValueParser { |
- public: |
- explicit FindElementParser(std::vector<ElementId>* elements) |
- : elements_(elements) { } |
- |
- virtual ~FindElementParser() { } |
- |
- virtual bool Parse(base::Value* value) const OVERRIDE { |
- if (value->IsType(base::Value::TYPE_NULL)) |
- return true; |
- ElementId element; |
- bool set = SetFromValue(value, &element); |
- if (set) |
- elements_->push_back(element); |
- return set; |
- } |
- private: |
- std::vector<ElementId>* elements_; |
- }; |
- |
- base::DictionaryValue locator_dict; |
- locator_dict.SetString(locator, query); |
- std::vector<ElementId> temp_elements; |
- Error* error = NULL; |
- if (find_one) { |
- error = ExecuteScriptAndParse( |
- frame_id, |
- atoms::asString(atoms::FIND_ELEMENT), |
- "findElement", |
- CreateListValueFrom(&locator_dict, root_element), |
- new FindElementParser(&temp_elements)); |
- } else { |
- error = ExecuteScriptAndParse( |
- frame_id, |
- atoms::asString(atoms::FIND_ELEMENTS), |
- "findElements", |
- CreateListValueFrom(&locator_dict, root_element), |
- new FindElementsParser(&temp_elements)); |
- } |
- if (!error) |
- elements->swap(temp_elements); |
- return error; |
-} |
- |
-Error* Session::VerifyElementIsClickable( |
- const FrameId& frame_id, |
- const ElementId& element, |
- 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(base::Value::TYPE_DICTIONARY)) |
- return false; |
- base::DictionaryValue* dict = static_cast<base::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::asString(atoms::IS_ELEMENT_CLICKABLE), |
- "isElementClickable", |
- CreateListValueFrom(element, location), |
- new IsElementClickableParser(&clickable, &message)); |
- if (error) |
- return error; |
- |
- if (!clickable) { |
- if (message.empty()) |
- message = "element is not clickable"; |
- return new Error(kUnknownError, message); |
- } |
- if (message.length()) { |
- logger_.Log(kWarningLogLevel, message); |
- } |
- return NULL; |
-} |
- |
-Error* Session::GetElementRegionInViewHelper( |
- const FrameId& frame_id, |
- const ElementId& element, |
- const Rect& region, |
- bool center, |
- bool verify_clickable_at_middle, |
- Point* location) { |
- Point temp_location; |
- Error* error = ExecuteScriptAndParse( |
- frame_id, |
- atoms::asString(atoms::GET_LOCATION_IN_VIEW), |
- "getLocationInView", |
- CreateListValueFrom(element, center, region), |
- CreateDirectValueParser(&temp_location)); |
- |
- if (verify_clickable_at_middle) { |
- Point middle_point = temp_location; |
- middle_point.Offset(region.width() / 2, region.height() / 2); |
- error = VerifyElementIsClickable(frame_id, element, middle_point); |
- if (error) |
- return error; |
- } |
- *location = temp_location; |
- return NULL; |
-} |
- |
-Error* Session::GetScreenShot(std::string* png) { |
- if (!current_target_.view_id.IsTab()) { |
- return new Error(kUnknownError, |
- "The current target does not support screenshot"); |
- } |
- Error* error = NULL; |
- base::ScopedTempDir screenshots_dir; |
- if (!screenshots_dir.CreateUniqueTempDir()) { |
- return new Error(kUnknownError, |
- "Could not create temp directory for screenshot"); |
- } |
- |
- base::FilePath path = screenshots_dir.path().AppendASCII("screen"); |
- RunSessionTask(base::Bind( |
- &Automation::CaptureEntirePageAsPNG, |
- base::Unretained(automation_.get()), |
- current_target_.view_id, |
- path, |
- &error)); |
- if (error) |
- return error; |
- if (!base::ReadFileToString(path, png)) |
- return new Error(kUnknownError, "Could not read screenshot file"); |
- return NULL; |
-} |
- |
-#if !defined(NO_TCMALLOC) && (defined(OS_LINUX) || defined(OS_CHROMEOS)) |
-Error* Session::HeapProfilerDump(const std::string& reason) { |
- // TODO(dmikurube): Support browser processes. |
- Error* error = NULL; |
- RunSessionTask(base::Bind( |
- &Automation::HeapProfilerDump, |
- base::Unretained(automation_.get()), |
- current_target_.view_id, |
- reason, |
- &error)); |
- return error; |
-} |
-#endif // !defined(NO_TCMALLOC) && (defined(OS_LINUX) || defined(OS_CHROMEOS)) |
- |
-Error* Session::PostBrowserStartInit() { |
- Error* error = NULL; |
- if (!capabilities_.no_website_testing_defaults) |
- error = InitForWebsiteTesting(); |
- if (!error) |
- error = SetPrefs(); |
- if (error) |
- return error; |
- |
- // Install extensions. |
- for (size_t i = 0; i < capabilities_.extensions.size(); ++i) { |
- std::string extension_id; |
- error = InstallExtension(capabilities_.extensions[i], &extension_id); |
- if (error) |
- return error; |
- } |
- return NULL; |
-} |
- |
-Error* Session::InitForWebsiteTesting() { |
- bool has_prefs_api = false; |
- // Don't set these prefs for Chrome 14 and below. |
- // TODO(kkania): Remove this when Chrome 14 is unsupported. |
- Error* error = CompareBrowserVersion(874, 0, &has_prefs_api); |
- if (error || !has_prefs_api) |
- return error; |
- |
- // Disable checking for SSL certificate revocation. |
- error = SetPreference( |
- "ssl.rev_checking.enabled", |
- false /* is_user_pref */, |
- new base::FundamentalValue(false)); |
- if (error) |
- return error; |
- |
- // Allow content by default. |
- // Media-stream cannot be enabled by default; we must specify |
- // particular host patterns and devices. |
- base::DictionaryValue* devices = new base::DictionaryValue(); |
- devices->SetString("audio", "Default"); |
- devices->SetString("video", "Default"); |
- base::DictionaryValue* content_settings = new base::DictionaryValue(); |
- content_settings->Set("media-stream", devices); |
- base::DictionaryValue* pattern_pairs = new base::DictionaryValue(); |
- pattern_pairs->Set("https://*,*", content_settings); |
- error = SetPreference( |
- "profile.content_settings.pattern_pairs", |
- true /* is_user_pref */, |
- pattern_pairs); |
- if (error) |
- return error; |
- const int kAllowContent = 1; |
- base::DictionaryValue* default_content_settings = new base::DictionaryValue(); |
- default_content_settings->SetInteger("geolocation", kAllowContent); |
- default_content_settings->SetInteger("mouselock", kAllowContent); |
- default_content_settings->SetInteger("notifications", kAllowContent); |
- default_content_settings->SetInteger("popups", kAllowContent); |
- return SetPreference( |
- "profile.default_content_settings", |
- true /* is_user_pref */, |
- default_content_settings); |
-} |
- |
-Error* Session::SetPrefs() { |
- for (base::DictionaryValue::Iterator iter(*capabilities_.prefs); |
- !iter.IsAtEnd(); iter.Advance()) { |
- Error* error = SetPreference(iter.key(), true /* is_user_pref */, |
- iter.value().DeepCopy()); |
- if (error) |
- return error; |
- } |
- for (base::DictionaryValue::Iterator iter(*capabilities_.local_state); |
- !iter.IsAtEnd(); iter.Advance()) { |
- Error* error = SetPreference(iter.key(), false /* is_user_pref */, |
- iter.value().DeepCopy()); |
- if (error) |
- return error; |
- } |
- return NULL; |
-} |
- |
-} // namespace webdriver |