summaryrefslogtreecommitdiffstats
path: root/chrome/test/webdriver/session.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/test/webdriver/session.cc')
-rw-r--r--chrome/test/webdriver/session.cc62
1 files changed, 37 insertions, 25 deletions
diff --git a/chrome/test/webdriver/session.cc b/chrome/test/webdriver/session.cc
index e59e7b8..e6c30a4 100644
--- a/chrome/test/webdriver/session.cc
+++ b/chrome/test/webdriver/session.cc
@@ -150,7 +150,8 @@ Error* Session::ExecuteAsyncScript(const FrameId& frame_id,
Error* Session::SendKeys(const WebElementId& element, const string16& keys) {
bool is_displayed = false;
- Error* error = IsElementDisplayed(current_target_, element, &is_displayed);
+ Error* error = IsElementDisplayed(
+ current_target_, element, true /* ignore_opacity */, &is_displayed);
if (error)
return error;
if (!is_displayed)
@@ -165,28 +166,36 @@ Error* Session::SendKeys(const WebElementId& element, const string16& keys) {
ListValue args;
args.Append(element.ToValue());
- // Focus the element if not focused already. If it is an editable element,
- // focus the editing host element instead. Descendants of an editing host
- // element cannot be focused in chrome.
- // See http://www.w3.org/TR/html5/editing.html#attr-contenteditable.
+ // 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, 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
// TODO(jleyba): Update this to use the correct atom.
const char* kFocusScript =
"var elem = arguments[0];"
- "if (elem.isContentEditable) {"
- " while (elem.parentNode && elem.parentNode.isContentEditable)"
- " elem = elem.parentNode;"
- "}"
- "if (elem != document.activeElement) {"
- " if(document.activeElement)"
- " document.activeElement.blur();"
- " elem.focus();"
- "}";
+ "var doc = elem.ownerDocument || elem;"
+ "var prevActiveElem = doc.activeElement;"
+ "if (elem != prevActiveElem && prevActiveElem)"
+ " prevActiveElem.blur();"
+ "elem.focus();"
+ "if (elem != doc.activeElement)"
+ " throw new Error('Failed to send keys because cannot focus element.');";
Value* unscoped_result = NULL;
error = ExecuteScript(kFocusScript, &args, &unscoped_result);
- if (error) {
- error->AddDetails("Failed to focus element before sending keys");
+ if (error)
return error;
- }
+
error = NULL;
RunSessionTask(NewRunnableMethod(
this,
@@ -523,6 +532,7 @@ Error* Session::SwitchToWindow(const std::string& name) {
if (!switch_to_id)
return new Error(kNoSuchWindow);
+ frame_elements_.clear();
current_target_ = FrameId(switch_to_id, FramePath());
return NULL;
}
@@ -564,7 +574,7 @@ Error* Session::SwitchToFrameWithIndex(int index) {
"console.info(frame == null ? 'found nothing' : frame);"
"if (!frame) { return null; }"
"frame_xpath = ((frame.tagName == 'IFRAME' ? "
- " '/html/body//iframe' : '/html/frameset/frame') + index);"
+ " '(/html/body//iframe)' : '/html/frameset/frame') + index);"
"return [frame, frame_xpath];";
ListValue args;
args.Append(Value::CreateIntegerValue(index));
@@ -923,11 +933,13 @@ Error* Session::GetElementBorder(const FrameId& frame_id,
Error* Session::IsElementDisplayed(const FrameId& frame_id,
const WebElementId& element,
+ bool ignore_opacity,
bool* is_displayed) {
std::string script = base::StringPrintf(
"return (%s).apply(null, arguments);", atoms::IS_DISPLAYED);
ListValue args;
args.Append(element.ToValue());
+ args.Append(Value::CreateBooleanValue(ignore_opacity));
Value* unscoped_result = NULL;
Error* error = ExecuteScript(frame_id, script, &args, &unscoped_result);
@@ -996,7 +1008,8 @@ Error* Session::GetElementTagName(const FrameId& frame_id,
Error* Session::GetClickableLocation(const WebElementId& element,
gfx::Point* location) {
bool is_displayed = false;
- Error* error = IsElementDisplayed(current_target_, element, &is_displayed);
+ Error* error = IsElementDisplayed(
+ current_target_, element, true /* ignore_opacity */, &is_displayed);
if (error)
return error;
if (!is_displayed)
@@ -1163,12 +1176,11 @@ Error* Session::ExecuteScriptAndParseResponse(const FrameId& frame_id,
ErrorCode code = static_cast<ErrorCode>(status);
if (code != kSuccess) {
DictionaryValue* error_dict;
- std::string error_msg = "Script threw an exception";
- if (result_dict->GetDictionary("value", &error_dict)) {
- std::string exception;
- if (error_dict->GetString("message", &exception))
- error_msg += ": " + exception;
- }
+ 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);
}