Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(104)

Side by Side Diff: chrome/test/webdriver/session.cc

Issue 7522024: Refactor chromedriver's script execution to reduce amount of custom Value parsing. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: ... Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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, &region_offset); 730 current_target_, element, region, center, &region_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
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, &region_offset); 761 center, &region_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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698