| 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_manager.h" | 5 #include "chrome/test/webdriver/session_manager.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/message_loop_proxy.h" | 12 #include "base/message_loop_proxy.h" |
| 13 #include "base/process.h" | 13 #include "base/process.h" |
| 14 #include "base/process_util.h" | 14 #include "base/process_util.h" |
| 15 #include "base/scoped_ptr.h" |
| 15 #include "base/stringprintf.h" | 16 #include "base/stringprintf.h" |
| 17 #include "base/string_number_conversions.h" |
| 16 #include "base/string_util.h" | 18 #include "base/string_util.h" |
| 17 #include "base/json/json_reader.h" | 19 #include "base/json/json_reader.h" |
| 18 #include "base/json/json_writer.h" | 20 #include "base/json/json_writer.h" |
| 19 #include "base/test/test_timeouts.h" | 21 #include "base/test/test_timeouts.h" |
| 20 #include "base/utf_string_conversions.h" | 22 #include "base/utf_string_conversions.h" |
| 21 #include "chrome/app/chrome_command_ids.h" | 23 #include "chrome/app/chrome_command_ids.h" |
| 22 #include "chrome/common/chrome_constants.h" | 24 #include "chrome/common/chrome_constants.h" |
| 23 #include "chrome/common/chrome_switches.h" | 25 #include "chrome/common/chrome_switches.h" |
| 24 #include "chrome/test/test_launcher_utils.h" | 26 #include "chrome/test/test_launcher_utils.h" |
| 27 #include "chrome/test/webdriver/session_manager.h" |
| 25 #include "chrome/test/webdriver/utility_functions.h" | 28 #include "chrome/test/webdriver/utility_functions.h" |
| 26 #include "chrome/test/webdriver/webdriver_key_converter.h" | 29 #include "chrome/test/webdriver/webdriver_key_converter.h" |
| 27 #include "googleurl/src/gurl.h" | 30 #include "googleurl/src/gurl.h" |
| 28 #include "third_party/webdriver/atoms.h" | 31 #include "third_party/webdriver/atoms.h" |
| 29 | 32 |
| 30 namespace webdriver { | 33 namespace webdriver { |
| 31 | 34 |
| 32 Session::Session(const std::string& id) | 35 Session::Session() |
| 33 : thread_(id.c_str()), | 36 : id_(GenerateRandomID()), |
| 34 id_(id), | 37 thread_(id_.c_str()), |
| 35 window_num_(0), | |
| 36 implicit_wait_(0), | 38 implicit_wait_(0), |
| 37 current_frame_xpath_("") { | 39 current_frame_xpath_(""), |
| 40 current_window_id_(0) { |
| 41 SessionManager::GetInstance()->Add(this); |
| 38 } | 42 } |
| 39 | 43 |
| 40 Session::~Session() {} | 44 Session::~Session() { |
| 45 SessionManager::GetInstance()->Remove(id_); |
| 46 } |
| 41 | 47 |
| 42 bool Session::Init() { | 48 bool Session::Init() { |
| 43 if (!thread_.Start()) { | 49 bool success = false; |
| 50 if (thread_.Start()) { |
| 51 RunSessionTask(NewRunnableMethod( |
| 52 this, |
| 53 &Session::InitOnSessionThread, |
| 54 &success)); |
| 55 } else { |
| 44 LOG(ERROR) << "Cannot start session thread"; | 56 LOG(ERROR) << "Cannot start session thread"; |
| 45 return false; | |
| 46 } | 57 } |
| 47 | 58 if (!success) |
| 48 bool success = false; | 59 delete this; |
| 49 RunSessionTask(NewRunnableMethod( | |
| 50 this, | |
| 51 &Session::InitOnSessionThread, | |
| 52 &success)); | |
| 53 return success; | 60 return success; |
| 54 } | 61 } |
| 55 | 62 |
| 56 void Session::Terminate() { | 63 void Session::Terminate() { |
| 57 RunSessionTask(NewRunnableMethod( | 64 RunSessionTask(NewRunnableMethod( |
| 58 this, | 65 this, |
| 59 &Session::TerminateOnSessionThread)); | 66 &Session::TerminateOnSessionThread)); |
| 67 delete this; |
| 60 } | 68 } |
| 61 | 69 |
| 62 ErrorCode Session::ExecuteScript(const std::string& script, | 70 ErrorCode Session::ExecuteScript(int window_id, |
| 71 const std::string& frame_xpath, |
| 72 const std::string& script, |
| 63 const ListValue* const args, | 73 const ListValue* const args, |
| 64 Value** value) { | 74 Value** value) { |
| 65 std::string args_as_json; | 75 std::string args_as_json; |
| 66 base::JSONWriter::Write(static_cast<const Value* const>(args), | 76 base::JSONWriter::Write(static_cast<const Value* const>(args), |
| 67 /*pretty_print=*/false, | 77 /*pretty_print=*/false, |
| 68 &args_as_json); | 78 &args_as_json); |
| 69 | 79 |
| 70 // Every injected script is fed through the executeScript atom. This atom | 80 // Every injected script is fed through the executeScript atom. This atom |
| 71 // will catch any errors that are thrown and convert them to the | 81 // will catch any errors that are thrown and convert them to the |
| 72 // appropriate JSON structure. | 82 // appropriate JSON structure. |
| 73 std::string jscript = base::StringPrintf( | 83 std::string jscript = base::StringPrintf( |
| 74 "window.domAutomationController.send((%s).apply(null," | 84 "window.domAutomationController.send((%s).apply(null," |
| 75 "[function(){%s\n},%s,true]));", | 85 "[function(){%s\n},%s,true]));", |
| 76 atoms::EXECUTE_SCRIPT, script.c_str(), args_as_json.c_str()); | 86 atoms::EXECUTE_SCRIPT, script.c_str(), args_as_json.c_str()); |
| 77 | 87 |
| 78 // Should we also log the script that's being executed? It could be several KB | 88 // Should we also log the script that's being executed? It could be several KB |
| 79 // in size and will add lots of noise to the logs. | 89 // in size and will add lots of noise to the logs. |
| 80 VLOG(1) << "Executing script in frame: " << current_frame_xpath_; | 90 VLOG(1) << "Executing script in frame: " << current_frame_xpath_; |
| 81 | 91 |
| 82 std::string result; | 92 std::string result; |
| 83 bool success; | 93 bool success = false; |
| 84 RunSessionTask(NewRunnableMethod( | 94 RunSessionTask(NewRunnableMethod( |
| 85 automation_.get(), | 95 automation_.get(), |
| 86 &Automation::ExecuteScript, | 96 &Automation::ExecuteScript, |
| 87 current_frame_xpath_, | 97 window_id, |
| 98 frame_xpath, |
| 88 jscript, | 99 jscript, |
| 89 &result, | 100 &result, |
| 90 &success)); | 101 &success)); |
| 91 if (!success) { | 102 if (!success) { |
| 103 LOG(ERROR) << "Automation failed to execute script"; |
| 92 *value = Value::CreateStringValue( | 104 *value = Value::CreateStringValue( |
| 93 "Unknown internal script execution failure"); | 105 "Unknown internal script execution failure"); |
| 94 return kUnknownError; | 106 return kUnknownError; |
| 95 } | 107 } |
| 96 | 108 |
| 97 VLOG(1) << "...script result: " << result; | 109 VLOG(1) << "...script result: " << result; |
| 98 scoped_ptr<Value> r(base::JSONReader::ReadAndReturnError( | 110 scoped_ptr<Value> r(base::JSONReader::ReadAndReturnError( |
| 99 result, true, NULL, NULL)); | 111 result, true, NULL, NULL)); |
| 100 if (!r.get()) { | 112 if (!r.get()) { |
| 113 LOG(ERROR) << "Failed to parse script result"; |
| 101 *value = Value::CreateStringValue( | 114 *value = Value::CreateStringValue( |
| 102 "Internal script execution error: failed to parse script result"); | 115 "Internal script execution error: failed to parse script result"); |
| 103 return kUnknownError; | 116 return kUnknownError; |
| 104 } | 117 } |
| 105 | 118 |
| 106 if (r->GetType() != Value::TYPE_DICTIONARY) { | 119 if (r->GetType() != Value::TYPE_DICTIONARY) { |
| 120 LOG(ERROR) << "Execute script returned non-dictionary type"; |
| 107 std::ostringstream stream; | 121 std::ostringstream stream; |
| 108 stream << "Internal script execution error: script result must be a " | 122 stream << "Internal script execution error: script result must be a " |
| 109 << print_valuetype(Value::TYPE_DICTIONARY) << ", but was " | 123 << print_valuetype(Value::TYPE_DICTIONARY) << ", but was " |
| 110 << print_valuetype(r->GetType()) << ": " << result; | 124 << print_valuetype(r->GetType()) << ": " << result; |
| 111 *value = Value::CreateStringValue(stream.str()); | 125 *value = Value::CreateStringValue(stream.str()); |
| 112 return kUnknownError; | 126 return kUnknownError; |
| 113 } | 127 } |
| 114 | 128 |
| 115 DictionaryValue* result_dict = static_cast<DictionaryValue*>(r.get()); | 129 DictionaryValue* result_dict = static_cast<DictionaryValue*>(r.get()); |
| 116 | 130 |
| 117 Value* tmp; | 131 Value* tmp; |
| 118 if (result_dict->Get("value", &tmp)) { | 132 if (result_dict->Get("value", &tmp)) { |
| 119 // result_dict owns the returned value, so we need to make a copy. | 133 // result_dict owns the returned value, so we need to make a copy. |
| 120 *value = tmp->DeepCopy(); | 134 *value = tmp->DeepCopy(); |
| 121 } else { | 135 } else { |
| 122 // "value" was not defined in the returned dictionary, set to null. | 136 // "value" was not defined in the returned dictionary, set to null. |
| 123 *value = Value::CreateNullValue(); | 137 *value = Value::CreateNullValue(); |
| 124 } | 138 } |
| 125 | 139 |
| 126 int status; | 140 int status; |
| 127 if (!result_dict->GetInteger("status", &status)) { | 141 if (!result_dict->GetInteger("status", &status)) { |
| 128 NOTREACHED() << "...script did not return a status flag."; | 142 NOTREACHED() << "...script did not return a status flag."; |
| 129 } | 143 } |
| 130 return static_cast<ErrorCode>(status); | 144 return static_cast<ErrorCode>(status); |
| 131 } | 145 } |
| 132 | 146 |
| 147 ErrorCode Session::ExecuteScript(const std::string& script, |
| 148 const ListValue* const args, |
| 149 Value** value) { |
| 150 return ExecuteScript( |
| 151 current_window_id_, current_frame_xpath_, script, args, value); |
| 152 } |
| 153 |
| 133 ErrorCode Session::SendKeys(DictionaryValue* element, const string16& keys) { | 154 ErrorCode Session::SendKeys(DictionaryValue* element, const string16& keys) { |
| 134 ListValue args; | 155 ListValue args; |
| 135 args.Append(element); | 156 args.Append(element); |
| 136 // TODO(jleyba): Update this to use the correct atom. | 157 // TODO(jleyba): Update this to use the correct atom. |
| 137 std::string script = "document.activeElement.blur();arguments[0].focus();"; | 158 std::string script = "document.activeElement.blur();arguments[0].focus();"; |
| 138 Value* unscoped_result = NULL; | 159 Value* unscoped_result = NULL; |
| 139 ErrorCode code = ExecuteScript(script, &args, &unscoped_result); | 160 ErrorCode code = ExecuteScript(script, &args, &unscoped_result); |
| 140 scoped_ptr<Value> result(unscoped_result); | 161 scoped_ptr<Value> result(unscoped_result); |
| 141 if (code != kSuccess) | 162 if (code != kSuccess) { |
| 163 LOG(ERROR) << "Failed to focus element before sending keys"; |
| 142 return code; | 164 return code; |
| 165 } |
| 143 | 166 |
| 144 bool success = false; | 167 bool success = false; |
| 145 RunSessionTask(NewRunnableMethod( | 168 RunSessionTask(NewRunnableMethod( |
| 146 this, | 169 this, |
| 147 &Session::SendKeysOnSessionThread, | 170 &Session::SendKeysOnSessionThread, |
| 148 keys, | 171 keys, |
| 149 &success)); | 172 &success)); |
| 150 if (!success) | 173 if (!success) |
| 151 return kUnknownError; | 174 return kUnknownError; |
| 152 return kSuccess; | 175 return kSuccess; |
| 153 } | 176 } |
| 154 | 177 |
| 155 bool Session::NavigateToURL(const std::string& url) { | 178 bool Session::NavigateToURL(const std::string& url) { |
| 156 bool success = false; | 179 bool success = false; |
| 157 RunSessionTask(NewRunnableMethod( | 180 RunSessionTask(NewRunnableMethod( |
| 158 automation_.get(), | 181 automation_.get(), |
| 159 &Automation::NavigateToURL, | 182 &Automation::NavigateToURL, |
| 183 current_window_id_, |
| 160 url, | 184 url, |
| 161 &success)); | 185 &success)); |
| 162 return success; | 186 return success; |
| 163 } | 187 } |
| 164 | 188 |
| 165 bool Session::GoForward() { | 189 bool Session::GoForward() { |
| 166 bool success = false; | 190 bool success = false; |
| 167 RunSessionTask(NewRunnableMethod( | 191 RunSessionTask(NewRunnableMethod( |
| 168 automation_.get(), | 192 automation_.get(), |
| 169 &Automation::GoForward, | 193 &Automation::GoForward, |
| 194 current_window_id_, |
| 170 &success)); | 195 &success)); |
| 171 return success; | 196 return success; |
| 172 } | 197 } |
| 173 | 198 |
| 174 bool Session::GoBack() { | 199 bool Session::GoBack() { |
| 175 bool success = false; | 200 bool success = false; |
| 176 RunSessionTask(NewRunnableMethod( | 201 RunSessionTask(NewRunnableMethod( |
| 177 automation_.get(), | 202 automation_.get(), |
| 178 &Automation::GoBack, | 203 &Automation::GoBack, |
| 204 current_window_id_, |
| 179 &success)); | 205 &success)); |
| 180 return success; | 206 return success; |
| 181 } | 207 } |
| 182 | 208 |
| 183 bool Session::Reload() { | 209 bool Session::Reload() { |
| 184 bool success = false; | 210 bool success = false; |
| 185 RunSessionTask(NewRunnableMethod( | 211 RunSessionTask(NewRunnableMethod( |
| 186 automation_.get(), | 212 automation_.get(), |
| 187 &Automation::Reload, | 213 &Automation::Reload, |
| 214 current_window_id_, |
| 188 &success)); | 215 &success)); |
| 189 return success; | 216 return success; |
| 190 } | 217 } |
| 191 | 218 |
| 192 bool Session::GetURL(std::string* url) { | 219 bool Session::GetURL(std::string* url) { |
| 193 bool success = false; | 220 bool success = false; |
| 194 RunSessionTask(NewRunnableMethod( | 221 RunSessionTask(NewRunnableMethod( |
| 195 automation_.get(), | 222 automation_.get(), |
| 196 &Automation::GetURL, | 223 &Automation::GetURL, |
| 224 current_window_id_, |
| 197 url, | 225 url, |
| 198 &success)); | 226 &success)); |
| 199 return success; | 227 return success; |
| 200 } | 228 } |
| 201 | 229 |
| 202 bool Session::GetURL(GURL* gurl) { | 230 bool Session::GetURL(GURL* gurl) { |
| 203 bool success = false; | 231 bool success = false; |
| 204 RunSessionTask(NewRunnableMethod( | 232 RunSessionTask(NewRunnableMethod( |
| 205 automation_.get(), | 233 automation_.get(), |
| 206 &Automation::GetGURL, | 234 &Automation::GetGURL, |
| 235 current_window_id_, |
| 207 gurl, | 236 gurl, |
| 208 &success)); | 237 &success)); |
| 209 return success; | 238 return success; |
| 210 } | 239 } |
| 211 | 240 |
| 212 bool Session::GetTabTitle(std::string* tab_title) { | 241 bool Session::GetTabTitle(std::string* tab_title) { |
| 213 bool success = false; | 242 bool success = false; |
| 214 RunSessionTask(NewRunnableMethod( | 243 RunSessionTask(NewRunnableMethod( |
| 215 automation_.get(), | 244 automation_.get(), |
| 216 &Automation::GetTabTitle, | 245 &Automation::GetTabTitle, |
| 246 current_window_id_, |
| 217 tab_title, | 247 tab_title, |
| 218 &success)); | 248 &success)); |
| 219 return success; | 249 return success; |
| 220 } | 250 } |
| 221 | 251 |
| 222 bool Session::GetCookies(const GURL& url, std::string* cookies) { | 252 bool Session::GetCookies(const GURL& url, std::string* cookies) { |
| 223 bool success = false; | 253 bool success = false; |
| 224 RunSessionTask(NewRunnableMethod( | 254 RunSessionTask(NewRunnableMethod( |
| 225 automation_.get(), | 255 automation_.get(), |
| 226 &Automation::GetCookies, | 256 &Automation::GetCookies, |
| 257 current_window_id_, |
| 227 url, | 258 url, |
| 228 cookies, | 259 cookies, |
| 229 &success)); | 260 &success)); |
| 230 return success; | 261 return success; |
| 231 } | 262 } |
| 232 | 263 |
| 233 bool Session::GetCookieByName(const GURL& url, | 264 bool Session::GetCookieByName(const GURL& url, |
| 234 const std::string& cookie_name, | 265 const std::string& cookie_name, |
| 235 std::string* cookie) { | 266 std::string* cookie) { |
| 236 bool success = false; | 267 bool success = false; |
| 237 RunSessionTask(NewRunnableMethod( | 268 RunSessionTask(NewRunnableMethod( |
| 238 automation_.get(), | 269 automation_.get(), |
| 239 &Automation::GetCookieByName, | 270 &Automation::GetCookieByName, |
| 271 current_window_id_, |
| 240 url, | 272 url, |
| 241 cookie_name, | 273 cookie_name, |
| 242 cookie, | 274 cookie, |
| 243 &success)); | 275 &success)); |
| 244 return success; | 276 return success; |
| 245 } | 277 } |
| 246 | 278 |
| 247 bool Session::DeleteCookie(const GURL& url, const std::string& cookie_name) { | 279 bool Session::DeleteCookie(const GURL& url, const std::string& cookie_name) { |
| 248 bool success = false; | 280 bool success = false; |
| 249 RunSessionTask(NewRunnableMethod( | 281 RunSessionTask(NewRunnableMethod( |
| 250 automation_.get(), | 282 automation_.get(), |
| 251 &Automation::DeleteCookie, | 283 &Automation::DeleteCookie, |
| 284 current_window_id_, |
| 252 url, | 285 url, |
| 253 cookie_name, | 286 cookie_name, |
| 254 &success)); | 287 &success)); |
| 255 return success; | 288 return success; |
| 256 } | 289 } |
| 257 | 290 |
| 258 bool Session::SetCookie(const GURL& url, const std::string& cookie) { | 291 bool Session::SetCookie(const GURL& url, const std::string& cookie) { |
| 259 bool success = false; | 292 bool success = false; |
| 260 RunSessionTask(NewRunnableMethod( | 293 RunSessionTask(NewRunnableMethod( |
| 261 automation_.get(), | 294 automation_.get(), |
| 262 &Automation::SetCookie, | 295 &Automation::SetCookie, |
| 296 current_window_id_, |
| 263 url, | 297 url, |
| 264 cookie, | 298 cookie, |
| 265 &success)); | 299 &success)); |
| 266 return success; | 300 return success; |
| 267 } | 301 } |
| 268 | 302 |
| 303 bool Session::GetWindowIds(std::vector<int>* window_ids) { |
| 304 bool success = false; |
| 305 RunSessionTask(NewRunnableMethod( |
| 306 automation_.get(), |
| 307 &Automation::GetTabIds, |
| 308 window_ids, |
| 309 &success)); |
| 310 return success; |
| 311 } |
| 312 |
| 313 ErrorCode Session::SwitchToWindow(const std::string& name) { |
| 314 int switch_to_id = 0; |
| 315 int name_no = 0; |
| 316 if (base::StringToInt(name, &name_no)) { |
| 317 bool does_exist = false; |
| 318 RunSessionTask(NewRunnableMethod( |
| 319 automation_.get(), |
| 320 &Automation::DoesTabExist, |
| 321 name_no, |
| 322 &does_exist)); |
| 323 if (does_exist) |
| 324 switch_to_id = name_no; |
| 325 } |
| 326 |
| 327 if (!switch_to_id) { |
| 328 std::vector<int> window_ids; |
| 329 GetWindowIds(&window_ids); |
| 330 // See if any of the window names match |name|. |
| 331 for (size_t i = 0; i < window_ids.size(); ++i) { |
| 332 ListValue empty_list; |
| 333 Value* unscoped_name_value; |
| 334 std::string window_name; |
| 335 ErrorCode code = ExecuteScript(window_ids[i], |
| 336 "", |
| 337 "return window.name;", |
| 338 &empty_list, |
| 339 &unscoped_name_value); |
| 340 scoped_ptr<Value> name_value(unscoped_name_value); |
| 341 if (code == kSuccess && |
| 342 name_value->GetAsString(&window_name) && |
| 343 name == window_name) { |
| 344 switch_to_id = window_ids[i]; |
| 345 break; |
| 346 } |
| 347 } |
| 348 } |
| 349 |
| 350 if (!switch_to_id) |
| 351 return kNoSuchWindow; |
| 352 current_window_id_ = switch_to_id; |
| 353 current_frame_xpath_ = ""; |
| 354 return kSuccess; |
| 355 } |
| 356 |
| 357 ErrorCode Session::SwitchToFrameWithNameOrId(const std::string& name_or_id) { |
| 358 std::string script = |
| 359 "var arg = arguments[0];" |
| 360 "var xpath = '(/html/body//iframe|/html/frameset/frame)';" |
| 361 "var sub = function(s) { return s.replace(/\\$/g, arg); };" |
| 362 "xpath += sub('[@name=\"$\" or @id=\"$\"]');" |
| 363 "var frame = document.evaluate(xpath, document, null, " |
| 364 " XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;" |
| 365 "if (!frame) { return null; }" |
| 366 "xpath = frame.tagName == 'IFRAME' ? '/html/body//iframe'" |
| 367 " : '/html/frameset/frame';" |
| 368 "return xpath + sub('[@' + (frame.id == arg ? 'id' : 'name')" |
| 369 " + '=\"$\"]');"; |
| 370 ListValue args; |
| 371 args.Append(new StringValue(name_or_id)); |
| 372 return SwitchToFrameWithJavaScriptLocatedFrame(script, &args); |
| 373 } |
| 374 |
| 375 ErrorCode Session::SwitchToFrameWithIndex(int index) { |
| 376 // We cannot simply index into window.frames because we need to know the |
| 377 // tagName of the frameElement. If child frame N is from another domain, then |
| 378 // the following will run afoul of the same origin policy: |
| 379 // window.frames[N].frameElement; |
| 380 // Instead of indexing window.frames, we use a an XPath expression to index |
| 381 // into the list of all IFRAME and FRAME elements on the page - if we find |
| 382 // something, then that XPath expression can be used as the new frame's XPath. |
| 383 std::string script = |
| 384 "var index = '[' + (arguments[0] + 1) + ']';" |
| 385 "var xpath = '(/html/body//iframe|/html/frameset/frame)' + " |
| 386 " index;" |
| 387 "console.info('searching for frame by xpath: ' + xpath);" |
| 388 "var frame = document.evaluate(xpath, document, null, " |
| 389 "XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;" |
| 390 "console.info(frame == null ? 'found nothing' : frame);" |
| 391 "return frame == null ? null : ((frame.tagName == 'IFRAME' ? " |
| 392 " '/html/body//iframe' : '/html/frameset/frame') + index);"; |
| 393 ListValue args; |
| 394 args.Append(Value::CreateIntegerValue(index)); |
| 395 return SwitchToFrameWithJavaScriptLocatedFrame(script, &args); |
| 396 } |
| 397 |
| 398 bool Session::CloseWindow() { |
| 399 bool success = false; |
| 400 RunSessionTask(NewRunnableMethod( |
| 401 automation_.get(), |
| 402 &Automation::CloseTab, |
| 403 current_window_id_, |
| 404 &success)); |
| 405 |
| 406 if (success) { |
| 407 std::vector<int> window_ids; |
| 408 if (!GetWindowIds(&window_ids) || window_ids.empty()) { |
| 409 // The automation connection will soon be closed, if not already, |
| 410 // because we supposedly just closed the last window. Terminate the |
| 411 // session. |
| 412 // TODO(kkania): This will cause us problems if GetWindowIds fails for a |
| 413 // reason other than the channel is disconnected. Look into having |
| 414 // |GetWindowIds| tell us if it just closed the last window. |
| 415 Terminate(); |
| 416 } |
| 417 } |
| 418 return success; |
| 419 } |
| 420 |
| 269 void Session::RunSessionTask(Task* task) { | 421 void Session::RunSessionTask(Task* task) { |
| 270 base::WaitableEvent done_event(false, false); | 422 base::WaitableEvent done_event(false, false); |
| 271 thread_.message_loop_proxy()->PostTask(FROM_HERE, NewRunnableMethod( | 423 thread_.message_loop_proxy()->PostTask(FROM_HERE, NewRunnableMethod( |
| 272 this, | 424 this, |
| 273 &Session::RunSessionTaskOnSessionThread, | 425 &Session::RunSessionTaskOnSessionThread, |
| 274 task, | 426 task, |
| 275 &done_event)); | 427 &done_event)); |
| 276 done_event.Wait(); | 428 done_event.Wait(); |
| 277 } | 429 } |
| 278 | 430 |
| 279 void Session::RunSessionTaskOnSessionThread(Task* task, | 431 void Session::RunSessionTaskOnSessionThread(Task* task, |
| 280 base::WaitableEvent* done_event) { | 432 base::WaitableEvent* done_event) { |
| 281 task->Run(); | 433 task->Run(); |
| 282 delete task; | 434 delete task; |
| 283 done_event->Signal(); | 435 done_event->Signal(); |
| 284 } | 436 } |
| 285 | 437 |
| 286 void Session::InitOnSessionThread(bool* success) { | 438 void Session::InitOnSessionThread(bool* success) { |
| 287 automation_.reset(new Automation()); | 439 automation_.reset(new Automation()); |
| 288 automation_->Init(success); | 440 automation_->Init(success); |
| 441 if (!*success) |
| 442 return; |
| 443 |
| 444 std::vector<int> tab_ids; |
| 445 automation_->GetTabIds(&tab_ids, success); |
| 446 if (!*success) { |
| 447 LOG(ERROR) << "Could not get tab ids"; |
| 448 return; |
| 449 } |
| 450 if (tab_ids.empty()) { |
| 451 LOG(ERROR) << "No tab ids after initialization"; |
| 452 *success = false; |
| 453 } else { |
| 454 current_window_id_ = tab_ids[0]; |
| 455 } |
| 289 } | 456 } |
| 290 | 457 |
| 291 void Session::TerminateOnSessionThread() { | 458 void Session::TerminateOnSessionThread() { |
| 292 automation_->Terminate(); | 459 if (automation_.get()) |
| 460 automation_->Terminate(); |
| 293 automation_.reset(); | 461 automation_.reset(); |
| 294 } | 462 } |
| 295 | 463 |
| 296 void Session::SendKeysOnSessionThread(const string16& keys, | 464 void Session::SendKeysOnSessionThread(const string16& keys, |
| 297 bool* success) { | 465 bool* success) { |
| 298 *success = true; | 466 *success = true; |
| 299 std::vector<WebKeyEvent> key_events; | 467 std::vector<WebKeyEvent> key_events; |
| 300 ConvertKeysToWebKeyEvents(keys, &key_events); | 468 ConvertKeysToWebKeyEvents(keys, &key_events); |
| 301 for (size_t i = 0; i < key_events.size(); ++i) { | 469 for (size_t i = 0; i < key_events.size(); ++i) { |
| 302 bool key_success = false; | 470 bool key_success = false; |
| 303 automation_->SendWebKeyEvent(key_events[i], &key_success); | 471 automation_->SendWebKeyEvent( |
| 472 current_window_id_, key_events[i], &key_success); |
| 304 if (!key_success) { | 473 if (!key_success) { |
| 305 LOG(ERROR) << "Failed to send key event. Event details:\n" | 474 LOG(ERROR) << "Failed to send key event. Event details:\n" |
| 306 << "Type: " << key_events[i].type << "\n" | 475 << "Type: " << key_events[i].type << "\n" |
| 307 << "KeyCode: " << key_events[i].key_code << "\n" | 476 << "KeyCode: " << key_events[i].key_code << "\n" |
| 308 << "UnmodifiedText: " << key_events[i].unmodified_text << "\n" | 477 << "UnmodifiedText: " << key_events[i].unmodified_text << "\n" |
| 309 << "ModifiedText: " << key_events[i].modified_text << "\n" | 478 << "ModifiedText: " << key_events[i].modified_text << "\n" |
| 310 << "Modifiers: " << key_events[i].modifiers << "\n"; | 479 << "Modifiers: " << key_events[i].modifiers << "\n"; |
| 311 *success = false; | 480 *success = false; |
| 312 } | 481 } |
| 313 } | 482 } |
| 314 } | 483 } |
| 315 | 484 |
| 485 ErrorCode Session::SwitchToFrameWithJavaScriptLocatedFrame( |
| 486 const std::string& script, |
| 487 ListValue* args) { |
| 488 Value* unscoped_result = NULL; |
| 489 ErrorCode code = ExecuteScript(script, args, &unscoped_result); |
| 490 scoped_ptr<Value> result(unscoped_result); |
| 491 if (code != kSuccess) |
| 492 return code; |
| 493 std::string xpath; |
| 494 if (result->GetAsString(&xpath)) { |
| 495 if (current_frame_xpath_.length()) |
| 496 current_frame_xpath_ += "\n"; |
| 497 current_frame_xpath_ += xpath; |
| 498 return kSuccess; |
| 499 } |
| 500 return kNoSuchFrame; |
| 501 } |
| 502 |
| 316 } // namespace webdriver | 503 } // namespace webdriver |
| OLD | NEW |