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 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 &args_as_json); | 106 &args_as_json); |
109 | 107 |
110 // Every injected script is fed through the executeScript atom. This atom | 108 // Every injected script is fed through the executeScript atom. This atom |
111 // will catch any errors that are thrown and convert them to the | 109 // will catch any errors that are thrown and convert them to the |
112 // appropriate JSON structure. | 110 // appropriate JSON structure. |
113 std::string jscript = base::StringPrintf( | 111 std::string jscript = base::StringPrintf( |
114 "window.domAutomationController.send((%s).apply(null," | 112 "window.domAutomationController.send((%s).apply(null," |
115 "[function(){%s\n},%s,true]));", | 113 "[function(){%s\n},%s,true]));", |
116 atoms::EXECUTE_SCRIPT, script.c_str(), args_as_json.c_str()); | 114 atoms::EXECUTE_SCRIPT, script.c_str(), args_as_json.c_str()); |
117 | 115 |
118 return ExecuteScriptAndParseResponse(frame_id, jscript, value); | 116 return ExecuteScriptAndParseValue(frame_id, jscript, value); |
119 } | 117 } |
120 | 118 |
121 Error* Session::ExecuteScript(const std::string& script, | 119 Error* Session::ExecuteScript(const std::string& script, |
122 const ListValue* const args, | 120 const ListValue* const args, |
123 Value** value) { | 121 Value** value) { |
124 return ExecuteScript(current_target_, script, args, value); | 122 return ExecuteScript(current_target_, script, args, value); |
125 } | 123 } |
126 | 124 |
| 125 Error* Session::ExecuteScriptAndParse(const FrameId& frame_id, |
| 126 const std::string& anonymous_func_script, |
| 127 const std::string& script_name, |
| 128 const ListValue* args, |
| 129 const ValueParser* parser) { |
| 130 scoped_ptr<const ListValue> scoped_args(args); |
| 131 scoped_ptr<const ValueParser> scoped_parser(parser); |
| 132 std::string called_script = base::StringPrintf( |
| 133 "return (%s).apply(null, arguments);", anonymous_func_script.c_str()); |
| 134 Value* unscoped_value = NULL; |
| 135 Error* error = ExecuteScript(frame_id, called_script, args, &unscoped_value); |
| 136 if (error) { |
| 137 error->AddDetails(script_name + " execution failed"); |
| 138 return error; |
| 139 } |
| 140 |
| 141 scoped_ptr<Value> value(unscoped_value); |
| 142 std::string error_msg; |
| 143 if (!parser->Parse(value.get())) { |
| 144 error_msg = base::StringPrintf("%s returned invalid value: %s", |
| 145 script_name.c_str(), JsonStringify(value.get()).c_str()); |
| 146 return new Error(kUnknownError, error_msg); |
| 147 } |
| 148 return NULL; |
| 149 } |
| 150 |
127 Error* Session::ExecuteAsyncScript(const FrameId& frame_id, | 151 Error* Session::ExecuteAsyncScript(const FrameId& frame_id, |
128 const std::string& script, | 152 const std::string& script, |
129 const ListValue* const args, | 153 const ListValue* const args, |
130 Value** value) { | 154 Value** value) { |
131 std::string args_as_json; | 155 std::string args_as_json; |
132 base::JSONWriter::Write(static_cast<const Value* const>(args), | 156 base::JSONWriter::Write(static_cast<const Value* const>(args), |
133 /*pretty_print=*/false, | 157 /*pretty_print=*/false, |
134 &args_as_json); | 158 &args_as_json); |
135 | 159 |
136 int timeout_ms = async_script_timeout(); | 160 int timeout_ms = async_script_timeout(); |
137 | 161 |
138 // Every injected script is fed through the executeScript atom. This atom | 162 // Every injected script is fed through the executeScript atom. This atom |
139 // will catch any errors that are thrown and convert them to the | 163 // will catch any errors that are thrown and convert them to the |
140 // appropriate JSON structure. | 164 // appropriate JSON structure. |
141 std::string jscript = base::StringPrintf( | 165 std::string jscript = base::StringPrintf( |
142 "(%s).apply(null, [function(){%s},%s,%d,%s,true]);", | 166 "(%s).apply(null, [function(){%s},%s,%d,%s,true]);", |
143 atoms::EXECUTE_ASYNC_SCRIPT, | 167 atoms::EXECUTE_ASYNC_SCRIPT, |
144 script.c_str(), | 168 script.c_str(), |
145 args_as_json.c_str(), | 169 args_as_json.c_str(), |
146 timeout_ms, | 170 timeout_ms, |
147 "function(result) {window.domAutomationController.send(result);}"); | 171 "function(result) {window.domAutomationController.send(result);}"); |
148 | 172 |
149 return ExecuteScriptAndParseResponse(frame_id, jscript, value); | 173 return ExecuteScriptAndParseValue(frame_id, jscript, value); |
150 } | 174 } |
151 | 175 |
152 Error* Session::SendKeys(const WebElementId& element, const string16& keys) { | 176 Error* Session::SendKeys(const WebElementId& element, const string16& keys) { |
153 bool is_displayed = false; | 177 bool is_displayed = false; |
154 Error* error = IsElementDisplayed( | 178 Error* error = IsElementDisplayed( |
155 current_target_, element, true /* ignore_opacity */, &is_displayed); | 179 current_target_, element, true /* ignore_opacity */, &is_displayed); |
156 if (error) | 180 if (error) |
157 return error; | 181 return error; |
158 if (!is_displayed) | 182 if (!is_displayed) |
159 return new Error(kElementNotVisible); | 183 return new Error(kElementNotVisible); |
160 | 184 |
161 bool is_enabled = false; | 185 bool is_enabled = false; |
162 error = IsElementEnabled(current_target_, element, &is_enabled); | 186 error = IsElementEnabled(current_target_, element, &is_enabled); |
163 if (error) | 187 if (error) |
164 return error; | 188 return error; |
165 if (!is_enabled) | 189 if (!is_enabled) |
166 return new Error(kInvalidElementState); | 190 return new Error(kInvalidElementState); |
167 | 191 |
168 ListValue args; | |
169 args.Append(element.ToValue()); | |
170 // Focus the target element in order to send keys to it. | 192 // Focus the target element in order to send keys to it. |
171 // First, the currently active element is blurred, if it is different from | 193 // First, the currently active element is blurred, if it is different from |
172 // the target element. We do not want to blur an element unnecessarily, | 194 // the target element. We do not want to blur an element unnecessarily, |
173 // because this may cause us to lose the current cursor position in the | 195 // because this may cause us to lose the current cursor position in the |
174 // element. | 196 // element. |
175 // Secondly, we focus the target element. | 197 // Secondly, we focus the target element. |
176 // Thirdly, if the target element is newly focused and is a text input, we | 198 // Thirdly, if the target element is newly focused and is a text input, we |
177 // set the cursor position at the end. | 199 // set the cursor position at the end. |
178 // Fourthly, we check if the new active element is the target element. If not, | 200 // Fourthly, we check if the new active element is the target element. If not, |
179 // we throw an error. | 201 // we throw an error. |
180 // Additional notes: | 202 // Additional notes: |
181 // - |document.activeElement| is the currently focused element, or body if | 203 // - |document.activeElement| is the currently focused element, or body if |
182 // no element is focused | 204 // no element is focused |
183 // - Even if |document.hasFocus()| returns true and the active element is | 205 // - Even if |document.hasFocus()| returns true and the active element is |
184 // the body, sometimes we still need to focus the body element for send | 206 // the body, sometimes we still need to focus the body element for send |
185 // keys to work. Not sure why | 207 // keys to work. Not sure why |
186 // - You cannot focus a descendant of a content editable node | 208 // - You cannot focus a descendant of a content editable node |
187 // TODO(jleyba): Update this to use the correct atom. | 209 // TODO(jleyba): Update this to use the correct atom. |
188 const char* kFocusScript = | 210 const char* kFocusScript = |
189 "var elem = arguments[0];" | 211 "function(elem) {" |
190 "var doc = elem.ownerDocument || elem;" | 212 " var doc = elem.ownerDocument || elem;" |
191 "var prevActiveElem = doc.activeElement;" | 213 " var prevActiveElem = doc.activeElement;" |
192 "if (elem != prevActiveElem && prevActiveElem)" | 214 " if (elem != prevActiveElem && prevActiveElem)" |
193 " prevActiveElem.blur();" | 215 " prevActiveElem.blur();" |
194 "elem.focus();" | 216 " elem.focus();" |
195 "if (elem != prevActiveElem && elem.value && elem.value.length &&" | 217 " if (elem != prevActiveElem && elem.value && elem.value.length &&" |
196 " elem.setSelectionRange) {" | 218 " elem.setSelectionRange) {" |
197 " elem.setSelectionRange(elem.value.length, elem.value.length);" | 219 " elem.setSelectionRange(elem.value.length, elem.value.length);" |
198 "}" | 220 " }" |
199 "if (elem != doc.activeElement)" | 221 " if (elem != doc.activeElement)" |
200 " throw new Error('Failed to send keys because cannot focus element.');"; | 222 " throw new Error('Failed to send keys because cannot focus element');" |
201 Value* unscoped_result = NULL; | 223 "}"; |
202 error = ExecuteScript(kFocusScript, &args, &unscoped_result); | 224 error = ExecuteScriptAndParse(current_target_, |
| 225 kFocusScript, |
| 226 "focusElement", |
| 227 CreateListValueFrom(element), |
| 228 CreateDirectValueParser(kSkipParsing)); |
203 if (error) | 229 if (error) |
204 return error; | 230 return error; |
205 | 231 |
206 error = NULL; | |
207 RunSessionTask(NewRunnableMethod( | 232 RunSessionTask(NewRunnableMethod( |
208 this, | 233 this, |
209 &Session::SendKeysOnSessionThread, | 234 &Session::SendKeysOnSessionThread, |
210 keys, | 235 keys, |
211 &error)); | 236 &error)); |
212 return error; | 237 return error; |
213 } | 238 } |
214 | 239 |
215 Error* Session::DragAndDropFilePaths( | 240 Error* Session::DragAndDropFilePaths( |
216 const gfx::Point& location, | 241 const Point& location, |
217 const std::vector<FilePath::StringType>& paths) { | 242 const std::vector<FilePath::StringType>& paths) { |
218 Error* error = NULL; | 243 Error* error = NULL; |
219 RunSessionTask(NewRunnableMethod( | 244 RunSessionTask(NewRunnableMethod( |
220 automation_.get(), | 245 automation_.get(), |
221 &Automation::DragAndDropFilePaths, | 246 &Automation::DragAndDropFilePaths, |
222 current_target_.window_id, | 247 current_target_.window_id, |
223 location, | 248 location, |
224 paths, | 249 paths, |
225 &error)); | 250 &error)); |
226 return error; | 251 return error; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 Error* error = NULL; | 286 Error* error = NULL; |
262 RunSessionTask(NewRunnableMethod( | 287 RunSessionTask(NewRunnableMethod( |
263 automation_.get(), | 288 automation_.get(), |
264 &Automation::Reload, | 289 &Automation::Reload, |
265 current_target_.window_id, | 290 current_target_.window_id, |
266 &error)); | 291 &error)); |
267 return error; | 292 return error; |
268 } | 293 } |
269 | 294 |
270 Error* Session::GetURL(std::string* url) { | 295 Error* Session::GetURL(std::string* url) { |
271 ListValue no_args; | 296 return ExecuteScriptAndParse(current_target_, |
272 Value* unscoped_value = NULL; | 297 "function() { return document.URL }", |
273 Error* error = ExecuteScript(current_target_, | 298 "getUrl", |
274 "return document.URL;", | 299 new ListValue(), |
275 &no_args, | 300 CreateDirectValueParser(url)); |
276 &unscoped_value); | |
277 scoped_ptr<Value> value(unscoped_value); | |
278 if (error) | |
279 return error; | |
280 if (!value->GetAsString(url)) | |
281 return new Error(kUnknownError, "GetURL Script returned non-string: " + | |
282 JsonStringify(value.get())); | |
283 return NULL; | |
284 } | 301 } |
285 | 302 |
286 Error* Session::GetTitle(std::string* tab_title) { | 303 Error* Session::GetTitle(std::string* tab_title) { |
287 std::string script = | 304 const char* kGetTitleScript = |
288 "if (document.title)" | 305 "function() {" |
289 " return document.title;" | 306 " if (document.title)" |
290 "else" | 307 " return document.title;" |
291 " return document.URL;"; | 308 " else" |
292 | 309 " return document.URL;" |
293 ListValue no_args; | 310 "}"; |
294 Value* unscoped_value = NULL; | 311 return ExecuteScriptAndParse(current_target_, |
295 Error* error = ExecuteScript(current_target_, | 312 kGetTitleScript, |
296 script, | 313 "getTitle", |
297 &no_args, | 314 new ListValue(), |
298 &unscoped_value); | 315 CreateDirectValueParser(tab_title)); |
299 scoped_ptr<Value> value(unscoped_value); | |
300 if (error) | |
301 return error; | |
302 if (!value->GetAsString(tab_title)) | |
303 return new Error(kUnknownError, "GetTitle script returned non-string: " + | |
304 JsonStringify(value.get())); | |
305 return NULL; | |
306 } | 316 } |
307 | 317 |
308 Error* Session::MouseMoveAndClick(const gfx::Point& location, | 318 Error* Session::MouseMoveAndClick(const Point& location, |
309 automation::MouseButton button) { | 319 automation::MouseButton button) { |
310 Error* error = NULL; | 320 Error* error = NULL; |
311 RunSessionTask(NewRunnableMethod( | 321 RunSessionTask(NewRunnableMethod( |
312 automation_.get(), | 322 automation_.get(), |
313 &Automation::MouseClick, | 323 &Automation::MouseClick, |
314 current_target_.window_id, | 324 current_target_.window_id, |
315 location, | 325 location, |
316 button, | 326 button, |
317 &error)); | 327 &error)); |
318 if (!error) | 328 if (!error) |
319 mouse_position_ = location; | 329 mouse_position_ = location; |
320 return error; | 330 return error; |
321 } | 331 } |
322 | 332 |
323 Error* Session::MouseMove(const gfx::Point& location) { | 333 Error* Session::MouseMove(const Point& location) { |
324 Error* error = NULL; | 334 Error* error = NULL; |
325 RunSessionTask(NewRunnableMethod( | 335 RunSessionTask(NewRunnableMethod( |
326 automation_.get(), | 336 automation_.get(), |
327 &Automation::MouseMove, | 337 &Automation::MouseMove, |
328 current_target_.window_id, | 338 current_target_.window_id, |
329 location, | 339 location, |
330 &error)); | 340 &error)); |
331 if (!error) | 341 if (!error) |
332 mouse_position_ = location; | 342 mouse_position_ = location; |
333 return error; | 343 return error; |
334 } | 344 } |
335 | 345 |
336 Error* Session::MouseDrag(const gfx::Point& start, | 346 Error* Session::MouseDrag(const Point& start, |
337 const gfx::Point& end) { | 347 const Point& end) { |
338 Error* error = NULL; | 348 Error* error = NULL; |
339 RunSessionTask(NewRunnableMethod( | 349 RunSessionTask(NewRunnableMethod( |
340 automation_.get(), | 350 automation_.get(), |
341 &Automation::MouseDrag, | 351 &Automation::MouseDrag, |
342 current_target_.window_id, | 352 current_target_.window_id, |
343 start, | 353 start, |
344 end, | 354 end, |
345 &error)); | 355 &error)); |
346 if (!error) | 356 if (!error) |
347 mouse_position_ = end; | 357 mouse_position_ = end; |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
448 switch_to_id = name_no; | 458 switch_to_id = name_no; |
449 } | 459 } |
450 | 460 |
451 if (!switch_to_id) { | 461 if (!switch_to_id) { |
452 std::vector<int> window_ids; | 462 std::vector<int> window_ids; |
453 Error* error = GetWindowIds(&window_ids); | 463 Error* error = GetWindowIds(&window_ids); |
454 if (error) | 464 if (error) |
455 return error; | 465 return error; |
456 // See if any of the window names match |name|. | 466 // See if any of the window names match |name|. |
457 for (size_t i = 0; i < window_ids.size(); ++i) { | 467 for (size_t i = 0; i < window_ids.size(); ++i) { |
458 ListValue empty_list; | |
459 Value* unscoped_name_value = NULL; | |
460 std::string window_name; | 468 std::string window_name; |
461 Error* error = ExecuteScript(FrameId(window_ids[i], FramePath()), | 469 Error* error = ExecuteScriptAndParse( |
462 "return window.name;", | 470 FrameId(window_ids[i], FramePath()), |
463 &empty_list, | 471 "function() { return window.name; }", |
464 &unscoped_name_value); | 472 "getWindowName", |
| 473 new ListValue(), |
| 474 CreateDirectValueParser(&window_name)); |
465 if (error) | 475 if (error) |
466 return error; | 476 return error; |
467 scoped_ptr<Value> name_value(unscoped_name_value); | 477 if (name == window_name) { |
468 if (name_value->GetAsString(&window_name) && | |
469 name == window_name) { | |
470 switch_to_id = window_ids[i]; | 478 switch_to_id = window_ids[i]; |
471 break; | 479 break; |
472 } | 480 } |
473 } | 481 } |
474 } | 482 } |
475 | 483 |
476 if (!switch_to_id) | 484 if (!switch_to_id) |
477 return new Error(kNoSuchWindow); | 485 return new Error(kNoSuchWindow); |
478 frame_elements_.clear(); | 486 frame_elements_.clear(); |
479 current_target_ = FrameId(switch_to_id, FramePath()); | 487 current_target_ = FrameId(switch_to_id, FramePath()); |
480 return NULL; | 488 return NULL; |
481 } | 489 } |
482 | 490 |
483 Error* Session::SwitchToFrameWithNameOrId(const std::string& name_or_id) { | 491 Error* Session::SwitchToFrameWithNameOrId(const std::string& name_or_id) { |
484 std::string script = | 492 std::string script = |
485 "var arg = arguments[0];" | 493 "function(arg) {" |
486 "var xpath = '(/html/body//iframe|/html/frameset/frame)';" | 494 " var xpath = '(/html/body//iframe|/html/frameset/frame)';" |
487 "var sub = function(s) { return s.replace(/\\$/g, arg); };" | 495 " var sub = function(s) { return s.replace(/\\$/g, arg); };" |
488 "xpath += sub('[@name=\"$\" or @id=\"$\"]');" | 496 " xpath += sub('[@name=\"$\" or @id=\"$\"]');" |
489 "var frame = document.evaluate(xpath, document, null, " | 497 " var frame = document.evaluate(xpath, document, null, " |
490 " XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;" | 498 " XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;" |
491 "if (!frame) { return null; }" | 499 " if (!frame) { return null; }" |
492 "xpath = frame.tagName == 'IFRAME' ? '/html/body//iframe'" | 500 " xpath = frame.tagName == 'IFRAME' ? '/html/body//iframe'" |
493 " : '/html/frameset/frame';" | 501 " : '/html/frameset/frame';" |
494 "frame_xpath = xpath + " | 502 " frame_xpath = xpath + " |
495 " sub('[@' + (frame.id == arg ? 'id' : 'name') + '=\"$\"]');" | 503 " sub('[@' + (frame.id == arg ? 'id' : 'name') + '=\"$\"]');" |
496 "return [frame, frame_xpath];"; | 504 " return [frame, frame_xpath];" |
497 ListValue args; | 505 "}"; |
498 args.Append(new StringValue(name_or_id)); | 506 return SwitchToFrameWithJavaScriptLocatedFrame( |
499 return SwitchToFrameWithJavaScriptLocatedFrame(script, &args); | 507 script, CreateListValueFrom(name_or_id)); |
500 } | 508 } |
501 | 509 |
502 Error* Session::SwitchToFrameWithIndex(int index) { | 510 Error* Session::SwitchToFrameWithIndex(int index) { |
503 // We cannot simply index into window.frames because we need to know the | 511 // We cannot simply index into window.frames because we need to know the |
504 // tagName of the frameElement. If child frame N is from another domain, then | 512 // tagName of the frameElement. If child frame N is from another domain, then |
505 // the following will run afoul of the same origin policy: | 513 // the following will run afoul of the same origin policy: |
506 // window.frames[N].frameElement; | 514 // window.frames[N].frameElement; |
507 // Instead of indexing window.frames, we use a an XPath expression to index | 515 // Instead of indexing window.frames, we use a an XPath expression to index |
508 // into the list of all IFRAME and FRAME elements on the page - if we find | 516 // into the list of all IFRAME and FRAME elements on the page - if we find |
509 // something, then that XPath expression can be used as the new frame's XPath. | 517 // something, then that XPath expression can be used as the new frame's XPath. |
510 std::string script = | 518 std::string script = |
511 "var index = '[' + (arguments[0] + 1) + ']';" | 519 "function(index) {" |
512 "var xpath = '(/html/body//iframe|/html/frameset/frame)' + " | 520 " var xpathIndex = '[' + (index + 1) + ']';" |
513 " index;" | 521 " var xpath = '(/html/body//iframe|/html/frameset/frame)' + " |
514 "console.info('searching for frame by xpath: ' + xpath);" | 522 " xpathIndex;" |
515 "var frame = document.evaluate(xpath, document, null, " | 523 " var frame = document.evaluate(xpath, document, null, " |
516 "XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;" | 524 " XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;" |
517 "console.info(frame == null ? 'found nothing' : frame);" | 525 " if (!frame) { return null; }" |
518 "if (!frame) { return null; }" | 526 " frame_xpath = ((frame.tagName == 'IFRAME' ? " |
519 "frame_xpath = ((frame.tagName == 'IFRAME' ? " | 527 " '(/html/body//iframe)' : '/html/frameset/frame') + xpathIndex);" |
520 " '(/html/body//iframe)' : '/html/frameset/frame') + index);" | 528 " return [frame, frame_xpath];" |
521 "return [frame, frame_xpath];"; | 529 "}"; |
522 ListValue args; | 530 return SwitchToFrameWithJavaScriptLocatedFrame( |
523 args.Append(Value::CreateIntegerValue(index)); | 531 script, CreateListValueFrom(index)); |
524 return SwitchToFrameWithJavaScriptLocatedFrame(script, &args); | |
525 } | 532 } |
526 | 533 |
527 Error* Session::SwitchToFrameWithElement(const WebElementId& element) { | 534 Error* Session::SwitchToFrameWithElement(const WebElementId& element) { |
528 // TODO(jleyba): Extract this, and the other frame switch methods to an atom. | 535 // TODO(jleyba): Extract this, and the other frame switch methods to an atom. |
529 std::string script = | 536 std::string script = |
530 "var element = arguments[0];" | 537 "function(elem) {" |
531 "console.info('Attempting to switch to ' + element);" | 538 " if (elem.nodeType != 1 || !/^i?frame$/i.test(elem.tagName)) {" |
532 "if (element.nodeType != 1 || !/^i?frame$/i.test(element.tagName)) {" | 539 " console.error('Element is not a frame');" |
533 " console.info('Element is not a frame: ' + element + " | 540 " return null;" |
534 "' {nodeType:' + element.nodeType + ',tagName:' + element.tagName + '}');" | 541 " }" |
| 542 " for (var i = 0; i < window.frames.length; i++) {" |
| 543 " if (elem.contentWindow == window.frames[i]) {" |
| 544 " return [elem, '(//iframe|//frame)[' + (i + 1) + ']'];" |
| 545 " }" |
| 546 " }" |
| 547 " console.info('Frame is not connected to this DOM tree');" |
535 " return null;" | 548 " return null;" |
536 "}" | 549 "}"; |
537 "for (var i = 0; i < window.frames.length; i++) {" | 550 return SwitchToFrameWithJavaScriptLocatedFrame( |
538 " if (element.contentWindow == window.frames[i]) {" | 551 script, CreateListValueFrom(element)); |
539 " return [element, '(//iframe|//frame)[' + (i + 1) + ']'];" | |
540 " }" | |
541 "}" | |
542 "console.info('Frame is not connected to this DOM tree');" | |
543 "return null;"; | |
544 | |
545 ListValue args; | |
546 args.Append(element.ToValue()); | |
547 return SwitchToFrameWithJavaScriptLocatedFrame(script, &args); | |
548 } | 552 } |
549 | 553 |
550 void Session::SwitchToTopFrame() { | 554 void Session::SwitchToTopFrame() { |
551 frame_elements_.clear(); | 555 frame_elements_.clear(); |
552 current_target_.frame_path = FramePath(); | 556 current_target_.frame_path = FramePath(); |
553 } | 557 } |
554 | 558 |
555 Error* Session::SwitchToTopFrameIfCurrentFrameInvalid() { | 559 Error* Session::SwitchToTopFrameIfCurrentFrameInvalid() { |
556 std::vector<std::string> components; | 560 std::vector<std::string> components; |
557 current_target_.frame_path.GetComponents(&components); | 561 current_target_.frame_path.GetComponents(&components); |
558 if (frame_elements_.size() != components.size()) { | 562 if (frame_elements_.size() != components.size()) { |
559 return new Error(kUnknownError, | 563 return new Error(kUnknownError, |
560 "Frame element vector out of sync with frame path"); | 564 "Frame element vector out of sync with frame path"); |
561 } | 565 } |
562 FramePath frame_path; | 566 FramePath frame_path; |
563 // Start from the root path and check that each frame element that makes | 567 // Start from the root path and check that each frame element that makes |
564 // up the current frame target is valid by executing an empty script. | 568 // up the current frame target is valid by executing an empty script. |
565 // This code should not execute script in any frame before making sure the | 569 // This code should not execute script in any frame before making sure the |
566 // frame element is valid, otherwise the automation hangs until a timeout. | 570 // frame element is valid, otherwise the automation hangs until a timeout. |
567 for (size_t i = 0; i < frame_elements_.size(); ++i) { | 571 for (size_t i = 0; i < frame_elements_.size(); ++i) { |
568 FrameId frame_id(current_target_.window_id, frame_path); | 572 FrameId frame_id(current_target_.window_id, frame_path); |
569 ListValue args; | 573 scoped_ptr<Error> error(ExecuteScriptAndParse( |
570 args.Append(frame_elements_[i].ToValue()); | 574 frame_id, |
571 Value* unscoped_value = NULL; | 575 "function(){ }", |
572 scoped_ptr<Error> error(ExecuteScript( | 576 "emptyScript", |
573 frame_id, "", &args, &unscoped_value)); | 577 CreateListValueFrom(frame_elements_[i]), |
574 | 578 CreateDirectValueParser(kSkipParsing))); |
575 scoped_ptr<Value> value(unscoped_value); | |
576 if (error.get() && error->code() == kStaleElementReference) { | 579 if (error.get() && error->code() == kStaleElementReference) { |
577 SwitchToTopFrame(); | 580 SwitchToTopFrame(); |
578 } else if (error.get()) { | 581 } else if (error.get()) { |
579 return error.release(); | 582 return error.release(); |
580 } | 583 } |
581 frame_path = frame_path.Append(components[i]); | 584 frame_path = frame_path.Append(components[i]); |
582 } | 585 } |
583 return NULL; | 586 return NULL; |
584 } | 587 } |
585 | 588 |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
698 const WebElementId& root_element, | 701 const WebElementId& root_element, |
699 const std::string& locator, | 702 const std::string& locator, |
700 const std::string& query, | 703 const std::string& query, |
701 std::vector<WebElementId>* elements) { | 704 std::vector<WebElementId>* elements) { |
702 return FindElementsHelper( | 705 return FindElementsHelper( |
703 frame_id, root_element, locator, query, false, elements); | 706 frame_id, root_element, locator, query, false, elements); |
704 } | 707 } |
705 | 708 |
706 Error* Session::GetElementLocationInView( | 709 Error* Session::GetElementLocationInView( |
707 const WebElementId& element, | 710 const WebElementId& element, |
708 gfx::Point* location) { | 711 Point* location) { |
709 gfx::Size size; | 712 Size size; |
710 Error* error = GetElementSize(current_target_, element, &size); | 713 Error* error = GetElementSize(current_target_, element, &size); |
711 if (error) | 714 if (error) |
712 return error; | 715 return error; |
713 return GetElementRegionInView( | 716 return GetElementRegionInView( |
714 element, gfx::Rect(gfx::Point(0, 0), size), | 717 element, Rect(Point(0, 0), size), false /* center */, location); |
715 false /* center */, location); | |
716 } | 718 } |
717 | 719 |
718 Error* Session::GetElementRegionInView( | 720 Error* Session::GetElementRegionInView( |
719 const WebElementId& element, | 721 const WebElementId& element, |
720 const gfx::Rect& region, | 722 const Rect& region, |
721 bool center, | 723 bool center, |
722 gfx::Point* location) { | 724 Point* location) { |
723 CHECK(element.is_valid()); | 725 CHECK(element.is_valid()); |
724 | 726 |
725 gfx::Point region_offset = region.origin(); | 727 Point region_offset = region.origin(); |
726 gfx::Size region_size = region.size(); | 728 Size region_size = region.size(); |
727 Error* error = GetElementRegionInViewHelper( | 729 Error* error = GetElementRegionInViewHelper( |
728 current_target_, element, region, center, ®ion_offset); | 730 current_target_, element, region, center, ®ion_offset); |
729 if (error) | 731 if (error) |
730 return error; | 732 return error; |
731 | 733 |
732 for (FramePath frame_path = current_target_.frame_path; | 734 for (FramePath frame_path = current_target_.frame_path; |
733 frame_path.IsSubframe(); | 735 frame_path.IsSubframe(); |
734 frame_path = frame_path.Parent()) { | 736 frame_path = frame_path.Parent()) { |
735 // Find the frame element for the current frame path. | 737 // Find the frame element for the current frame path. |
736 FrameId frame_id(current_target_.window_id, frame_path.Parent()); | 738 FrameId frame_id(current_target_.window_id, frame_path.Parent()); |
(...skipping 11 matching lines...) Expand all Loading... |
748 } | 750 } |
749 // Modify |region_offset| by the frame's border. | 751 // Modify |region_offset| by the frame's border. |
750 int border_left, border_top; | 752 int border_left, border_top; |
751 error = GetElementBorder( | 753 error = GetElementBorder( |
752 frame_id, frame_element, &border_left, &border_top); | 754 frame_id, frame_element, &border_left, &border_top); |
753 if (error) | 755 if (error) |
754 return error; | 756 return error; |
755 region_offset.Offset(border_left, border_top); | 757 region_offset.Offset(border_left, border_top); |
756 | 758 |
757 error = GetElementRegionInViewHelper( | 759 error = GetElementRegionInViewHelper( |
758 frame_id, frame_element, gfx::Rect(region_offset, region_size), | 760 frame_id, frame_element, Rect(region_offset, region_size), |
759 center, ®ion_offset); | 761 center, ®ion_offset); |
760 if (error) | 762 if (error) |
761 return error; | 763 return error; |
762 } | 764 } |
763 *location = region_offset; | 765 *location = region_offset; |
764 return NULL; | 766 return NULL; |
765 } | 767 } |
766 | 768 |
767 Error* Session::GetElementSize(const FrameId& frame_id, | 769 Error* Session::GetElementSize(const FrameId& frame_id, |
768 const WebElementId& element, | 770 const WebElementId& element, |
769 gfx::Size* size) { | 771 Size* size) { |
770 std::string script = base::StringPrintf( | 772 return ExecuteScriptAndParse(frame_id, |
771 "return (%s).apply(null, arguments);", atoms::GET_SIZE); | 773 atoms::GET_SIZE, |
772 ListValue args; | 774 "getSize", |
773 args.Append(element.ToValue()); | 775 CreateListValueFrom(element), |
774 | 776 CreateDirectValueParser(size)); |
775 Value* unscoped_result = NULL; | |
776 Error* error = ExecuteScript(frame_id, script, &args, &unscoped_result); | |
777 scoped_ptr<Value> result(unscoped_result); | |
778 if (error) | |
779 return error; | |
780 if (!result->IsType(Value::TYPE_DICTIONARY)) { | |
781 return new Error(kUnknownError, "GetSize atom returned non-dict type: " + | |
782 JsonStringify(result.get())); | |
783 } | |
784 DictionaryValue* dict = static_cast<DictionaryValue*>(result.get()); | |
785 int width, height; | |
786 if (!dict->GetInteger("width", &width) || | |
787 !dict->GetInteger("height", &height)) { | |
788 return new Error(kUnknownError, "GetSize atom returned invalid dict: " + | |
789 JsonStringify(dict)); | |
790 } | |
791 *size = gfx::Size(width, height); | |
792 return NULL; | |
793 } | 777 } |
794 | 778 |
795 Error* Session::GetElementFirstClientRect(const FrameId& frame_id, | 779 Error* Session::GetElementFirstClientRect(const FrameId& frame_id, |
796 const WebElementId& element, | 780 const WebElementId& element, |
797 gfx::Rect* rect) { | 781 Rect* rect) { |
798 std::string script = base::StringPrintf( | 782 return ExecuteScriptAndParse(frame_id, |
799 "return (%s).apply(null, arguments);", atoms::GET_FIRST_CLIENT_RECT); | 783 atoms::GET_FIRST_CLIENT_RECT, |
800 ListValue args; | 784 "getFirstClientRect", |
801 args.Append(element.ToValue()); | 785 CreateListValueFrom(element), |
802 | 786 CreateDirectValueParser(rect)); |
803 Value* unscoped_result = NULL; | |
804 Error* error = ExecuteScript(frame_id, script, &args, &unscoped_result); | |
805 scoped_ptr<Value> result(unscoped_result); | |
806 if (error) | |
807 return error; | |
808 if (!result->IsType(Value::TYPE_DICTIONARY)) { | |
809 return new Error( | |
810 kUnknownError, | |
811 "GetFirstClientRect atom returned non-dict type: " + | |
812 JsonStringify(result.get())); | |
813 } | |
814 DictionaryValue* dict = static_cast<DictionaryValue*>(result.get()); | |
815 // TODO(kkania): Convert the atom to return integers. | |
816 double left, top, width, height; | |
817 if (!dict->GetDouble("left", &left) || | |
818 !dict->GetDouble("top", &top) || | |
819 !dict->GetDouble("width", &width) || | |
820 !dict->GetDouble("height", &height)) { | |
821 return new Error( | |
822 kUnknownError, | |
823 "GetFirstClientRect atom returned invalid dict: " + | |
824 JsonStringify(dict)); | |
825 } | |
826 *rect = gfx::Rect(static_cast<int>(left), static_cast<int>(top), | |
827 static_cast<int>(width), static_cast<int>(height)); | |
828 return NULL; | |
829 } | 787 } |
830 | 788 |
831 Error* Session::GetElementEffectiveStyle( | 789 Error* Session::GetElementEffectiveStyle( |
832 const FrameId& frame_id, | 790 const FrameId& frame_id, |
833 const WebElementId& element, | 791 const WebElementId& element, |
834 const std::string& prop, | 792 const std::string& prop, |
835 std::string* value) { | 793 std::string* value) { |
836 std::string script = base::StringPrintf( | 794 return ExecuteScriptAndParse(frame_id, |
837 "return (%s).apply(null, arguments);", atoms::GET_EFFECTIVE_STYLE); | 795 atoms::GET_EFFECTIVE_STYLE, |
838 ListValue args; | 796 "getEffectiveStyle", |
839 args.Append(element.ToValue()); | 797 CreateListValueFrom(element, prop), |
840 args.Append(Value::CreateStringValue(prop)); | 798 CreateDirectValueParser(value)); |
841 Value* unscoped_result = NULL; | |
842 Error* error = ExecuteScript( | |
843 frame_id, script, &args, &unscoped_result); | |
844 scoped_ptr<Value> result(unscoped_result); | |
845 if (error) { | |
846 error->AddDetails(base::StringPrintf( | |
847 "GetEffectiveStyle atom failed for property (%s)", prop.c_str())); | |
848 return error; | |
849 } | |
850 | |
851 if (!result->GetAsString(value)) { | |
852 std::string context = base::StringPrintf( | |
853 "GetEffectiveStyle atom returned non-string for property (%s): %s", | |
854 prop.c_str(), JsonStringify(result.get()).c_str()); | |
855 return new Error(kUnknownError, context); | |
856 } | |
857 return NULL; | |
858 } | 799 } |
859 | 800 |
860 Error* Session::GetElementBorder(const FrameId& frame_id, | 801 Error* Session::GetElementBorder(const FrameId& frame_id, |
861 const WebElementId& element, | 802 const WebElementId& element, |
862 int* border_left, | 803 int* border_left, |
863 int* border_top) { | 804 int* border_top) { |
864 std::string border_left_str, border_top_str; | 805 std::string border_left_str, border_top_str; |
865 Error* error = GetElementEffectiveStyle( | 806 Error* error = GetElementEffectiveStyle( |
866 frame_id, element, "border-left-width", &border_left_str); | 807 frame_id, element, "border-left-width", &border_left_str); |
867 if (error) | 808 if (error) |
868 return error; | 809 return error; |
869 error = GetElementEffectiveStyle( | 810 error = GetElementEffectiveStyle( |
870 frame_id, element, "border-top-width", &border_top_str); | 811 frame_id, element, "border-top-width", &border_top_str); |
871 if (error) | 812 if (error) |
872 return error; | 813 return error; |
873 | 814 |
874 base::StringToInt(border_left_str, border_left); | 815 base::StringToInt(border_left_str, border_left); |
875 base::StringToInt(border_top_str, border_top); | 816 base::StringToInt(border_top_str, border_top); |
876 return NULL; | 817 return NULL; |
877 } | 818 } |
878 | 819 |
879 Error* Session::IsElementDisplayed(const FrameId& frame_id, | 820 Error* Session::IsElementDisplayed(const FrameId& frame_id, |
880 const WebElementId& element, | 821 const WebElementId& element, |
881 bool ignore_opacity, | 822 bool ignore_opacity, |
882 bool* is_displayed) { | 823 bool* is_displayed) { |
883 std::string script = base::StringPrintf( | 824 return ExecuteScriptAndParse(frame_id, |
884 "return (%s).apply(null, arguments);", atoms::IS_DISPLAYED); | 825 atoms::IS_DISPLAYED, |
885 ListValue args; | 826 "isDisplayed", |
886 args.Append(element.ToValue()); | 827 CreateListValueFrom(element, ignore_opacity), |
887 args.Append(Value::CreateBooleanValue(ignore_opacity)); | 828 CreateDirectValueParser(is_displayed)); |
888 | |
889 Value* unscoped_result = NULL; | |
890 Error* error = ExecuteScript(frame_id, script, &args, &unscoped_result); | |
891 scoped_ptr<Value> result(unscoped_result); | |
892 if (error) | |
893 return error; | |
894 if (!result->GetAsBoolean(is_displayed)) | |
895 return new Error(kUnknownError, "IsDisplayed atom returned non-boolean: " + | |
896 JsonStringify(result.get())); | |
897 return NULL; | |
898 } | 829 } |
899 | 830 |
900 Error* Session::IsElementEnabled(const FrameId& frame_id, | 831 Error* Session::IsElementEnabled(const FrameId& frame_id, |
901 const WebElementId& element, | 832 const WebElementId& element, |
902 bool* is_enabled) { | 833 bool* is_enabled) { |
903 std::string script = base::StringPrintf( | 834 return ExecuteScriptAndParse(frame_id, |
904 "return (%s).apply(null, arguments);", atoms::IS_ENABLED); | 835 atoms::IS_ENABLED, |
905 ListValue args; | 836 "isEnabled", |
906 args.Append(element.ToValue()); | 837 CreateListValueFrom(element), |
907 | 838 CreateDirectValueParser(is_enabled)); |
908 Value* unscoped_result = NULL; | |
909 Error* error = ExecuteScript(frame_id, script, &args, &unscoped_result); | |
910 scoped_ptr<Value> result(unscoped_result); | |
911 if (error) | |
912 return error; | |
913 if (!result->GetAsBoolean(is_enabled)) | |
914 return new Error(kUnknownError, "IsEnabled atom returned non-boolean: " + | |
915 JsonStringify(result.get())); | |
916 return NULL; | |
917 } | 839 } |
918 | 840 |
919 Error* Session::SelectOptionElement(const FrameId& frame_id, | 841 Error* Session::SelectOptionElement(const FrameId& frame_id, |
920 const WebElementId& element) { | 842 const WebElementId& element) { |
921 ListValue args; | 843 return ExecuteScriptAndParse(frame_id, |
922 args.Append(element.ToValue()); | 844 atoms::SET_SELECTED, |
923 args.Append(Value::CreateBooleanValue(true)); | 845 "setSelected", |
924 | 846 CreateListValueFrom(element, true), |
925 std::string script = base::StringPrintf( | 847 CreateDirectValueParser(kSkipParsing)); |
926 "return (%s).apply(null, arguments);", atoms::SET_SELECTED); | |
927 | |
928 Value* unscoped_result = NULL; | |
929 Error* error = ExecuteScript(frame_id, script, &args, &unscoped_result); | |
930 scoped_ptr<Value> result(unscoped_result); | |
931 return error; | |
932 } | 848 } |
933 | 849 |
934 Error* Session::GetElementTagName(const FrameId& frame_id, | 850 Error* Session::GetElementTagName(const FrameId& frame_id, |
935 const WebElementId& element, | 851 const WebElementId& element, |
936 std::string* tag_name) { | 852 std::string* tag_name) { |
937 ListValue args; | 853 return ExecuteScriptAndParse( |
938 args.Append(element.ToValue()); | 854 frame_id, |
939 | 855 "function(elem) { return elem.tagName.toLowerCase() }", |
940 std::string script = "return arguments[0].tagName.toLocaleLowerCase();"; | 856 "getElementTagName", |
941 | 857 CreateListValueFrom(element), |
942 Value* unscoped_result = NULL; | 858 CreateDirectValueParser(tag_name)); |
943 Error* error = ExecuteScript(frame_id, script, &args, &unscoped_result); | |
944 scoped_ptr<Value> result(unscoped_result); | |
945 if (error) | |
946 return error; | |
947 if (!result->GetAsString(tag_name)) | |
948 return new Error(kUnknownError, "TagName script returned non-string: " + | |
949 JsonStringify(result.get())); | |
950 return NULL; | |
951 } | 859 } |
952 | 860 |
953 Error* Session::GetClickableLocation(const WebElementId& element, | 861 Error* Session::GetClickableLocation(const WebElementId& element, |
954 gfx::Point* location) { | 862 Point* location) { |
955 bool is_displayed = false; | 863 bool is_displayed = false; |
956 Error* error = IsElementDisplayed( | 864 Error* error = IsElementDisplayed( |
957 current_target_, element, true /* ignore_opacity */, &is_displayed); | 865 current_target_, element, true /* ignore_opacity */, &is_displayed); |
958 if (error) | 866 if (error) |
959 return error; | 867 return error; |
960 if (!is_displayed) | 868 if (!is_displayed) |
961 return new Error(kElementNotVisible, "Element must be displayed to click"); | 869 return new Error(kElementNotVisible, "Element must be displayed to click"); |
962 | 870 |
963 gfx::Rect rect; | 871 Rect rect; |
964 error = GetElementFirstClientRect(current_target_, element, &rect); | 872 error = GetElementFirstClientRect(current_target_, element, &rect); |
965 if (error) | 873 if (error) |
966 return error; | 874 return error; |
967 | 875 |
968 error = GetElementRegionInView(element, rect, true /* center */, location); | 876 error = GetElementRegionInView( |
| 877 element, rect, true /* center */, location); |
969 if (error) | 878 if (error) |
970 return error; | 879 return error; |
971 location->Offset(rect.width() / 2, rect.height() / 2); | 880 location->Offset(rect.width() / 2, rect.height() / 2); |
972 return NULL; | 881 return NULL; |
973 } | 882 } |
974 | 883 |
975 Error* Session::GetAttribute(const WebElementId& element, | 884 Error* Session::GetAttribute(const WebElementId& element, |
976 const std::string& key, Value** value) { | 885 const std::string& key, |
977 std::string script = base::StringPrintf( | 886 Value** value) { |
978 "return (%s).apply(null, arguments);", atoms::GET_ATTRIBUTE); | 887 return ExecuteScriptAndParse(current_target_, |
979 | 888 atoms::GET_ATTRIBUTE, |
980 ListValue args; | 889 "getAttribute", |
981 args.Append(element.ToValue()); | 890 CreateListValueFrom(element, key), |
982 args.Append(Value::CreateStringValue(key)); | 891 CreateDirectValueParser(value)); |
983 | |
984 Error* error = ExecuteScript(script, &args, value); | |
985 if (error) { | |
986 return error; | |
987 } | |
988 | |
989 return NULL; | |
990 } | 892 } |
991 | 893 |
992 Error* Session::WaitForAllTabsToStopLoading() { | 894 Error* Session::WaitForAllTabsToStopLoading() { |
993 if (!automation_.get()) | 895 if (!automation_.get()) |
994 return NULL; | 896 return NULL; |
995 Error* error = NULL; | 897 Error* error = NULL; |
996 RunSessionTask(NewRunnableMethod( | 898 RunSessionTask(NewRunnableMethod( |
997 automation_.get(), | 899 automation_.get(), |
998 &Automation::WaitForAllTabsToStopLoading, | 900 &Automation::WaitForAllTabsToStopLoading, |
999 &error)); | 901 &error)); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1033 } | 935 } |
1034 | 936 |
1035 void Session::set_use_native_events(bool use_native_events) { | 937 void Session::set_use_native_events(bool use_native_events) { |
1036 use_native_events_ = use_native_events; | 938 use_native_events_ = use_native_events; |
1037 } | 939 } |
1038 | 940 |
1039 bool Session::use_native_events() const { | 941 bool Session::use_native_events() const { |
1040 return use_native_events_; | 942 return use_native_events_; |
1041 } | 943 } |
1042 | 944 |
1043 const gfx::Point& Session::get_mouse_position() const { | 945 const Point& Session::get_mouse_position() const { |
1044 return mouse_position_; | 946 return mouse_position_; |
1045 } | 947 } |
1046 | 948 |
1047 void Session::RunSessionTask(Task* task) { | 949 void Session::RunSessionTask(Task* task) { |
1048 base::WaitableEvent done_event(false, false); | 950 base::WaitableEvent done_event(false, false); |
1049 thread_.message_loop_proxy()->PostTask(FROM_HERE, NewRunnableMethod( | 951 thread_.message_loop_proxy()->PostTask(FROM_HERE, NewRunnableMethod( |
1050 this, | 952 this, |
1051 &Session::RunSessionTaskOnSessionThread, | 953 &Session::RunSessionTaskOnSessionThread, |
1052 task, | 954 task, |
1053 &done_event)); | 955 &done_event)); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1086 } | 988 } |
1087 current_target_ = FrameId(tab_ids[0], FramePath()); | 989 current_target_ = FrameId(tab_ids[0], FramePath()); |
1088 } | 990 } |
1089 | 991 |
1090 void Session::TerminateOnSessionThread() { | 992 void Session::TerminateOnSessionThread() { |
1091 if (automation_.get()) | 993 if (automation_.get()) |
1092 automation_->Terminate(); | 994 automation_->Terminate(); |
1093 automation_.reset(); | 995 automation_.reset(); |
1094 } | 996 } |
1095 | 997 |
1096 Error* Session::ExecuteScriptAndParseResponse(const FrameId& frame_id, | 998 Error* Session::ExecuteScriptAndParseValue(const FrameId& frame_id, |
1097 const std::string& script, | 999 const std::string& script, |
1098 Value** script_result) { | 1000 Value** script_result) { |
1099 std::string response_json; | 1001 std::string response_json; |
1100 Error* error = NULL; | 1002 Error* error = NULL; |
1101 RunSessionTask(NewRunnableMethod( | 1003 RunSessionTask(NewRunnableMethod( |
1102 automation_.get(), | 1004 automation_.get(), |
1103 &Automation::ExecuteScript, | 1005 &Automation::ExecuteScript, |
1104 frame_id.window_id, | 1006 frame_id.window_id, |
1105 frame_id.frame_path, | 1007 frame_id.frame_path, |
1106 script, | 1008 script, |
1107 &response_json, | 1009 &response_json, |
1108 &error)); | 1010 &error)); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1177 key_events[i].modified_text.c_str(), | 1079 key_events[i].modified_text.c_str(), |
1178 key_events[i].modifiers); | 1080 key_events[i].modifiers); |
1179 (*error)->AddDetails(details); | 1081 (*error)->AddDetails(details); |
1180 return; | 1082 return; |
1181 } | 1083 } |
1182 } | 1084 } |
1183 } | 1085 } |
1184 | 1086 |
1185 Error* Session::SwitchToFrameWithJavaScriptLocatedFrame( | 1087 Error* Session::SwitchToFrameWithJavaScriptLocatedFrame( |
1186 const std::string& script, ListValue* args) { | 1088 const std::string& script, ListValue* args) { |
1187 Value* unscoped_result = NULL; | 1089 class SwitchFrameValueParser : public ValueParser { |
1188 Error* error = ExecuteScript(script, args, &unscoped_result); | 1090 public: |
1189 scoped_ptr<Value> result(unscoped_result); | 1091 SwitchFrameValueParser( |
| 1092 bool* found_frame, WebElementId* frame, std::string* xpath) |
| 1093 : found_frame_(found_frame), frame_(frame), xpath_(xpath) { } |
| 1094 |
| 1095 virtual ~SwitchFrameValueParser() { } |
| 1096 |
| 1097 virtual bool Parse(base::Value* value) const OVERRIDE { |
| 1098 if (value->IsType(Value::TYPE_NULL)) { |
| 1099 *found_frame_ = false; |
| 1100 return true; |
| 1101 } |
| 1102 ListValue* list; |
| 1103 if (!value->GetAsList(&list)) |
| 1104 return false; |
| 1105 *found_frame_ = true; |
| 1106 return SetFromListValue(list, frame_, xpath_); |
| 1107 } |
| 1108 |
| 1109 private: |
| 1110 bool* found_frame_; |
| 1111 WebElementId* frame_; |
| 1112 std::string* xpath_; |
| 1113 }; |
| 1114 |
| 1115 bool found_frame; |
| 1116 WebElementId new_frame_element; |
| 1117 std::string xpath; |
| 1118 Error* error = ExecuteScriptAndParse( |
| 1119 current_target_, script, "switchFrame", args, |
| 1120 new SwitchFrameValueParser(&found_frame, &new_frame_element, &xpath)); |
1190 if (error) | 1121 if (error) |
1191 return error; | 1122 return error; |
1192 | 1123 |
1193 ListValue* frame_and_xpath_list; | 1124 if (!found_frame) |
1194 if (!result->GetAsList(&frame_and_xpath_list)) | |
1195 return new Error(kNoSuchFrame); | 1125 return new Error(kNoSuchFrame); |
1196 DictionaryValue* element_dict; | |
1197 std::string xpath; | |
1198 if (!frame_and_xpath_list->GetDictionary(0, &element_dict) || | |
1199 !frame_and_xpath_list->GetString(1, &xpath)) { | |
1200 return new Error( | |
1201 kUnknownError, | |
1202 "Frame finding script did not return correct type: " + | |
1203 JsonStringify(frame_and_xpath_list)); | |
1204 } | |
1205 WebElementId new_frame_element(element_dict); | |
1206 if (!new_frame_element.is_valid()) { | |
1207 return new Error( | |
1208 kUnknownError, | |
1209 "Frame finding script did not return a frame element: " + | |
1210 JsonStringify(element_dict)); | |
1211 } | |
1212 | 1126 |
1213 frame_elements_.push_back(new_frame_element); | 1127 frame_elements_.push_back(new_frame_element); |
1214 current_target_.frame_path = current_target_.frame_path.Append(xpath); | 1128 current_target_.frame_path = current_target_.frame_path.Append(xpath); |
1215 return NULL; | 1129 return NULL; |
1216 } | 1130 } |
1217 | 1131 |
1218 Error* Session::FindElementsHelper(const FrameId& frame_id, | 1132 Error* Session::FindElementsHelper(const FrameId& frame_id, |
1219 const WebElementId& root_element, | 1133 const WebElementId& root_element, |
1220 const std::string& locator, | 1134 const std::string& locator, |
1221 const std::string& query, | 1135 const std::string& query, |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1270 done = done || elapsed_time > implicit_wait_; | 1184 done = done || elapsed_time > implicit_wait_; |
1271 if (!done) | 1185 if (!done) |
1272 base::PlatformThread::Sleep(50); // Prevent a busy loop. | 1186 base::PlatformThread::Sleep(50); // Prevent a busy loop. |
1273 } | 1187 } |
1274 | 1188 |
1275 if (error.get()) | 1189 if (error.get()) |
1276 return error.release(); | 1190 return error.release(); |
1277 | 1191 |
1278 // Parse the results. | 1192 // Parse the results. |
1279 const std::string kInvalidElementDictionaryMessage = | 1193 const std::string kInvalidElementDictionaryMessage = |
1280 "Find element script returned invalid element dictionary: " + | 1194 "findElement script returned invalid element dictionary: " + |
1281 JsonStringify(value.get()); | 1195 JsonStringify(value.get()); |
1282 if (value->IsType(Value::TYPE_LIST)) { | 1196 if (find_one) { |
1283 ListValue* element_list = static_cast<ListValue*>(value.get()); | 1197 WebElementId element; |
| 1198 if (!SetFromValue(value.get(), &element)) |
| 1199 return new Error(kUnknownError, kInvalidElementDictionaryMessage); |
| 1200 elements->push_back(element); |
| 1201 } else { |
| 1202 ListValue* element_list; |
| 1203 if (!value->GetAsList(&element_list)) { |
| 1204 return new Error( |
| 1205 kUnknownError, |
| 1206 "findElements script returned unsupported type: " + |
| 1207 JsonStringify(value.get())); |
| 1208 } |
1284 for (size_t i = 0; i < element_list->GetSize(); ++i) { | 1209 for (size_t i = 0; i < element_list->GetSize(); ++i) { |
1285 DictionaryValue* element_dict = NULL; | 1210 WebElementId element; |
1286 if (!element_list->GetDictionary(i, &element_dict)) { | 1211 if (!SetFromValue(value.get(), &element)) |
1287 return new Error( | |
1288 kUnknownError, | |
1289 "Find element script returned non-dictionary: " + | |
1290 JsonStringify(element_list)); | |
1291 } | |
1292 | |
1293 WebElementId element(element_dict); | |
1294 if (!element.is_valid()) { | |
1295 return new Error(kUnknownError, kInvalidElementDictionaryMessage); | 1212 return new Error(kUnknownError, kInvalidElementDictionaryMessage); |
1296 } | |
1297 elements->push_back(element); | 1213 elements->push_back(element); |
1298 } | 1214 } |
1299 } else if (value->IsType(Value::TYPE_DICTIONARY)) { | |
1300 DictionaryValue* element_dict = | |
1301 static_cast<DictionaryValue*>(value.get()); | |
1302 WebElementId element(element_dict); | |
1303 if (!element.is_valid()) { | |
1304 return new Error(kUnknownError, kInvalidElementDictionaryMessage); | |
1305 } | |
1306 elements->push_back(element); | |
1307 } else { | |
1308 return new Error( | |
1309 kUnknownError, | |
1310 "Find element script returned unsupported type: " + | |
1311 JsonStringify(value.get())); | |
1312 } | 1215 } |
1313 return NULL; | 1216 return NULL; |
1314 } | 1217 } |
1315 | 1218 |
1316 Error* Session::GetElementRegionInViewHelper( | 1219 Error* Session::GetElementRegionInViewHelper( |
1317 const FrameId& frame_id, | 1220 const FrameId& frame_id, |
1318 const WebElementId& element, | 1221 const WebElementId& element, |
1319 const gfx::Rect& region, | 1222 const Rect& region, |
1320 bool center, | 1223 bool center, |
1321 gfx::Point* location) { | 1224 Point* location) { |
1322 std::string jscript = base::StringPrintf( | 1225 return ExecuteScriptAndParse(frame_id, |
1323 "return (%s).apply(null, arguments);", atoms::GET_LOCATION_IN_VIEW); | 1226 atoms::GET_LOCATION_IN_VIEW, |
1324 ListValue jscript_args; | 1227 "getLocationInView", |
1325 jscript_args.Append(element.ToValue()); | 1228 CreateListValueFrom(element, center, region), |
1326 jscript_args.Append(Value::CreateBooleanValue(center)); | 1229 CreateDirectValueParser(location)); |
1327 DictionaryValue* elem_offset_dict = new DictionaryValue(); | |
1328 elem_offset_dict->SetInteger("left", region.x()); | |
1329 elem_offset_dict->SetInteger("top", region.y()); | |
1330 elem_offset_dict->SetInteger("width", region.width()); | |
1331 elem_offset_dict->SetInteger("height", region.height()); | |
1332 jscript_args.Append(elem_offset_dict); | |
1333 Value* unscoped_value = NULL; | |
1334 Error* error = ExecuteScript(frame_id, jscript, &jscript_args, | |
1335 &unscoped_value); | |
1336 scoped_ptr<Value> value(unscoped_value); | |
1337 if (error) | |
1338 return error; | |
1339 if (!value->IsType(Value::TYPE_DICTIONARY)) { | |
1340 return new Error( | |
1341 kUnknownError, | |
1342 "Location atom returned non-dictionary type: " + | |
1343 JsonStringify(value.get())); | |
1344 } | |
1345 DictionaryValue* loc_dict = static_cast<DictionaryValue*>(value.get()); | |
1346 int x = 0, y = 0; | |
1347 if (!loc_dict->GetInteger("x", &x) || | |
1348 !loc_dict->GetInteger("y", &y)) { | |
1349 return new Error( | |
1350 kUnknownError, | |
1351 "Location atom returned bad coordinate dictionary: " + | |
1352 JsonStringify(loc_dict)); | |
1353 } | |
1354 *location = gfx::Point(x, y); | |
1355 return NULL; | |
1356 } | 1230 } |
1357 | 1231 |
1358 Error* Session::GetScreenShot(std::string* png) { | 1232 Error* Session::GetScreenShot(std::string* png) { |
1359 Error* error = NULL; | 1233 Error* error = NULL; |
1360 ScopedTempDir screenshots_dir; | 1234 ScopedTempDir screenshots_dir; |
1361 if (!screenshots_dir.CreateUniqueTempDir()) { | 1235 if (!screenshots_dir.CreateUniqueTempDir()) { |
1362 return new Error(kUnknownError, | 1236 return new Error(kUnknownError, |
1363 "Could not create temp directory for screenshot"); | 1237 "Could not create temp directory for screenshot"); |
1364 } | 1238 } |
1365 | 1239 |
1366 FilePath path = screenshots_dir.path().AppendASCII("screen"); | 1240 FilePath path = screenshots_dir.path().AppendASCII("screen"); |
1367 RunSessionTask(NewRunnableMethod( | 1241 RunSessionTask(NewRunnableMethod( |
1368 automation_.get(), | 1242 automation_.get(), |
1369 &Automation::CaptureEntirePageAsPNG, | 1243 &Automation::CaptureEntirePageAsPNG, |
1370 current_target_.window_id, | 1244 current_target_.window_id, |
1371 path, | 1245 path, |
1372 &error)); | 1246 &error)); |
1373 if (error) | 1247 if (error) |
1374 return error; | 1248 return error; |
1375 if (!file_util::ReadFileToString(path, png)) | 1249 if (!file_util::ReadFileToString(path, png)) |
1376 return new Error(kUnknownError, "Could not read screenshot file"); | 1250 return new Error(kUnknownError, "Could not read screenshot file"); |
1377 return NULL; | 1251 return NULL; |
1378 } | 1252 } |
1379 | 1253 |
1380 } // namespace webdriver | 1254 } // namespace webdriver |
OLD | NEW |