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 |