| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/test/webdriver/session.h" | 5 #include "chrome/test/webdriver/session.h" |
| 6 | 6 |
| 7 #include <sstream> | 7 #include <sstream> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 #include "base/synchronization/waitable_event.h" | 25 #include "base/synchronization/waitable_event.h" |
| 26 #include "base/test/test_timeouts.h" | 26 #include "base/test/test_timeouts.h" |
| 27 #include "base/threading/platform_thread.h" | 27 #include "base/threading/platform_thread.h" |
| 28 #include "base/time.h" | 28 #include "base/time.h" |
| 29 #include "base/utf_string_conversions.h" | 29 #include "base/utf_string_conversions.h" |
| 30 #include "base/values.h" | 30 #include "base/values.h" |
| 31 #include "chrome/app/chrome_command_ids.h" | 31 #include "chrome/app/chrome_command_ids.h" |
| 32 #include "chrome/common/chrome_constants.h" | 32 #include "chrome/common/chrome_constants.h" |
| 33 #include "chrome/common/chrome_switches.h" | 33 #include "chrome/common/chrome_switches.h" |
| 34 #include "chrome/test/automation/automation_json_requests.h" | 34 #include "chrome/test/automation/automation_json_requests.h" |
| 35 #include "chrome/test/automation/value_conversion_util.h" |
| 36 #include "chrome/test/webdriver/session_manager.h" |
| 35 #include "chrome/test/webdriver/webdriver_error.h" | 37 #include "chrome/test/webdriver/webdriver_error.h" |
| 36 #include "chrome/test/webdriver/session_manager.h" | |
| 37 #include "chrome/test/webdriver/utility_functions.h" | |
| 38 #include "chrome/test/webdriver/webdriver_key_converter.h" | 38 #include "chrome/test/webdriver/webdriver_key_converter.h" |
| 39 #include "chrome/test/webdriver/webdriver_util.h" |
| 39 #include "third_party/webdriver/atoms.h" | 40 #include "third_party/webdriver/atoms.h" |
| 40 #include "ui/gfx/point.h" | |
| 41 #include "ui/gfx/rect.h" | |
| 42 #include "ui/gfx/size.h" | |
| 43 | 41 |
| 44 namespace webdriver { | 42 namespace webdriver { |
| 45 | 43 |
| 46 FrameId::FrameId(int window_id, const FramePath& frame_path) | 44 FrameId::FrameId(int window_id, const FramePath& frame_path) |
| 47 : window_id(window_id), | 45 : window_id(window_id), |
| 48 frame_path(frame_path) { | 46 frame_path(frame_path) { |
| 49 } | 47 } |
| 50 | 48 |
| 51 FrameId& FrameId::operator=(const FrameId& other) { | 49 FrameId& FrameId::operator=(const FrameId& other) { |
| 52 window_id = other.window_id; | 50 window_id = other.window_id; |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 124 &args_as_json); | 122 &args_as_json); |
| 125 | 123 |
| 126 // Every injected script is fed through the executeScript atom. This atom | 124 // Every injected script is fed through the executeScript atom. This atom |
| 127 // will catch any errors that are thrown and convert them to the | 125 // will catch any errors that are thrown and convert them to the |
| 128 // appropriate JSON structure. | 126 // appropriate JSON structure. |
| 129 std::string jscript = base::StringPrintf( | 127 std::string jscript = base::StringPrintf( |
| 130 "window.domAutomationController.send((%s).apply(null," | 128 "window.domAutomationController.send((%s).apply(null," |
| 131 "[function(){%s\n},%s,true]));", | 129 "[function(){%s\n},%s,true]));", |
| 132 atoms::EXECUTE_SCRIPT, script.c_str(), args_as_json.c_str()); | 130 atoms::EXECUTE_SCRIPT, script.c_str(), args_as_json.c_str()); |
| 133 | 131 |
| 134 return ExecuteScriptAndParseResponse(frame_id, jscript, value); | 132 return ExecuteScriptAndParseValue(frame_id, jscript, value); |
| 135 } | 133 } |
| 136 | 134 |
| 137 Error* Session::ExecuteScript(const std::string& script, | 135 Error* Session::ExecuteScript(const std::string& script, |
| 138 const ListValue* const args, | 136 const ListValue* const args, |
| 139 Value** value) { | 137 Value** value) { |
| 140 return ExecuteScript(current_target_, script, args, value); | 138 return ExecuteScript(current_target_, script, args, value); |
| 141 } | 139 } |
| 142 | 140 |
| 141 Error* Session::ExecuteScriptAndParse(const FrameId& frame_id, |
| 142 const std::string& anonymous_func_script, |
| 143 const std::string& script_name, |
| 144 const ListValue* args, |
| 145 const ValueParser* parser) { |
| 146 scoped_ptr<const ListValue> scoped_args(args); |
| 147 scoped_ptr<const ValueParser> scoped_parser(parser); |
| 148 std::string called_script = base::StringPrintf( |
| 149 "return (%s).apply(null, arguments);", anonymous_func_script.c_str()); |
| 150 Value* unscoped_value = NULL; |
| 151 Error* error = ExecuteScript(frame_id, called_script, args, &unscoped_value); |
| 152 if (error) { |
| 153 error->AddDetails(script_name + " execution failed"); |
| 154 return error; |
| 155 } |
| 156 |
| 157 scoped_ptr<Value> value(unscoped_value); |
| 158 std::string error_msg; |
| 159 if (!parser->Parse(value.get())) { |
| 160 error_msg = base::StringPrintf("%s returned invalid value: %s", |
| 161 script_name.c_str(), JsonStringify(value.get()).c_str()); |
| 162 return new Error(kUnknownError, error_msg); |
| 163 } |
| 164 return NULL; |
| 165 } |
| 166 |
| 143 Error* Session::ExecuteAsyncScript(const FrameId& frame_id, | 167 Error* Session::ExecuteAsyncScript(const FrameId& frame_id, |
| 144 const std::string& script, | 168 const std::string& script, |
| 145 const ListValue* const args, | 169 const ListValue* const args, |
| 146 Value** value) { | 170 Value** value) { |
| 147 std::string args_as_json; | 171 std::string args_as_json; |
| 148 base::JSONWriter::Write(static_cast<const Value* const>(args), | 172 base::JSONWriter::Write(static_cast<const Value* const>(args), |
| 149 /*pretty_print=*/false, | 173 /*pretty_print=*/false, |
| 150 &args_as_json); | 174 &args_as_json); |
| 151 | 175 |
| 152 int timeout_ms = async_script_timeout(); | 176 int timeout_ms = async_script_timeout(); |
| 153 | 177 |
| 154 // Every injected script is fed through the executeScript atom. This atom | 178 // Every injected script is fed through the executeScript atom. This atom |
| 155 // will catch any errors that are thrown and convert them to the | 179 // will catch any errors that are thrown and convert them to the |
| 156 // appropriate JSON structure. | 180 // appropriate JSON structure. |
| 157 std::string jscript = base::StringPrintf( | 181 std::string jscript = base::StringPrintf( |
| 158 "(%s).apply(null, [function(){%s},%s,%d,%s,true]);", | 182 "(%s).apply(null, [function(){%s},%s,%d,%s,true]);", |
| 159 atoms::EXECUTE_ASYNC_SCRIPT, | 183 atoms::EXECUTE_ASYNC_SCRIPT, |
| 160 script.c_str(), | 184 script.c_str(), |
| 161 args_as_json.c_str(), | 185 args_as_json.c_str(), |
| 162 timeout_ms, | 186 timeout_ms, |
| 163 "function(result) {window.domAutomationController.send(result);}"); | 187 "function(result) {window.domAutomationController.send(result);}"); |
| 164 | 188 |
| 165 return ExecuteScriptAndParseResponse(frame_id, jscript, value); | 189 return ExecuteScriptAndParseValue(frame_id, jscript, value); |
| 166 } | 190 } |
| 167 | 191 |
| 168 Error* Session::SendKeys(const WebElementId& element, const string16& keys) { | 192 Error* Session::SendKeys(const WebElementId& element, const string16& keys) { |
| 169 bool is_displayed = false; | 193 bool is_displayed = false; |
| 170 Error* error = IsElementDisplayed( | 194 Error* error = IsElementDisplayed( |
| 171 current_target_, element, true /* ignore_opacity */, &is_displayed); | 195 current_target_, element, true /* ignore_opacity */, &is_displayed); |
| 172 if (error) | 196 if (error) |
| 173 return error; | 197 return error; |
| 174 if (!is_displayed) | 198 if (!is_displayed) |
| 175 return new Error(kElementNotVisible); | 199 return new Error(kElementNotVisible); |
| 176 | 200 |
| 177 bool is_enabled = false; | 201 bool is_enabled = false; |
| 178 error = IsElementEnabled(current_target_, element, &is_enabled); | 202 error = IsElementEnabled(current_target_, element, &is_enabled); |
| 179 if (error) | 203 if (error) |
| 180 return error; | 204 return error; |
| 181 if (!is_enabled) | 205 if (!is_enabled) |
| 182 return new Error(kInvalidElementState); | 206 return new Error(kInvalidElementState); |
| 183 | 207 |
| 184 ListValue args; | |
| 185 args.Append(element.ToValue()); | |
| 186 // Focus the target element in order to send keys to it. | 208 // Focus the target element in order to send keys to it. |
| 187 // First, the currently active element is blurred, if it is different from | 209 // First, the currently active element is blurred, if it is different from |
| 188 // the target element. We do not want to blur an element unnecessarily, | 210 // the target element. We do not want to blur an element unnecessarily, |
| 189 // because this may cause us to lose the current cursor position in the | 211 // because this may cause us to lose the current cursor position in the |
| 190 // element. | 212 // element. |
| 191 // Secondly, we focus the target element. | 213 // Secondly, we focus the target element. |
| 192 // Thirdly, if the target element is newly focused and is a text input, we | 214 // Thirdly, if the target element is newly focused and is a text input, we |
| 193 // set the cursor position at the end. | 215 // set the cursor position at the end. |
| 194 // Fourthly, we check if the new active element is the target element. If not, | 216 // Fourthly, we check if the new active element is the target element. If not, |
| 195 // we throw an error. | 217 // we throw an error. |
| 196 // Additional notes: | 218 // Additional notes: |
| 197 // - |document.activeElement| is the currently focused element, or body if | 219 // - |document.activeElement| is the currently focused element, or body if |
| 198 // no element is focused | 220 // no element is focused |
| 199 // - Even if |document.hasFocus()| returns true and the active element is | 221 // - Even if |document.hasFocus()| returns true and the active element is |
| 200 // the body, sometimes we still need to focus the body element for send | 222 // the body, sometimes we still need to focus the body element for send |
| 201 // keys to work. Not sure why | 223 // keys to work. Not sure why |
| 202 // - You cannot focus a descendant of a content editable node | 224 // - You cannot focus a descendant of a content editable node |
| 203 // TODO(jleyba): Update this to use the correct atom. | 225 // TODO(jleyba): Update this to use the correct atom. |
| 204 const char* kFocusScript = | 226 const char* kFocusScript = |
| 205 "var elem = arguments[0];" | 227 "function(elem) {" |
| 206 "var doc = elem.ownerDocument || elem;" | 228 " var doc = elem.ownerDocument || elem;" |
| 207 "var prevActiveElem = doc.activeElement;" | 229 " var prevActiveElem = doc.activeElement;" |
| 208 "if (elem != prevActiveElem && prevActiveElem)" | 230 " if (elem != prevActiveElem && prevActiveElem)" |
| 209 " prevActiveElem.blur();" | 231 " prevActiveElem.blur();" |
| 210 "elem.focus();" | 232 " elem.focus();" |
| 211 "if (elem != prevActiveElem && elem.value && elem.value.length &&" | 233 " if (elem != prevActiveElem && elem.value && elem.value.length &&" |
| 212 " elem.setSelectionRange) {" | 234 " elem.setSelectionRange) {" |
| 213 " elem.setSelectionRange(elem.value.length, elem.value.length);" | 235 " elem.setSelectionRange(elem.value.length, elem.value.length);" |
| 214 "}" | 236 " }" |
| 215 "if (elem != doc.activeElement)" | 237 " if (elem != doc.activeElement)" |
| 216 " throw new Error('Failed to send keys because cannot focus element.');"; | 238 " throw new Error('Failed to send keys because cannot focus element');" |
| 217 Value* unscoped_result = NULL; | 239 "}"; |
| 218 error = ExecuteScript(kFocusScript, &args, &unscoped_result); | 240 error = ExecuteScriptAndParse(current_target_, |
| 241 kFocusScript, |
| 242 "focusElement", |
| 243 CreateListValueFrom(element), |
| 244 CreateDirectValueParser(kSkipParsing)); |
| 219 if (error) | 245 if (error) |
| 220 return error; | 246 return error; |
| 221 | 247 |
| 222 error = NULL; | |
| 223 RunSessionTask(NewRunnableMethod( | 248 RunSessionTask(NewRunnableMethod( |
| 224 this, | 249 this, |
| 225 &Session::SendKeysOnSessionThread, | 250 &Session::SendKeysOnSessionThread, |
| 226 keys, | 251 keys, |
| 227 &error)); | 252 &error)); |
| 228 return error; | 253 return error; |
| 229 } | 254 } |
| 230 | 255 |
| 231 Error* Session::DragAndDropFilePaths( | 256 Error* Session::DragAndDropFilePaths( |
| 232 const gfx::Point& location, | 257 const Point& location, |
| 233 const std::vector<FilePath::StringType>& paths) { | 258 const std::vector<FilePath::StringType>& paths) { |
| 234 Error* error = NULL; | 259 Error* error = NULL; |
| 235 RunSessionTask(NewRunnableMethod( | 260 RunSessionTask(NewRunnableMethod( |
| 236 automation_.get(), | 261 automation_.get(), |
| 237 &Automation::DragAndDropFilePaths, | 262 &Automation::DragAndDropFilePaths, |
| 238 current_target_.window_id, | 263 current_target_.window_id, |
| 239 location, | 264 location, |
| 240 paths, | 265 paths, |
| 241 &error)); | 266 &error)); |
| 242 return error; | 267 return error; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 286 Error* error = NULL; | 311 Error* error = NULL; |
| 287 RunSessionTask(NewRunnableMethod( | 312 RunSessionTask(NewRunnableMethod( |
| 288 automation_.get(), | 313 automation_.get(), |
| 289 &Automation::Reload, | 314 &Automation::Reload, |
| 290 current_target_.window_id, | 315 current_target_.window_id, |
| 291 &error)); | 316 &error)); |
| 292 return error; | 317 return error; |
| 293 } | 318 } |
| 294 | 319 |
| 295 Error* Session::GetURL(std::string* url) { | 320 Error* Session::GetURL(std::string* url) { |
| 296 ListValue no_args; | 321 return ExecuteScriptAndParse(current_target_, |
| 297 Value* unscoped_value = NULL; | 322 "function() { return document.URL }", |
| 298 Error* error = ExecuteScript(current_target_, | 323 "getUrl", |
| 299 "return document.URL;", | 324 new ListValue(), |
| 300 &no_args, | 325 CreateDirectValueParser(url)); |
| 301 &unscoped_value); | |
| 302 scoped_ptr<Value> value(unscoped_value); | |
| 303 if (error) | |
| 304 return error; | |
| 305 if (!value->GetAsString(url)) | |
| 306 return new Error(kUnknownError, "GetURL Script returned non-string: " + | |
| 307 JsonStringify(value.get())); | |
| 308 return NULL; | |
| 309 } | 326 } |
| 310 | 327 |
| 311 Error* Session::GetTitle(std::string* tab_title) { | 328 Error* Session::GetTitle(std::string* tab_title) { |
| 312 std::string script = | 329 const char* kGetTitleScript = |
| 313 "if (document.title)" | 330 "function() {" |
| 314 " return document.title;" | 331 " if (document.title)" |
| 315 "else" | 332 " return document.title;" |
| 316 " return document.URL;"; | 333 " else" |
| 317 | 334 " return document.URL;" |
| 318 ListValue no_args; | 335 "}"; |
| 319 Value* unscoped_value = NULL; | 336 return ExecuteScriptAndParse(current_target_, |
| 320 Error* error = ExecuteScript(current_target_, | 337 kGetTitleScript, |
| 321 script, | 338 "getTitle", |
| 322 &no_args, | 339 new ListValue(), |
| 323 &unscoped_value); | 340 CreateDirectValueParser(tab_title)); |
| 324 scoped_ptr<Value> value(unscoped_value); | |
| 325 if (error) | |
| 326 return error; | |
| 327 if (!value->GetAsString(tab_title)) | |
| 328 return new Error(kUnknownError, "GetTitle script returned non-string: " + | |
| 329 JsonStringify(value.get())); | |
| 330 return NULL; | |
| 331 } | 341 } |
| 332 | 342 |
| 333 Error* Session::MouseMoveAndClick(const gfx::Point& location, | 343 Error* Session::MouseMoveAndClick(const Point& location, |
| 334 automation::MouseButton button) { | 344 automation::MouseButton button) { |
| 335 Error* error = NULL; | 345 Error* error = NULL; |
| 336 RunSessionTask(NewRunnableMethod( | 346 RunSessionTask(NewRunnableMethod( |
| 337 automation_.get(), | 347 automation_.get(), |
| 338 &Automation::MouseClick, | 348 &Automation::MouseClick, |
| 339 current_target_.window_id, | 349 current_target_.window_id, |
| 340 location, | 350 location, |
| 341 button, | 351 button, |
| 342 &error)); | 352 &error)); |
| 343 if (!error) | 353 if (!error) |
| 344 mouse_position_ = location; | 354 mouse_position_ = location; |
| 345 return error; | 355 return error; |
| 346 } | 356 } |
| 347 | 357 |
| 348 Error* Session::MouseMove(const gfx::Point& location) { | 358 Error* Session::MouseMove(const Point& location) { |
| 349 Error* error = NULL; | 359 Error* error = NULL; |
| 350 RunSessionTask(NewRunnableMethod( | 360 RunSessionTask(NewRunnableMethod( |
| 351 automation_.get(), | 361 automation_.get(), |
| 352 &Automation::MouseMove, | 362 &Automation::MouseMove, |
| 353 current_target_.window_id, | 363 current_target_.window_id, |
| 354 location, | 364 location, |
| 355 &error)); | 365 &error)); |
| 356 if (!error) | 366 if (!error) |
| 357 mouse_position_ = location; | 367 mouse_position_ = location; |
| 358 return error; | 368 return error; |
| 359 } | 369 } |
| 360 | 370 |
| 361 Error* Session::MouseDrag(const gfx::Point& start, | 371 Error* Session::MouseDrag(const Point& start, |
| 362 const gfx::Point& end) { | 372 const Point& end) { |
| 363 Error* error = NULL; | 373 Error* error = NULL; |
| 364 RunSessionTask(NewRunnableMethod( | 374 RunSessionTask(NewRunnableMethod( |
| 365 automation_.get(), | 375 automation_.get(), |
| 366 &Automation::MouseDrag, | 376 &Automation::MouseDrag, |
| 367 current_target_.window_id, | 377 current_target_.window_id, |
| 368 start, | 378 start, |
| 369 end, | 379 end, |
| 370 &error)); | 380 &error)); |
| 371 if (!error) | 381 if (!error) |
| 372 mouse_position_ = end; | 382 mouse_position_ = end; |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 473 switch_to_id = name_no; | 483 switch_to_id = name_no; |
| 474 } | 484 } |
| 475 | 485 |
| 476 if (!switch_to_id) { | 486 if (!switch_to_id) { |
| 477 std::vector<int> window_ids; | 487 std::vector<int> window_ids; |
| 478 Error* error = GetWindowIds(&window_ids); | 488 Error* error = GetWindowIds(&window_ids); |
| 479 if (error) | 489 if (error) |
| 480 return error; | 490 return error; |
| 481 // See if any of the window names match |name|. | 491 // See if any of the window names match |name|. |
| 482 for (size_t i = 0; i < window_ids.size(); ++i) { | 492 for (size_t i = 0; i < window_ids.size(); ++i) { |
| 483 ListValue empty_list; | |
| 484 Value* unscoped_name_value = NULL; | |
| 485 std::string window_name; | 493 std::string window_name; |
| 486 Error* error = ExecuteScript(FrameId(window_ids[i], FramePath()), | 494 Error* error = ExecuteScriptAndParse( |
| 487 "return window.name;", | 495 FrameId(window_ids[i], FramePath()), |
| 488 &empty_list, | 496 "function() { return window.name; }", |
| 489 &unscoped_name_value); | 497 "getWindowName", |
| 498 new ListValue(), |
| 499 CreateDirectValueParser(&window_name)); |
| 490 if (error) | 500 if (error) |
| 491 return error; | 501 return error; |
| 492 scoped_ptr<Value> name_value(unscoped_name_value); | 502 if (name == window_name) { |
| 493 if (name_value->GetAsString(&window_name) && | |
| 494 name == window_name) { | |
| 495 switch_to_id = window_ids[i]; | 503 switch_to_id = window_ids[i]; |
| 496 break; | 504 break; |
| 497 } | 505 } |
| 498 } | 506 } |
| 499 } | 507 } |
| 500 | 508 |
| 501 if (!switch_to_id) | 509 if (!switch_to_id) |
| 502 return new Error(kNoSuchWindow); | 510 return new Error(kNoSuchWindow); |
| 503 frame_elements_.clear(); | 511 frame_elements_.clear(); |
| 504 current_target_ = FrameId(switch_to_id, FramePath()); | 512 current_target_ = FrameId(switch_to_id, FramePath()); |
| 505 return NULL; | 513 return NULL; |
| 506 } | 514 } |
| 507 | 515 |
| 508 Error* Session::SwitchToFrameWithNameOrId(const std::string& name_or_id) { | 516 Error* Session::SwitchToFrameWithNameOrId(const std::string& name_or_id) { |
| 509 std::string script = | 517 std::string script = |
| 510 "var arg = arguments[0];" | 518 "function(arg) {" |
| 511 "var xpath = '(/html/body//iframe|/html/frameset/frame)';" | 519 " var xpath = '(/html/body//iframe|/html/frameset/frame)';" |
| 512 "var sub = function(s) { return s.replace(/\\$/g, arg); };" | 520 " var sub = function(s) { return s.replace(/\\$/g, arg); };" |
| 513 "xpath += sub('[@name=\"$\" or @id=\"$\"]');" | 521 " xpath += sub('[@name=\"$\" or @id=\"$\"]');" |
| 514 "var frame = document.evaluate(xpath, document, null, " | 522 " var frame = document.evaluate(xpath, document, null, " |
| 515 " XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;" | 523 " XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;" |
| 516 "if (!frame) { return null; }" | 524 " if (!frame) { return null; }" |
| 517 "xpath = frame.tagName == 'IFRAME' ? '/html/body//iframe'" | 525 " xpath = frame.tagName == 'IFRAME' ? '/html/body//iframe'" |
| 518 " : '/html/frameset/frame';" | 526 " : '/html/frameset/frame';" |
| 519 "frame_xpath = xpath + " | 527 " frame_xpath = xpath + " |
| 520 " sub('[@' + (frame.id == arg ? 'id' : 'name') + '=\"$\"]');" | 528 " sub('[@' + (frame.id == arg ? 'id' : 'name') + '=\"$\"]');" |
| 521 "return [frame, frame_xpath];"; | 529 " return [frame, frame_xpath];" |
| 522 ListValue args; | 530 "}"; |
| 523 args.Append(new StringValue(name_or_id)); | 531 return SwitchToFrameWithJavaScriptLocatedFrame( |
| 524 return SwitchToFrameWithJavaScriptLocatedFrame(script, &args); | 532 script, CreateListValueFrom(name_or_id)); |
| 525 } | 533 } |
| 526 | 534 |
| 527 Error* Session::SwitchToFrameWithIndex(int index) { | 535 Error* Session::SwitchToFrameWithIndex(int index) { |
| 528 // We cannot simply index into window.frames because we need to know the | 536 // We cannot simply index into window.frames because we need to know the |
| 529 // tagName of the frameElement. If child frame N is from another domain, then | 537 // tagName of the frameElement. If child frame N is from another domain, then |
| 530 // the following will run afoul of the same origin policy: | 538 // the following will run afoul of the same origin policy: |
| 531 // window.frames[N].frameElement; | 539 // window.frames[N].frameElement; |
| 532 // Instead of indexing window.frames, we use a an XPath expression to index | 540 // Instead of indexing window.frames, we use a an XPath expression to index |
| 533 // into the list of all IFRAME and FRAME elements on the page - if we find | 541 // into the list of all IFRAME and FRAME elements on the page - if we find |
| 534 // something, then that XPath expression can be used as the new frame's XPath. | 542 // something, then that XPath expression can be used as the new frame's XPath. |
| 535 std::string script = | 543 std::string script = |
| 536 "var index = '[' + (arguments[0] + 1) + ']';" | 544 "function(index) {" |
| 537 "var xpath = '(/html/body//iframe|/html/frameset/frame)' + " | 545 " var xpathIndex = '[' + (index + 1) + ']';" |
| 538 " index;" | 546 " var xpath = '(/html/body//iframe|/html/frameset/frame)' + " |
| 539 "console.info('searching for frame by xpath: ' + xpath);" | 547 " xpathIndex;" |
| 540 "var frame = document.evaluate(xpath, document, null, " | 548 " var frame = document.evaluate(xpath, document, null, " |
| 541 "XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;" | 549 " XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;" |
| 542 "console.info(frame == null ? 'found nothing' : frame);" | 550 " if (!frame) { return null; }" |
| 543 "if (!frame) { return null; }" | 551 " frame_xpath = ((frame.tagName == 'IFRAME' ? " |
| 544 "frame_xpath = ((frame.tagName == 'IFRAME' ? " | 552 " '(/html/body//iframe)' : '/html/frameset/frame') + xpathIndex);" |
| 545 " '(/html/body//iframe)' : '/html/frameset/frame') + index);" | 553 " return [frame, frame_xpath];" |
| 546 "return [frame, frame_xpath];"; | 554 "}"; |
| 547 ListValue args; | 555 return SwitchToFrameWithJavaScriptLocatedFrame( |
| 548 args.Append(Value::CreateIntegerValue(index)); | 556 script, CreateListValueFrom(index)); |
| 549 return SwitchToFrameWithJavaScriptLocatedFrame(script, &args); | |
| 550 } | 557 } |
| 551 | 558 |
| 552 Error* Session::SwitchToFrameWithElement(const WebElementId& element) { | 559 Error* Session::SwitchToFrameWithElement(const WebElementId& element) { |
| 553 // TODO(jleyba): Extract this, and the other frame switch methods to an atom. | 560 // TODO(jleyba): Extract this, and the other frame switch methods to an atom. |
| 554 std::string script = | 561 std::string script = |
| 555 "var element = arguments[0];" | 562 "function(elem) {" |
| 556 "console.info('Attempting to switch to ' + element);" | 563 " if (elem.nodeType != 1 || !/^i?frame$/i.test(elem.tagName)) {" |
| 557 "if (element.nodeType != 1 || !/^i?frame$/i.test(element.tagName)) {" | 564 " console.error('Element is not a frame');" |
| 558 " console.info('Element is not a frame: ' + element + " | 565 " return null;" |
| 559 "' {nodeType:' + element.nodeType + ',tagName:' + element.tagName + '}');" | 566 " }" |
| 567 " for (var i = 0; i < window.frames.length; i++) {" |
| 568 " if (elem.contentWindow == window.frames[i]) {" |
| 569 " return [elem, '(//iframe|//frame)[' + (i + 1) + ']'];" |
| 570 " }" |
| 571 " }" |
| 572 " console.info('Frame is not connected to this DOM tree');" |
| 560 " return null;" | 573 " return null;" |
| 561 "}" | 574 "}"; |
| 562 "for (var i = 0; i < window.frames.length; i++) {" | 575 return SwitchToFrameWithJavaScriptLocatedFrame( |
| 563 " if (element.contentWindow == window.frames[i]) {" | 576 script, CreateListValueFrom(element)); |
| 564 " return [element, '(//iframe|//frame)[' + (i + 1) + ']'];" | |
| 565 " }" | |
| 566 "}" | |
| 567 "console.info('Frame is not connected to this DOM tree');" | |
| 568 "return null;"; | |
| 569 | |
| 570 ListValue args; | |
| 571 args.Append(element.ToValue()); | |
| 572 return SwitchToFrameWithJavaScriptLocatedFrame(script, &args); | |
| 573 } | 577 } |
| 574 | 578 |
| 575 void Session::SwitchToTopFrame() { | 579 void Session::SwitchToTopFrame() { |
| 576 frame_elements_.clear(); | 580 frame_elements_.clear(); |
| 577 current_target_.frame_path = FramePath(); | 581 current_target_.frame_path = FramePath(); |
| 578 } | 582 } |
| 579 | 583 |
| 580 Error* Session::SwitchToTopFrameIfCurrentFrameInvalid() { | 584 Error* Session::SwitchToTopFrameIfCurrentFrameInvalid() { |
| 581 std::vector<std::string> components; | 585 std::vector<std::string> components; |
| 582 current_target_.frame_path.GetComponents(&components); | 586 current_target_.frame_path.GetComponents(&components); |
| 583 if (frame_elements_.size() != components.size()) { | 587 if (frame_elements_.size() != components.size()) { |
| 584 return new Error(kUnknownError, | 588 return new Error(kUnknownError, |
| 585 "Frame element vector out of sync with frame path"); | 589 "Frame element vector out of sync with frame path"); |
| 586 } | 590 } |
| 587 FramePath frame_path; | 591 FramePath frame_path; |
| 588 // Start from the root path and check that each frame element that makes | 592 // Start from the root path and check that each frame element that makes |
| 589 // up the current frame target is valid by executing an empty script. | 593 // up the current frame target is valid by executing an empty script. |
| 590 // This code should not execute script in any frame before making sure the | 594 // This code should not execute script in any frame before making sure the |
| 591 // frame element is valid, otherwise the automation hangs until a timeout. | 595 // frame element is valid, otherwise the automation hangs until a timeout. |
| 592 for (size_t i = 0; i < frame_elements_.size(); ++i) { | 596 for (size_t i = 0; i < frame_elements_.size(); ++i) { |
| 593 FrameId frame_id(current_target_.window_id, frame_path); | 597 FrameId frame_id(current_target_.window_id, frame_path); |
| 594 ListValue args; | 598 scoped_ptr<Error> error(ExecuteScriptAndParse( |
| 595 args.Append(frame_elements_[i].ToValue()); | 599 frame_id, |
| 596 Value* unscoped_value = NULL; | 600 "function(){ }", |
| 597 scoped_ptr<Error> error(ExecuteScript( | 601 "emptyScript", |
| 598 frame_id, "", &args, &unscoped_value)); | 602 CreateListValueFrom(frame_elements_[i]), |
| 599 | 603 CreateDirectValueParser(kSkipParsing))); |
| 600 scoped_ptr<Value> value(unscoped_value); | |
| 601 if (error.get() && error->code() == kStaleElementReference) { | 604 if (error.get() && error->code() == kStaleElementReference) { |
| 602 SwitchToTopFrame(); | 605 SwitchToTopFrame(); |
| 603 } else if (error.get()) { | 606 } else if (error.get()) { |
| 604 return error.release(); | 607 return error.release(); |
| 605 } | 608 } |
| 606 frame_path = frame_path.Append(components[i]); | 609 frame_path = frame_path.Append(components[i]); |
| 607 } | 610 } |
| 608 return NULL; | 611 return NULL; |
| 609 } | 612 } |
| 610 | 613 |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 723 const WebElementId& root_element, | 726 const WebElementId& root_element, |
| 724 const std::string& locator, | 727 const std::string& locator, |
| 725 const std::string& query, | 728 const std::string& query, |
| 726 std::vector<WebElementId>* elements) { | 729 std::vector<WebElementId>* elements) { |
| 727 return FindElementsHelper( | 730 return FindElementsHelper( |
| 728 frame_id, root_element, locator, query, false, elements); | 731 frame_id, root_element, locator, query, false, elements); |
| 729 } | 732 } |
| 730 | 733 |
| 731 Error* Session::GetElementLocationInView( | 734 Error* Session::GetElementLocationInView( |
| 732 const WebElementId& element, | 735 const WebElementId& element, |
| 733 gfx::Point* location) { | 736 Point* location) { |
| 734 gfx::Size size; | 737 Size size; |
| 735 Error* error = GetElementSize(current_target_, element, &size); | 738 Error* error = GetElementSize(current_target_, element, &size); |
| 736 if (error) | 739 if (error) |
| 737 return error; | 740 return error; |
| 738 return GetElementRegionInView( | 741 return GetElementRegionInView( |
| 739 element, gfx::Rect(gfx::Point(0, 0), size), | 742 element, Rect(Point(0, 0), size), |
| 740 false /* center */, false /* verify_clickable_at_middle */, location); | 743 false /* center */, false /* verify_clickable_at_middle */, location); |
| 741 } | 744 } |
| 742 | 745 |
| 743 Error* Session::GetElementRegionInView( | 746 Error* Session::GetElementRegionInView( |
| 744 const WebElementId& element, | 747 const WebElementId& element, |
| 745 const gfx::Rect& region, | 748 const Rect& region, |
| 746 bool center, | 749 bool center, |
| 747 bool verify_clickable_at_middle, | 750 bool verify_clickable_at_middle, |
| 748 gfx::Point* location) { | 751 Point* location) { |
| 749 CHECK(element.is_valid()); | 752 CHECK(element.is_valid()); |
| 750 | 753 |
| 751 gfx::Point region_offset = region.origin(); | 754 Point region_offset = region.origin(); |
| 752 gfx::Size region_size = region.size(); | 755 Size region_size = region.size(); |
| 753 Error* error = GetElementRegionInViewHelper( | 756 Error* error = GetElementRegionInViewHelper( |
| 754 current_target_, element, region, center, verify_clickable_at_middle, | 757 current_target_, element, region, center, verify_clickable_at_middle, |
| 755 ®ion_offset); | 758 ®ion_offset); |
| 756 if (error) | 759 if (error) |
| 757 return error; | 760 return error; |
| 758 | 761 |
| 759 for (FramePath frame_path = current_target_.frame_path; | 762 for (FramePath frame_path = current_target_.frame_path; |
| 760 frame_path.IsSubframe(); | 763 frame_path.IsSubframe(); |
| 761 frame_path = frame_path.Parent()) { | 764 frame_path = frame_path.Parent()) { |
| 762 // Find the frame element for the current frame path. | 765 // Find the frame element for the current frame path. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 775 } | 778 } |
| 776 // Modify |region_offset| by the frame's border. | 779 // Modify |region_offset| by the frame's border. |
| 777 int border_left, border_top; | 780 int border_left, border_top; |
| 778 error = GetElementBorder( | 781 error = GetElementBorder( |
| 779 frame_id, frame_element, &border_left, &border_top); | 782 frame_id, frame_element, &border_left, &border_top); |
| 780 if (error) | 783 if (error) |
| 781 return error; | 784 return error; |
| 782 region_offset.Offset(border_left, border_top); | 785 region_offset.Offset(border_left, border_top); |
| 783 | 786 |
| 784 error = GetElementRegionInViewHelper( | 787 error = GetElementRegionInViewHelper( |
| 785 frame_id, frame_element, gfx::Rect(region_offset, region_size), | 788 frame_id, frame_element, Rect(region_offset, region_size), |
| 786 center, verify_clickable_at_middle, ®ion_offset); | 789 center, verify_clickable_at_middle, ®ion_offset); |
| 787 if (error) | 790 if (error) |
| 788 return error; | 791 return error; |
| 789 } | 792 } |
| 790 *location = region_offset; | 793 *location = region_offset; |
| 791 return NULL; | 794 return NULL; |
| 792 } | 795 } |
| 793 | 796 |
| 794 Error* Session::GetElementSize(const FrameId& frame_id, | 797 Error* Session::GetElementSize(const FrameId& frame_id, |
| 795 const WebElementId& element, | 798 const WebElementId& element, |
| 796 gfx::Size* size) { | 799 Size* size) { |
| 797 std::string script = base::StringPrintf( | 800 return ExecuteScriptAndParse(frame_id, |
| 798 "return (%s).apply(null, arguments);", atoms::GET_SIZE); | 801 atoms::GET_SIZE, |
| 799 ListValue args; | 802 "getSize", |
| 800 args.Append(element.ToValue()); | 803 CreateListValueFrom(element), |
| 801 | 804 CreateDirectValueParser(size)); |
| 802 Value* unscoped_result = NULL; | |
| 803 Error* error = ExecuteScript(frame_id, script, &args, &unscoped_result); | |
| 804 scoped_ptr<Value> result(unscoped_result); | |
| 805 if (error) | |
| 806 return error; | |
| 807 if (!result->IsType(Value::TYPE_DICTIONARY)) { | |
| 808 return new Error(kUnknownError, "GetSize atom returned non-dict type: " + | |
| 809 JsonStringify(result.get())); | |
| 810 } | |
| 811 DictionaryValue* dict = static_cast<DictionaryValue*>(result.get()); | |
| 812 int width, height; | |
| 813 if (!dict->GetInteger("width", &width) || | |
| 814 !dict->GetInteger("height", &height)) { | |
| 815 return new Error(kUnknownError, "GetSize atom returned invalid dict: " + | |
| 816 JsonStringify(dict)); | |
| 817 } | |
| 818 *size = gfx::Size(width, height); | |
| 819 return NULL; | |
| 820 } | 805 } |
| 821 | 806 |
| 822 Error* Session::GetElementFirstClientRect(const FrameId& frame_id, | 807 Error* Session::GetElementFirstClientRect(const FrameId& frame_id, |
| 823 const WebElementId& element, | 808 const WebElementId& element, |
| 824 gfx::Rect* rect) { | 809 Rect* rect) { |
| 825 std::string script = base::StringPrintf( | 810 return ExecuteScriptAndParse(frame_id, |
| 826 "return (%s).apply(null, arguments);", atoms::GET_FIRST_CLIENT_RECT); | 811 atoms::GET_FIRST_CLIENT_RECT, |
| 827 ListValue args; | 812 "getFirstClientRect", |
| 828 args.Append(element.ToValue()); | 813 CreateListValueFrom(element), |
| 829 | 814 CreateDirectValueParser(rect)); |
| 830 Value* unscoped_result = NULL; | |
| 831 Error* error = ExecuteScript(frame_id, script, &args, &unscoped_result); | |
| 832 scoped_ptr<Value> result(unscoped_result); | |
| 833 if (error) | |
| 834 return error; | |
| 835 if (!result->IsType(Value::TYPE_DICTIONARY)) { | |
| 836 return new Error( | |
| 837 kUnknownError, | |
| 838 "GetFirstClientRect atom returned non-dict type: " + | |
| 839 JsonStringify(result.get())); | |
| 840 } | |
| 841 DictionaryValue* dict = static_cast<DictionaryValue*>(result.get()); | |
| 842 // TODO(kkania): Convert the atom to return integers. | |
| 843 double left, top, width, height; | |
| 844 if (!dict->GetDouble("left", &left) || | |
| 845 !dict->GetDouble("top", &top) || | |
| 846 !dict->GetDouble("width", &width) || | |
| 847 !dict->GetDouble("height", &height)) { | |
| 848 return new Error( | |
| 849 kUnknownError, | |
| 850 "GetFirstClientRect atom returned invalid dict: " + | |
| 851 JsonStringify(dict)); | |
| 852 } | |
| 853 *rect = gfx::Rect(static_cast<int>(left), static_cast<int>(top), | |
| 854 static_cast<int>(width), static_cast<int>(height)); | |
| 855 return NULL; | |
| 856 } | 815 } |
| 857 | 816 |
| 858 Error* Session::GetElementEffectiveStyle( | 817 Error* Session::GetElementEffectiveStyle( |
| 859 const FrameId& frame_id, | 818 const FrameId& frame_id, |
| 860 const WebElementId& element, | 819 const WebElementId& element, |
| 861 const std::string& prop, | 820 const std::string& prop, |
| 862 std::string* value) { | 821 std::string* value) { |
| 863 std::string script = base::StringPrintf( | 822 return ExecuteScriptAndParse(frame_id, |
| 864 "return (%s).apply(null, arguments);", atoms::GET_EFFECTIVE_STYLE); | 823 atoms::GET_EFFECTIVE_STYLE, |
| 865 ListValue args; | 824 "getEffectiveStyle", |
| 866 args.Append(element.ToValue()); | 825 CreateListValueFrom(element, prop), |
| 867 args.Append(Value::CreateStringValue(prop)); | 826 CreateDirectValueParser(value)); |
| 868 Value* unscoped_result = NULL; | |
| 869 Error* error = ExecuteScript( | |
| 870 frame_id, script, &args, &unscoped_result); | |
| 871 scoped_ptr<Value> result(unscoped_result); | |
| 872 if (error) { | |
| 873 error->AddDetails(base::StringPrintf( | |
| 874 "GetEffectiveStyle atom failed for property (%s)", prop.c_str())); | |
| 875 return error; | |
| 876 } | |
| 877 | |
| 878 if (!result->GetAsString(value)) { | |
| 879 std::string context = base::StringPrintf( | |
| 880 "GetEffectiveStyle atom returned non-string for property (%s): %s", | |
| 881 prop.c_str(), JsonStringify(result.get()).c_str()); | |
| 882 return new Error(kUnknownError, context); | |
| 883 } | |
| 884 return NULL; | |
| 885 } | 827 } |
| 886 | 828 |
| 887 Error* Session::GetElementBorder(const FrameId& frame_id, | 829 Error* Session::GetElementBorder(const FrameId& frame_id, |
| 888 const WebElementId& element, | 830 const WebElementId& element, |
| 889 int* border_left, | 831 int* border_left, |
| 890 int* border_top) { | 832 int* border_top) { |
| 891 std::string border_left_str, border_top_str; | 833 std::string border_left_str, border_top_str; |
| 892 Error* error = GetElementEffectiveStyle( | 834 Error* error = GetElementEffectiveStyle( |
| 893 frame_id, element, "border-left-width", &border_left_str); | 835 frame_id, element, "border-left-width", &border_left_str); |
| 894 if (error) | 836 if (error) |
| 895 return error; | 837 return error; |
| 896 error = GetElementEffectiveStyle( | 838 error = GetElementEffectiveStyle( |
| 897 frame_id, element, "border-top-width", &border_top_str); | 839 frame_id, element, "border-top-width", &border_top_str); |
| 898 if (error) | 840 if (error) |
| 899 return error; | 841 return error; |
| 900 | 842 |
| 901 base::StringToInt(border_left_str, border_left); | 843 base::StringToInt(border_left_str, border_left); |
| 902 base::StringToInt(border_top_str, border_top); | 844 base::StringToInt(border_top_str, border_top); |
| 903 return NULL; | 845 return NULL; |
| 904 } | 846 } |
| 905 | 847 |
| 906 Error* Session::IsElementDisplayed(const FrameId& frame_id, | 848 Error* Session::IsElementDisplayed(const FrameId& frame_id, |
| 907 const WebElementId& element, | 849 const WebElementId& element, |
| 908 bool ignore_opacity, | 850 bool ignore_opacity, |
| 909 bool* is_displayed) { | 851 bool* is_displayed) { |
| 910 std::string script = base::StringPrintf( | 852 return ExecuteScriptAndParse(frame_id, |
| 911 "return (%s).apply(null, arguments);", atoms::IS_DISPLAYED); | 853 atoms::IS_DISPLAYED, |
| 912 ListValue args; | 854 "isDisplayed", |
| 913 args.Append(element.ToValue()); | 855 CreateListValueFrom(element, ignore_opacity), |
| 914 args.Append(Value::CreateBooleanValue(ignore_opacity)); | 856 CreateDirectValueParser(is_displayed)); |
| 915 | |
| 916 Value* unscoped_result = NULL; | |
| 917 Error* error = ExecuteScript(frame_id, script, &args, &unscoped_result); | |
| 918 scoped_ptr<Value> result(unscoped_result); | |
| 919 if (error) | |
| 920 return error; | |
| 921 if (!result->GetAsBoolean(is_displayed)) | |
| 922 return new Error(kUnknownError, "IsDisplayed atom returned non-boolean: " + | |
| 923 JsonStringify(result.get())); | |
| 924 return NULL; | |
| 925 } | 857 } |
| 926 | 858 |
| 927 Error* Session::IsElementEnabled(const FrameId& frame_id, | 859 Error* Session::IsElementEnabled(const FrameId& frame_id, |
| 928 const WebElementId& element, | 860 const WebElementId& element, |
| 929 bool* is_enabled) { | 861 bool* is_enabled) { |
| 930 std::string script = base::StringPrintf( | 862 return ExecuteScriptAndParse(frame_id, |
| 931 "return (%s).apply(null, arguments);", atoms::IS_ENABLED); | 863 atoms::IS_ENABLED, |
| 932 ListValue args; | 864 "isEnabled", |
| 933 args.Append(element.ToValue()); | 865 CreateListValueFrom(element), |
| 934 | 866 CreateDirectValueParser(is_enabled)); |
| 935 Value* unscoped_result = NULL; | |
| 936 Error* error = ExecuteScript(frame_id, script, &args, &unscoped_result); | |
| 937 scoped_ptr<Value> result(unscoped_result); | |
| 938 if (error) | |
| 939 return error; | |
| 940 if (!result->GetAsBoolean(is_enabled)) | |
| 941 return new Error(kUnknownError, "IsEnabled atom returned non-boolean: " + | |
| 942 JsonStringify(result.get())); | |
| 943 return NULL; | |
| 944 } | 867 } |
| 945 | 868 |
| 946 Error* Session::IsOptionElementSelected(const FrameId& frame_id, | 869 Error* Session::IsOptionElementSelected(const FrameId& frame_id, |
| 947 const WebElementId& element, | 870 const WebElementId& element, |
| 948 bool* is_selected) { | 871 bool* is_selected) { |
| 949 ListValue args; | 872 return ExecuteScriptAndParse( |
| 950 args.Append(element.ToValue()); | 873 frame_id, |
| 951 | 874 atoms::IS_SELECTED, |
| 952 std::string script = base::StringPrintf( | 875 "isSelected", |
| 953 "return (%s).apply(null, arguments);", atoms::IS_SELECTED); | 876 CreateListValueFrom(element), |
| 954 | 877 CreateDirectValueParser(is_selected)); |
| 955 Value* result = NULL; | |
| 956 Error* error = ExecuteScript(frame_id, script, &args, &result); | |
| 957 if (error) | |
| 958 return error; | |
| 959 scoped_ptr<Value> scoped_result(result); | |
| 960 if (!result->GetAsBoolean(is_selected)) { | |
| 961 return new Error(kUnknownError, "isSelected atom returned non-boolean: " + | |
| 962 JsonStringify(result)); | |
| 963 } | |
| 964 return NULL; | |
| 965 } | 878 } |
| 966 | 879 |
| 967 Error* Session::SetOptionElementSelected(const FrameId& frame_id, | 880 Error* Session::SetOptionElementSelected(const FrameId& frame_id, |
| 968 const WebElementId& element, | 881 const WebElementId& element, |
| 969 bool selected) { | 882 bool selected) { |
| 970 ListValue args; | 883 return ExecuteScriptAndParse(frame_id, |
| 971 args.Append(element.ToValue()); | 884 atoms::SET_SELECTED, |
| 972 args.Append(Value::CreateBooleanValue(selected)); | 885 "setSelected", |
| 973 | 886 CreateListValueFrom(element, selected), |
| 974 std::string script = base::StringPrintf( | 887 CreateDirectValueParser(kSkipParsing)); |
| 975 "return (%s).apply(null, arguments);", atoms::SET_SELECTED); | |
| 976 | |
| 977 Value* unscoped_result = NULL; | |
| 978 Error* error = ExecuteScript(frame_id, script, &args, &unscoped_result); | |
| 979 scoped_ptr<Value> result(unscoped_result); | |
| 980 return error; | |
| 981 } | 888 } |
| 982 | 889 |
| 983 Error* Session::ToggleOptionElement(const FrameId& frame_id, | 890 Error* Session::ToggleOptionElement(const FrameId& frame_id, |
| 984 const WebElementId& element) { | 891 const WebElementId& element) { |
| 985 bool is_selected; | 892 bool is_selected; |
| 986 Error* error = IsOptionElementSelected(frame_id, element, &is_selected); | 893 Error* error = IsOptionElementSelected(frame_id, element, &is_selected); |
| 987 if (error) | 894 if (error) |
| 988 return error; | 895 return error; |
| 989 | 896 |
| 990 return SetOptionElementSelected(frame_id, element, !is_selected); | 897 return SetOptionElementSelected(frame_id, element, !is_selected); |
| 991 } | 898 } |
| 992 | 899 |
| 993 Error* Session::GetElementTagName(const FrameId& frame_id, | 900 Error* Session::GetElementTagName(const FrameId& frame_id, |
| 994 const WebElementId& element, | 901 const WebElementId& element, |
| 995 std::string* tag_name) { | 902 std::string* tag_name) { |
| 996 ListValue args; | 903 return ExecuteScriptAndParse( |
| 997 args.Append(element.ToValue()); | 904 frame_id, |
| 998 | 905 "function(elem) { return elem.tagName.toLowerCase() }", |
| 999 std::string script = "return arguments[0].tagName.toLocaleLowerCase();"; | 906 "getElementTagName", |
| 1000 | 907 CreateListValueFrom(element), |
| 1001 Value* unscoped_result = NULL; | 908 CreateDirectValueParser(tag_name)); |
| 1002 Error* error = ExecuteScript(frame_id, script, &args, &unscoped_result); | |
| 1003 scoped_ptr<Value> result(unscoped_result); | |
| 1004 if (error) | |
| 1005 return error; | |
| 1006 if (!result->GetAsString(tag_name)) | |
| 1007 return new Error(kUnknownError, "TagName script returned non-string: " + | |
| 1008 JsonStringify(result.get())); | |
| 1009 return NULL; | |
| 1010 } | 909 } |
| 1011 | 910 |
| 1012 Error* Session::GetClickableLocation(const WebElementId& element, | 911 Error* Session::GetClickableLocation(const WebElementId& element, |
| 1013 gfx::Point* location) { | 912 Point* location) { |
| 1014 bool is_displayed = false; | 913 bool is_displayed = false; |
| 1015 Error* error = IsElementDisplayed( | 914 Error* error = IsElementDisplayed( |
| 1016 current_target_, element, true /* ignore_opacity */, &is_displayed); | 915 current_target_, element, true /* ignore_opacity */, &is_displayed); |
| 1017 if (error) | 916 if (error) |
| 1018 return error; | 917 return error; |
| 1019 if (!is_displayed) | 918 if (!is_displayed) |
| 1020 return new Error(kElementNotVisible, "Element must be displayed to click"); | 919 return new Error(kElementNotVisible, "Element must be displayed to click"); |
| 1021 | 920 |
| 1022 gfx::Rect rect; | 921 Rect rect; |
| 1023 error = GetElementFirstClientRect(current_target_, element, &rect); | 922 error = GetElementFirstClientRect(current_target_, element, &rect); |
| 1024 if (error) | 923 if (error) |
| 1025 return error; | 924 return error; |
| 1026 | 925 |
| 1027 error = GetElementRegionInView( | 926 error = GetElementRegionInView( |
| 1028 element, rect, true /* center */, true /* verify_clickable_at_middle */, | 927 element, rect, true /* center */, true /* verify_clickable_at_middle */, |
| 1029 location); | 928 location); |
| 1030 if (error) | 929 if (error) |
| 1031 return error; | 930 return error; |
| 1032 location->Offset(rect.width() / 2, rect.height() / 2); | 931 location->Offset(rect.width() / 2, rect.height() / 2); |
| 1033 return NULL; | 932 return NULL; |
| 1034 } | 933 } |
| 1035 | 934 |
| 1036 Error* Session::GetAttribute(const WebElementId& element, | 935 Error* Session::GetAttribute(const WebElementId& element, |
| 1037 const std::string& key, Value** value) { | 936 const std::string& key, |
| 1038 std::string script = base::StringPrintf( | 937 Value** value) { |
| 1039 "return (%s).apply(null, arguments);", atoms::GET_ATTRIBUTE); | 938 return ExecuteScriptAndParse(current_target_, |
| 1040 | 939 atoms::GET_ATTRIBUTE, |
| 1041 ListValue args; | 940 "getAttribute", |
| 1042 args.Append(element.ToValue()); | 941 CreateListValueFrom(element, key), |
| 1043 args.Append(Value::CreateStringValue(key)); | 942 CreateDirectValueParser(value)); |
| 1044 | |
| 1045 Error* error = ExecuteScript(script, &args, value); | |
| 1046 if (error) { | |
| 1047 return error; | |
| 1048 } | |
| 1049 | |
| 1050 return NULL; | |
| 1051 } | 943 } |
| 1052 | 944 |
| 1053 Error* Session::WaitForAllTabsToStopLoading() { | 945 Error* Session::WaitForAllTabsToStopLoading() { |
| 1054 if (!automation_.get()) | 946 if (!automation_.get()) |
| 1055 return NULL; | 947 return NULL; |
| 1056 Error* error = NULL; | 948 Error* error = NULL; |
| 1057 RunSessionTask(NewRunnableMethod( | 949 RunSessionTask(NewRunnableMethod( |
| 1058 automation_.get(), | 950 automation_.get(), |
| 1059 &Automation::WaitForAllTabsToStopLoading, | 951 &Automation::WaitForAllTabsToStopLoading, |
| 1060 &error)); | 952 &error)); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1088 } | 980 } |
| 1089 | 981 |
| 1090 void Session::set_implicit_wait(int timeout_ms) { | 982 void Session::set_implicit_wait(int timeout_ms) { |
| 1091 implicit_wait_ = timeout_ms; | 983 implicit_wait_ = timeout_ms; |
| 1092 } | 984 } |
| 1093 | 985 |
| 1094 int Session::implicit_wait() const { | 986 int Session::implicit_wait() const { |
| 1095 return implicit_wait_; | 987 return implicit_wait_; |
| 1096 } | 988 } |
| 1097 | 989 |
| 1098 const gfx::Point& Session::get_mouse_position() const { | 990 const Point& Session::get_mouse_position() const { |
| 1099 return mouse_position_; | 991 return mouse_position_; |
| 1100 } | 992 } |
| 1101 | 993 |
| 1102 const Session::Options& Session::options() const { | 994 const Session::Options& Session::options() const { |
| 1103 return options_; | 995 return options_; |
| 1104 } | 996 } |
| 1105 | 997 |
| 1106 void Session::RunSessionTask(Task* task) { | 998 void Session::RunSessionTask(Task* task) { |
| 1107 base::WaitableEvent done_event(false, false); | 999 base::WaitableEvent done_event(false, false); |
| 1108 thread_.message_loop_proxy()->PostTask(FROM_HERE, NewRunnableMethod( | 1000 thread_.message_loop_proxy()->PostTask(FROM_HERE, NewRunnableMethod( |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1138 } | 1030 } |
| 1139 current_target_ = FrameId(tab_ids[0], FramePath()); | 1031 current_target_ = FrameId(tab_ids[0], FramePath()); |
| 1140 } | 1032 } |
| 1141 | 1033 |
| 1142 void Session::TerminateOnSessionThread() { | 1034 void Session::TerminateOnSessionThread() { |
| 1143 if (automation_.get()) | 1035 if (automation_.get()) |
| 1144 automation_->Terminate(); | 1036 automation_->Terminate(); |
| 1145 automation_.reset(); | 1037 automation_.reset(); |
| 1146 } | 1038 } |
| 1147 | 1039 |
| 1148 Error* Session::ExecuteScriptAndParseResponse(const FrameId& frame_id, | 1040 Error* Session::ExecuteScriptAndParseValue(const FrameId& frame_id, |
| 1149 const std::string& script, | 1041 const std::string& script, |
| 1150 Value** script_result) { | 1042 Value** script_result) { |
| 1151 std::string response_json; | 1043 std::string response_json; |
| 1152 Error* error = NULL; | 1044 Error* error = NULL; |
| 1153 RunSessionTask(NewRunnableMethod( | 1045 RunSessionTask(NewRunnableMethod( |
| 1154 automation_.get(), | 1046 automation_.get(), |
| 1155 &Automation::ExecuteScript, | 1047 &Automation::ExecuteScript, |
| 1156 frame_id.window_id, | 1048 frame_id.window_id, |
| 1157 frame_id.frame_path, | 1049 frame_id.frame_path, |
| 1158 script, | 1050 script, |
| 1159 &response_json, | 1051 &response_json, |
| 1160 &error)); | 1052 &error)); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1229 key_events[i].modified_text.c_str(), | 1121 key_events[i].modified_text.c_str(), |
| 1230 key_events[i].modifiers); | 1122 key_events[i].modifiers); |
| 1231 (*error)->AddDetails(details); | 1123 (*error)->AddDetails(details); |
| 1232 return; | 1124 return; |
| 1233 } | 1125 } |
| 1234 } | 1126 } |
| 1235 } | 1127 } |
| 1236 | 1128 |
| 1237 Error* Session::SwitchToFrameWithJavaScriptLocatedFrame( | 1129 Error* Session::SwitchToFrameWithJavaScriptLocatedFrame( |
| 1238 const std::string& script, ListValue* args) { | 1130 const std::string& script, ListValue* args) { |
| 1239 Value* unscoped_result = NULL; | 1131 class SwitchFrameValueParser : public ValueParser { |
| 1240 Error* error = ExecuteScript(script, args, &unscoped_result); | 1132 public: |
| 1241 scoped_ptr<Value> result(unscoped_result); | 1133 SwitchFrameValueParser( |
| 1134 bool* found_frame, WebElementId* frame, std::string* xpath) |
| 1135 : found_frame_(found_frame), frame_(frame), xpath_(xpath) { } |
| 1136 |
| 1137 virtual ~SwitchFrameValueParser() { } |
| 1138 |
| 1139 virtual bool Parse(base::Value* value) const OVERRIDE { |
| 1140 if (value->IsType(Value::TYPE_NULL)) { |
| 1141 *found_frame_ = false; |
| 1142 return true; |
| 1143 } |
| 1144 ListValue* list; |
| 1145 if (!value->GetAsList(&list)) |
| 1146 return false; |
| 1147 *found_frame_ = true; |
| 1148 return SetFromListValue(list, frame_, xpath_); |
| 1149 } |
| 1150 |
| 1151 private: |
| 1152 bool* found_frame_; |
| 1153 WebElementId* frame_; |
| 1154 std::string* xpath_; |
| 1155 }; |
| 1156 |
| 1157 bool found_frame; |
| 1158 WebElementId new_frame_element; |
| 1159 std::string xpath; |
| 1160 Error* error = ExecuteScriptAndParse( |
| 1161 current_target_, script, "switchFrame", args, |
| 1162 new SwitchFrameValueParser(&found_frame, &new_frame_element, &xpath)); |
| 1242 if (error) | 1163 if (error) |
| 1243 return error; | 1164 return error; |
| 1244 | 1165 |
| 1245 ListValue* frame_and_xpath_list; | 1166 if (!found_frame) |
| 1246 if (!result->GetAsList(&frame_and_xpath_list)) | |
| 1247 return new Error(kNoSuchFrame); | 1167 return new Error(kNoSuchFrame); |
| 1248 DictionaryValue* element_dict; | |
| 1249 std::string xpath; | |
| 1250 if (!frame_and_xpath_list->GetDictionary(0, &element_dict) || | |
| 1251 !frame_and_xpath_list->GetString(1, &xpath)) { | |
| 1252 return new Error( | |
| 1253 kUnknownError, | |
| 1254 "Frame finding script did not return correct type: " + | |
| 1255 JsonStringify(frame_and_xpath_list)); | |
| 1256 } | |
| 1257 WebElementId new_frame_element(element_dict); | |
| 1258 if (!new_frame_element.is_valid()) { | |
| 1259 return new Error( | |
| 1260 kUnknownError, | |
| 1261 "Frame finding script did not return a frame element: " + | |
| 1262 JsonStringify(element_dict)); | |
| 1263 } | |
| 1264 | 1168 |
| 1265 frame_elements_.push_back(new_frame_element); | 1169 frame_elements_.push_back(new_frame_element); |
| 1266 current_target_.frame_path = current_target_.frame_path.Append(xpath); | 1170 current_target_.frame_path = current_target_.frame_path.Append(xpath); |
| 1267 return NULL; | 1171 return NULL; |
| 1268 } | 1172 } |
| 1269 | 1173 |
| 1270 Error* Session::FindElementsHelper(const FrameId& frame_id, | 1174 Error* Session::FindElementsHelper(const FrameId& frame_id, |
| 1271 const WebElementId& root_element, | 1175 const WebElementId& root_element, |
| 1272 const std::string& locator, | 1176 const std::string& locator, |
| 1273 const std::string& query, | 1177 const std::string& query, |
| 1274 bool find_one, | 1178 bool find_one, |
| 1275 std::vector<WebElementId>* elements) { | 1179 std::vector<WebElementId>* elements) { |
| 1276 CHECK(root_element.is_valid()); | 1180 CHECK(root_element.is_valid()); |
| 1181 base::Time start_time = base::Time::Now(); |
| 1182 while (true) { |
| 1183 std::vector<WebElementId> temp_elements; |
| 1184 Error* error = ExecuteFindElementScriptAndParse( |
| 1185 frame_id, root_element, locator, query, find_one, &temp_elements); |
| 1186 if (error) |
| 1187 return error; |
| 1277 | 1188 |
| 1278 std::string jscript; | 1189 if (temp_elements.size() > 0u) { |
| 1279 if (find_one) { | 1190 elements->swap(temp_elements); |
| 1280 // TODO(jleyba): Write a Chrome-specific find element atom that will | 1191 break; |
| 1281 // correctly throw an error if the element cannot be found. | 1192 } |
| 1282 jscript = base::StringPrintf( | |
| 1283 "var result = (%s).apply(null, arguments);" | |
| 1284 "if (!result) {" | |
| 1285 "var e = new Error('Unable to locate element');" | |
| 1286 "e.code = %d;" | |
| 1287 "throw e;" | |
| 1288 "} else { return result; }", | |
| 1289 atoms::FIND_ELEMENT, kNoSuchElement); | |
| 1290 } else { | |
| 1291 jscript = base::StringPrintf("return (%s).apply(null, arguments);", | |
| 1292 atoms::FIND_ELEMENTS); | |
| 1293 } | |
| 1294 ListValue jscript_args; | |
| 1295 DictionaryValue* locator_dict = new DictionaryValue(); | |
| 1296 locator_dict->SetString(locator, query); | |
| 1297 jscript_args.Append(locator_dict); | |
| 1298 jscript_args.Append(root_element.ToValue()); | |
| 1299 | 1193 |
| 1300 // The element search needs to loop until at least one element is found or the | 1194 if ((base::Time::Now() - start_time).InMilliseconds() > implicit_wait_) { |
| 1301 // session's implicit wait timeout expires, whichever occurs first. | 1195 if (find_one) |
| 1302 base::Time start_time = base::Time::Now(); | 1196 return new Error(kNoSuchElement); |
| 1303 | 1197 break; |
| 1304 scoped_ptr<Value> value; | |
| 1305 scoped_ptr<Error> error; | |
| 1306 bool done = false; | |
| 1307 while (!done) { | |
| 1308 Value* unscoped_value = NULL; | |
| 1309 error.reset(ExecuteScript( | |
| 1310 frame_id, jscript, &jscript_args, &unscoped_value)); | |
| 1311 value.reset(unscoped_value); | |
| 1312 if (!error.get()) { | |
| 1313 // If searching for many elements, make sure we found at least one before | |
| 1314 // stopping. | |
| 1315 done = find_one || | |
| 1316 (value->GetType() == Value::TYPE_LIST && | |
| 1317 static_cast<ListValue*>(value.get())->GetSize() > 0); | |
| 1318 } else if (error->code() != kNoSuchElement) { | |
| 1319 return error.release(); | |
| 1320 } | 1198 } |
| 1321 int64 elapsed_time = (base::Time::Now() - start_time).InMilliseconds(); | 1199 base::PlatformThread::Sleep(50); |
| 1322 done = done || elapsed_time > implicit_wait_; | |
| 1323 if (!done) | |
| 1324 base::PlatformThread::Sleep(50); // Prevent a busy loop. | |
| 1325 } | |
| 1326 | |
| 1327 if (error.get()) | |
| 1328 return error.release(); | |
| 1329 | |
| 1330 // Parse the results. | |
| 1331 const std::string kInvalidElementDictionaryMessage = | |
| 1332 "Find element script returned invalid element dictionary: " + | |
| 1333 JsonStringify(value.get()); | |
| 1334 if (value->IsType(Value::TYPE_LIST)) { | |
| 1335 ListValue* element_list = static_cast<ListValue*>(value.get()); | |
| 1336 for (size_t i = 0; i < element_list->GetSize(); ++i) { | |
| 1337 DictionaryValue* element_dict = NULL; | |
| 1338 if (!element_list->GetDictionary(i, &element_dict)) { | |
| 1339 return new Error( | |
| 1340 kUnknownError, | |
| 1341 "Find element script returned non-dictionary: " + | |
| 1342 JsonStringify(element_list)); | |
| 1343 } | |
| 1344 | |
| 1345 WebElementId element(element_dict); | |
| 1346 if (!element.is_valid()) { | |
| 1347 return new Error(kUnknownError, kInvalidElementDictionaryMessage); | |
| 1348 } | |
| 1349 elements->push_back(element); | |
| 1350 } | |
| 1351 } else if (value->IsType(Value::TYPE_DICTIONARY)) { | |
| 1352 DictionaryValue* element_dict = | |
| 1353 static_cast<DictionaryValue*>(value.get()); | |
| 1354 WebElementId element(element_dict); | |
| 1355 if (!element.is_valid()) { | |
| 1356 return new Error(kUnknownError, kInvalidElementDictionaryMessage); | |
| 1357 } | |
| 1358 elements->push_back(element); | |
| 1359 } else { | |
| 1360 return new Error( | |
| 1361 kUnknownError, | |
| 1362 "Find element script returned unsupported type: " + | |
| 1363 JsonStringify(value.get())); | |
| 1364 } | 1200 } |
| 1365 return NULL; | 1201 return NULL; |
| 1366 } | 1202 } |
| 1367 | 1203 |
| 1204 Error* Session::ExecuteFindElementScriptAndParse( |
| 1205 const FrameId& frame_id, |
| 1206 const WebElementId& root_element, |
| 1207 const std::string& locator, |
| 1208 const std::string& query, |
| 1209 bool find_one, |
| 1210 std::vector<WebElementId>* elements) { |
| 1211 CHECK(root_element.is_valid()); |
| 1212 |
| 1213 class FindElementsParser : public ValueParser { |
| 1214 public: |
| 1215 explicit FindElementsParser(std::vector<WebElementId>* elements) |
| 1216 : elements_(elements) { } |
| 1217 |
| 1218 virtual ~FindElementsParser() { } |
| 1219 |
| 1220 virtual bool Parse(base::Value* value) const OVERRIDE { |
| 1221 if (!value->IsType(Value::TYPE_LIST)) |
| 1222 return false; |
| 1223 ListValue* list = static_cast<ListValue*>(value); |
| 1224 for (size_t i = 0; i < list->GetSize(); ++i) { |
| 1225 WebElementId element; |
| 1226 Value* element_value = NULL; |
| 1227 if (!list->Get(i, &element_value)) |
| 1228 return false; |
| 1229 if (!SetFromValue(element_value, &element)) |
| 1230 return false; |
| 1231 elements_->push_back(element); |
| 1232 } |
| 1233 return true; |
| 1234 } |
| 1235 private: |
| 1236 std::vector<WebElementId>* elements_; |
| 1237 }; |
| 1238 |
| 1239 class FindElementParser : public ValueParser { |
| 1240 public: |
| 1241 explicit FindElementParser(std::vector<WebElementId>* elements) |
| 1242 : elements_(elements) { } |
| 1243 |
| 1244 virtual ~FindElementParser() { } |
| 1245 |
| 1246 virtual bool Parse(base::Value* value) const OVERRIDE { |
| 1247 if (value->IsType(Value::TYPE_NULL)) |
| 1248 return true; |
| 1249 WebElementId element; |
| 1250 bool set = SetFromValue(value, &element); |
| 1251 if (set) |
| 1252 elements_->push_back(element); |
| 1253 return set; |
| 1254 } |
| 1255 private: |
| 1256 std::vector<WebElementId>* elements_; |
| 1257 }; |
| 1258 |
| 1259 DictionaryValue locator_dict; |
| 1260 locator_dict.SetString(locator, query); |
| 1261 std::vector<WebElementId> temp_elements; |
| 1262 Error* error = NULL; |
| 1263 if (find_one) { |
| 1264 error = ExecuteScriptAndParse( |
| 1265 frame_id, |
| 1266 atoms::FIND_ELEMENT, |
| 1267 "findElement", |
| 1268 CreateListValueFrom(&locator_dict, root_element), |
| 1269 new FindElementParser(&temp_elements)); |
| 1270 } else { |
| 1271 error = ExecuteScriptAndParse( |
| 1272 frame_id, |
| 1273 atoms::FIND_ELEMENTS, |
| 1274 "findElements", |
| 1275 CreateListValueFrom(&locator_dict, root_element), |
| 1276 new FindElementsParser(&temp_elements)); |
| 1277 } |
| 1278 if (!error) |
| 1279 elements->swap(temp_elements); |
| 1280 return error; |
| 1281 } |
| 1282 |
| 1368 Error* Session::VerifyElementIsClickable( | 1283 Error* Session::VerifyElementIsClickable( |
| 1369 const FrameId& frame_id, | 1284 const FrameId& frame_id, |
| 1370 const WebElementId& element, | 1285 const WebElementId& element, |
| 1371 const gfx::Point& location) { | 1286 const Point& location) { |
| 1372 std::string jscript = base::StringPrintf( | 1287 class IsElementClickableParser : public ValueParser { |
| 1373 "return (%s).apply(null, arguments);", atoms::IS_ELEMENT_CLICKABLE); | 1288 public: |
| 1374 ListValue jscript_args; | 1289 IsElementClickableParser(bool* clickable, std::string* message) |
| 1375 jscript_args.Append(element.ToValue()); | 1290 : clickable_(clickable), message_(message) { } |
| 1376 DictionaryValue* location_dict = new DictionaryValue(); | 1291 |
| 1377 location_dict->SetInteger("x", location.x()); | 1292 virtual ~IsElementClickableParser() { } |
| 1378 location_dict->SetInteger("y", location.y()); | 1293 |
| 1379 jscript_args.Append(location_dict); | 1294 virtual bool Parse(base::Value* value) const OVERRIDE { |
| 1380 Value* unscoped_value = NULL; | 1295 if (!value->IsType(Value::TYPE_DICTIONARY)) |
| 1381 Error* error = ExecuteScript(frame_id, jscript, &jscript_args, | 1296 return false; |
| 1382 &unscoped_value); | 1297 DictionaryValue* dict = static_cast<DictionaryValue*>(value); |
| 1298 dict->GetString("message", message_); |
| 1299 return dict->GetBoolean("clickable", clickable_); |
| 1300 } |
| 1301 |
| 1302 private: |
| 1303 bool* clickable_; |
| 1304 std::string* message_; |
| 1305 }; |
| 1306 |
| 1307 bool clickable; |
| 1308 std::string message; |
| 1309 Error* error = ExecuteScriptAndParse( |
| 1310 frame_id, |
| 1311 atoms::IS_ELEMENT_CLICKABLE, |
| 1312 "isElementClickable", |
| 1313 CreateListValueFrom(element, location), |
| 1314 new IsElementClickableParser(&clickable, &message)); |
| 1383 if (error) | 1315 if (error) |
| 1384 return error; | 1316 return error; |
| 1385 | 1317 |
| 1386 scoped_ptr<Value> value(unscoped_value); | |
| 1387 if (!value->IsType(Value::TYPE_DICTIONARY)) { | |
| 1388 return new Error( | |
| 1389 kUnknownError, | |
| 1390 "isElementClickable atom returned non-dictionary type: " + | |
| 1391 JsonStringify(value.get())); | |
| 1392 } | |
| 1393 DictionaryValue* dict = static_cast<DictionaryValue*>(value.get()); | |
| 1394 bool clickable = false; | |
| 1395 if (!dict->GetBoolean("clickable", &clickable)) { | |
| 1396 return new Error( | |
| 1397 kUnknownError, | |
| 1398 "isElementClickable atom returned bad invalid dictionary: " + | |
| 1399 JsonStringify(dict)); | |
| 1400 } | |
| 1401 std::string message; | |
| 1402 dict->GetString("message", &message); | |
| 1403 if (!clickable) { | 1318 if (!clickable) { |
| 1404 if (message.empty()) | 1319 if (message.empty()) |
| 1405 message = "element is not clickable"; | 1320 message = "element is not clickable"; |
| 1406 return new Error(kUnknownError, message); | 1321 return new Error(kUnknownError, message); |
| 1407 } | 1322 } |
| 1408 if (message.length()) { | 1323 if (message.length()) { |
| 1409 LOG(WARNING) << message; | 1324 LOG(WARNING) << message; |
| 1410 } | 1325 } |
| 1411 return NULL; | 1326 return NULL; |
| 1412 } | 1327 } |
| 1413 | 1328 |
| 1414 Error* Session::GetElementRegionInViewHelper( | 1329 Error* Session::GetElementRegionInViewHelper( |
| 1415 const FrameId& frame_id, | 1330 const FrameId& frame_id, |
| 1416 const WebElementId& element, | 1331 const WebElementId& element, |
| 1417 const gfx::Rect& region, | 1332 const Rect& region, |
| 1418 bool center, | 1333 bool center, |
| 1419 bool verify_clickable_at_middle, | 1334 bool verify_clickable_at_middle, |
| 1420 gfx::Point* location) { | 1335 Point* location) { |
| 1421 std::string jscript = base::StringPrintf( | 1336 Point temp_location; |
| 1422 "return (%s).apply(null, arguments);", atoms::GET_LOCATION_IN_VIEW); | 1337 Error* error = ExecuteScriptAndParse( |
| 1423 ListValue jscript_args; | 1338 frame_id, |
| 1424 jscript_args.Append(element.ToValue()); | 1339 atoms::GET_LOCATION_IN_VIEW, |
| 1425 jscript_args.Append(Value::CreateBooleanValue(center)); | 1340 "getLocationInView", |
| 1426 DictionaryValue* elem_offset_dict = new DictionaryValue(); | 1341 CreateListValueFrom(element, center, region), |
| 1427 elem_offset_dict->SetInteger("left", region.x()); | 1342 CreateDirectValueParser(&temp_location)); |
| 1428 elem_offset_dict->SetInteger("top", region.y()); | |
| 1429 elem_offset_dict->SetInteger("width", region.width()); | |
| 1430 elem_offset_dict->SetInteger("height", region.height()); | |
| 1431 jscript_args.Append(elem_offset_dict); | |
| 1432 Value* unscoped_value = NULL; | |
| 1433 Error* error = ExecuteScript(frame_id, jscript, &jscript_args, | |
| 1434 &unscoped_value); | |
| 1435 scoped_ptr<Value> value(unscoped_value); | |
| 1436 if (error) | |
| 1437 return error; | |
| 1438 | |
| 1439 if (!value->IsType(Value::TYPE_DICTIONARY)) { | |
| 1440 return new Error( | |
| 1441 kUnknownError, | |
| 1442 "Location atom returned non-dictionary type: " + | |
| 1443 JsonStringify(value.get())); | |
| 1444 } | |
| 1445 DictionaryValue* loc_dict = static_cast<DictionaryValue*>(value.get()); | |
| 1446 int x = 0, y = 0; | |
| 1447 if (!loc_dict->GetInteger("x", &x) || | |
| 1448 !loc_dict->GetInteger("y", &y)) { | |
| 1449 return new Error( | |
| 1450 kUnknownError, | |
| 1451 "Location atom returned bad coordinate dictionary: " + | |
| 1452 JsonStringify(loc_dict)); | |
| 1453 } | |
| 1454 gfx::Point temp_location = gfx::Point(x, y); | |
| 1455 | 1343 |
| 1456 if (verify_clickable_at_middle) { | 1344 if (verify_clickable_at_middle) { |
| 1457 gfx::Point middle_point = temp_location; | 1345 Point middle_point = temp_location; |
| 1458 middle_point.Offset(region.width() / 2, region.height() / 2); | 1346 middle_point.Offset(region.width() / 2, region.height() / 2); |
| 1459 error = VerifyElementIsClickable(frame_id, element, middle_point); | 1347 error = VerifyElementIsClickable(frame_id, element, middle_point); |
| 1460 if (error) | 1348 if (error) |
| 1461 return error; | 1349 return error; |
| 1462 } | 1350 } |
| 1463 *location = temp_location; | 1351 *location = temp_location; |
| 1464 return NULL; | 1352 return NULL; |
| 1465 } | 1353 } |
| 1466 | 1354 |
| 1467 Error* Session::GetScreenShot(std::string* png) { | 1355 Error* Session::GetScreenShot(std::string* png) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1480 path, | 1368 path, |
| 1481 &error)); | 1369 &error)); |
| 1482 if (error) | 1370 if (error) |
| 1483 return error; | 1371 return error; |
| 1484 if (!file_util::ReadFileToString(path, png)) | 1372 if (!file_util::ReadFileToString(path, png)) |
| 1485 return new Error(kUnknownError, "Could not read screenshot file"); | 1373 return new Error(kUnknownError, "Could not read screenshot file"); |
| 1486 return NULL; | 1374 return NULL; |
| 1487 } | 1375 } |
| 1488 | 1376 |
| 1489 Error* Session::GetBrowserConnectionState(bool* online) { | 1377 Error* Session::GetBrowserConnectionState(bool* online) { |
| 1490 std::string jscript = base::StringPrintf( | 1378 return ExecuteScriptAndParse( |
| 1491 "return (%s).apply(null, arguments);", atoms::IS_ONLINE); | 1379 current_target_, |
| 1492 base::ListValue no_args; | 1380 atoms::IS_ONLINE, |
| 1493 Value* unscoped_value = NULL; | 1381 "isOnline", |
| 1494 Error* error = ExecuteScript(jscript, | 1382 new ListValue(), |
| 1495 &no_args, | 1383 CreateDirectValueParser(online)); |
| 1496 &unscoped_value); | |
| 1497 scoped_ptr<base::Value> value(unscoped_value); | |
| 1498 if (error) | |
| 1499 return error; | |
| 1500 if (!value->GetAsBoolean(online)) | |
| 1501 return new Error(kUnknownError, | |
| 1502 "IS_ONLINE script returned non-boolean: " + | |
| 1503 JsonStringify(value.get())); | |
| 1504 return NULL; | |
| 1505 } | 1384 } |
| 1506 | 1385 |
| 1507 Error* Session::GetAppCacheStatus(int* status) { | 1386 Error* Session::GetAppCacheStatus(int* status) { |
| 1508 std::string jscript = base::StringPrintf( | 1387 return ExecuteScriptAndParse( |
| 1509 "return (%s).apply(null, arguments);", atoms::GET_APPCACHE_STATUS); | 1388 current_target_, |
| 1510 base::ListValue no_args; | 1389 atoms::GET_APPCACHE_STATUS, |
| 1511 Value* unscoped_value = NULL; | 1390 "getAppcacheStatus", |
| 1512 Error* error = ExecuteScript(jscript, | 1391 new ListValue(), |
| 1513 &no_args, | 1392 CreateDirectValueParser(status)); |
| 1514 &unscoped_value); | |
| 1515 scoped_ptr<base::Value> value(unscoped_value); | |
| 1516 if (error) | |
| 1517 return error; | |
| 1518 if (!value->GetAsInteger(status)) | |
| 1519 return new Error(kUnknownError, | |
| 1520 "GET_APPCACHE_STATUS script returned non-integer: " + | |
| 1521 JsonStringify(value.get())); | |
| 1522 return NULL; | |
| 1523 } | 1393 } |
| 1524 | 1394 |
| 1525 } // namespace webdriver | 1395 } // namespace webdriver |
| OLD | NEW |