| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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/chromedriver/element_util.h" | 5 #include "chrome/test/chromedriver/element_util.h" |
| 6 | 6 |
| 7 #include "base/string_util.h" | 7 #include "base/string_util.h" |
| 8 #include "base/stringprintf.h" |
| 9 #include "base/strings/string_number_conversions.h" |
| 8 #include "base/threading/platform_thread.h" | 10 #include "base/threading/platform_thread.h" |
| 9 #include "base/time.h" | 11 #include "base/time.h" |
| 10 #include "base/values.h" | 12 #include "base/values.h" |
| 11 #include "chrome/test/chromedriver/basic_types.h" | 13 #include "chrome/test/chromedriver/basic_types.h" |
| 12 #include "chrome/test/chromedriver/js.h" | 14 #include "chrome/test/chromedriver/js.h" |
| 13 #include "chrome/test/chromedriver/session.h" | 15 #include "chrome/test/chromedriver/session.h" |
| 14 #include "chrome/test/chromedriver/status.h" | 16 #include "chrome/test/chromedriver/status.h" |
| 15 #include "chrome/test/chromedriver/web_view.h" | 17 #include "chrome/test/chromedriver/web_view.h" |
| 16 #include "third_party/webdriver/atoms.h" | 18 #include "third_party/webdriver/atoms.h" |
| 17 | 19 |
| 18 namespace { | 20 namespace { |
| 19 | 21 |
| 20 const char kElementKey[] = "ELEMENT"; | 22 const char kElementKey[] = "ELEMENT"; |
| 21 | 23 |
| 22 bool ParseFromValue(base::Value* value, WebPoint* point) { | 24 bool ParseFromValue(base::Value* value, WebPoint* point) { |
| 23 base::DictionaryValue* dict_value; | 25 base::DictionaryValue* dict_value; |
| 24 if (!value->GetAsDictionary(&dict_value)) | 26 if (!value->GetAsDictionary(&dict_value)) |
| 25 return false; | 27 return false; |
| 26 double x, y; | 28 double x, y; |
| 27 if (!dict_value->GetDouble("x", &x) || | 29 if (!dict_value->GetDouble("x", &x) || |
| 28 !dict_value->GetDouble("y", &y)) | 30 !dict_value->GetDouble("y", &y)) |
| 29 return false; | 31 return false; |
| 30 point->x = static_cast<int>(x); | 32 point->x = static_cast<int>(x); |
| 31 point->y = static_cast<int>(y); | 33 point->y = static_cast<int>(y); |
| 32 return true; | 34 return true; |
| 33 } | 35 } |
| 34 | 36 |
| 35 base::Value* CreateValueFrom(const WebPoint* point) { | 37 base::Value* CreateValueFrom(const WebPoint& point) { |
| 36 base::DictionaryValue* dict = new base::DictionaryValue(); | 38 base::DictionaryValue* dict = new base::DictionaryValue(); |
| 37 dict->SetInteger("x", point->x); | 39 dict->SetInteger("x", point.x); |
| 38 dict->SetInteger("y", point->y); | 40 dict->SetInteger("y", point.y); |
| 39 return dict; | 41 return dict; |
| 40 } | 42 } |
| 41 | 43 |
| 42 bool ParseFromValue(base::Value* value, WebSize* size) { | 44 bool ParseFromValue(base::Value* value, WebSize* size) { |
| 43 base::DictionaryValue* dict_value; | 45 base::DictionaryValue* dict_value; |
| 44 if (!value->GetAsDictionary(&dict_value)) | 46 if (!value->GetAsDictionary(&dict_value)) |
| 45 return false; | 47 return false; |
| 46 double width, height; | 48 double width, height; |
| 47 if (!dict_value->GetDouble("width", &width) || | 49 if (!dict_value->GetDouble("width", &width) || |
| 48 !dict_value->GetDouble("height", &height)) | 50 !dict_value->GetDouble("height", &height)) |
| 49 return false; | 51 return false; |
| 50 size->width = static_cast<int>(width); | 52 size->width = static_cast<int>(width); |
| 51 size->height = static_cast<int>(height); | 53 size->height = static_cast<int>(height); |
| 52 return true; | 54 return true; |
| 53 } | 55 } |
| 54 | 56 |
| 55 base::Value* CreateValueFrom(const WebSize* size) { | 57 base::Value* CreateValueFrom(const WebSize& size) { |
| 56 base::DictionaryValue* dict = new base::DictionaryValue(); | 58 base::DictionaryValue* dict = new base::DictionaryValue(); |
| 57 dict->SetInteger("width", size->width); | 59 dict->SetInteger("width", size.width); |
| 58 dict->SetInteger("height", size->height); | 60 dict->SetInteger("height", size.height); |
| 59 return dict; | 61 return dict; |
| 60 } | 62 } |
| 61 | 63 |
| 62 bool ParseFromValue(base::Value* value, WebRect* rect) { | 64 bool ParseFromValue(base::Value* value, WebRect* rect) { |
| 63 base::DictionaryValue* dict_value; | 65 base::DictionaryValue* dict_value; |
| 64 if (!value->GetAsDictionary(&dict_value)) | 66 if (!value->GetAsDictionary(&dict_value)) |
| 65 return false; | 67 return false; |
| 66 double x, y, width, height; | 68 double x, y, width, height; |
| 67 if (!dict_value->GetDouble("left", &x) || | 69 if (!dict_value->GetDouble("left", &x) || |
| 68 !dict_value->GetDouble("top", &y) || | 70 !dict_value->GetDouble("top", &y) || |
| 69 !dict_value->GetDouble("width", &width) || | 71 !dict_value->GetDouble("width", &width) || |
| 70 !dict_value->GetDouble("height", &height)) | 72 !dict_value->GetDouble("height", &height)) |
| 71 return false; | 73 return false; |
| 72 rect->origin.x = static_cast<int>(x); | 74 rect->origin.x = static_cast<int>(x); |
| 73 rect->origin.y = static_cast<int>(y); | 75 rect->origin.y = static_cast<int>(y); |
| 74 rect->size.width = static_cast<int>(width); | 76 rect->size.width = static_cast<int>(width); |
| 75 rect->size.height = static_cast<int>(height); | 77 rect->size.height = static_cast<int>(height); |
| 76 return true; | 78 return true; |
| 77 } | 79 } |
| 78 | 80 |
| 79 base::Value* CreateValueFrom(const WebRect* rect) { | 81 base::Value* CreateValueFrom(const WebRect& rect) { |
| 80 base::DictionaryValue* dict = new base::DictionaryValue(); | 82 base::DictionaryValue* dict = new base::DictionaryValue(); |
| 81 dict->SetInteger("left", rect->origin.x); | 83 dict->SetInteger("left", rect.X()); |
| 82 dict->SetInteger("top", rect->origin.y); | 84 dict->SetInteger("top", rect.Y()); |
| 83 dict->SetInteger("width", rect->size.width); | 85 dict->SetInteger("width", rect.Width()); |
| 84 dict->SetInteger("height", rect->size.height); | 86 dict->SetInteger("height", rect.Height()); |
| 85 return dict; | 87 return dict; |
| 86 } | 88 } |
| 87 | 89 |
| 88 Status CallAtomsJs( | 90 Status CallAtomsJs( |
| 89 Session* session, | 91 const std::string& frame, |
| 90 WebView* web_view, | 92 WebView* web_view, |
| 91 const char* const* atom_function, | 93 const char* const* atom_function, |
| 92 const base::ListValue& args, | 94 const base::ListValue& args, |
| 93 scoped_ptr<base::Value>* result) { | 95 scoped_ptr<base::Value>* result) { |
| 94 return web_view->CallFunction( | 96 return web_view->CallFunction( |
| 95 session->frame, webdriver::atoms::asString(atom_function), | 97 frame, webdriver::atoms::asString(atom_function), args, result); |
| 96 args, result); | 98 } |
| 99 |
| 100 Status VerifyElementClickable( |
| 101 const std::string& frame, |
| 102 WebView* web_view, |
| 103 const std::string& element_id, |
| 104 const WebPoint& location) { |
| 105 base::ListValue args; |
| 106 args.Append(CreateElement(element_id)); |
| 107 args.Append(CreateValueFrom(location)); |
| 108 scoped_ptr<base::Value> result; |
| 109 Status status = CallAtomsJs( |
| 110 frame, web_view, webdriver::atoms::IS_ELEMENT_CLICKABLE, |
| 111 args, &result); |
| 112 if (status.IsError()) |
| 113 return status; |
| 114 base::DictionaryValue* dict; |
| 115 bool is_clickable; |
| 116 if (!result->GetAsDictionary(&dict) || |
| 117 !dict->GetBoolean("clickable", &is_clickable)) |
| 118 return Status(kUnknownError, "fail to parse value of IS_ELEMENT_CLICKABLE"); |
| 119 |
| 120 if (!is_clickable) { |
| 121 std::string message; |
| 122 if (!dict->GetString("message", &message)) |
| 123 message = "element is not clickable"; |
| 124 return Status(kUnknownError, message); |
| 125 } |
| 126 return Status(kOk); |
| 127 } |
| 128 |
| 129 Status ScrollElementRegionIntoViewHelper( |
| 130 const std::string& frame, |
| 131 WebView* web_view, |
| 132 const std::string& element_id, |
| 133 const WebRect& region, |
| 134 bool center, |
| 135 bool verify_clickable, |
| 136 WebPoint* location) { |
| 137 WebPoint tmp_location = *location; |
| 138 base::ListValue args; |
| 139 args.Append(CreateElement(element_id)); |
| 140 args.AppendBoolean(center); |
| 141 args.Append(CreateValueFrom(region)); |
| 142 scoped_ptr<base::Value> result; |
| 143 Status status = web_view->CallFunction( |
| 144 frame, webdriver::atoms::asString(webdriver::atoms::GET_LOCATION_IN_VIEW), |
| 145 args, &result); |
| 146 if (status.IsError()) |
| 147 return status; |
| 148 if (!ParseFromValue(result.get(), &tmp_location)) |
| 149 return Status(kUnknownError, "fail to parse value of GET_LOCATION_IN_VIEW"); |
| 150 if (verify_clickable) { |
| 151 WebPoint middle = tmp_location; |
| 152 middle.Offset(region.Width() / 2, region.Height() / 2); |
| 153 status = VerifyElementClickable(frame, web_view, element_id, middle); |
| 154 if (status.IsError()) |
| 155 return status; |
| 156 } |
| 157 *location = tmp_location; |
| 158 return Status(kOk); |
| 159 } |
| 160 |
| 161 Status GetElementEffectiveStyle( |
| 162 const std::string& frame, |
| 163 WebView* web_view, |
| 164 const std::string& element_id, |
| 165 const std::string& property, |
| 166 std::string* value) { |
| 167 base::ListValue args; |
| 168 args.Append(CreateElement(element_id)); |
| 169 args.AppendString(property); |
| 170 scoped_ptr<base::Value> result; |
| 171 Status status = web_view->CallFunction( |
| 172 frame, webdriver::atoms::asString(webdriver::atoms::GET_EFFECTIVE_STYLE), |
| 173 args, &result); |
| 174 if (status.IsError()) |
| 175 return status; |
| 176 if (!result->GetAsString(value)) |
| 177 return Status(kUnknownError, "fail to parse value of GET_EFFECTIVE_STYLE"); |
| 178 return Status(kOk); |
| 179 } |
| 180 |
| 181 Status GetElementBorder( |
| 182 const std::string& frame, |
| 183 WebView* web_view, |
| 184 const std::string& element_id, |
| 185 int* border_left, |
| 186 int* border_top) { |
| 187 std::string border_left_str; |
| 188 Status status = GetElementEffectiveStyle( |
| 189 frame, web_view, element_id, "border-left-width", &border_left_str); |
| 190 if (status.IsError()) |
| 191 return status; |
| 192 std::string border_top_str; |
| 193 status = GetElementEffectiveStyle( |
| 194 frame, web_view, element_id, "border-top-width", &border_top_str); |
| 195 if (status.IsError()) |
| 196 return status; |
| 197 int border_left_tmp = -1; |
| 198 int border_top_tmp = -1; |
| 199 base::StringToInt(border_left_str, &border_left_tmp); |
| 200 base::StringToInt(border_top_str, &border_top_tmp); |
| 201 if (border_left_tmp == -1 || border_top_tmp == -1) |
| 202 return Status(kUnknownError, "fail to get border width of element"); |
| 203 *border_left = border_left_tmp; |
| 204 *border_top = border_top_tmp; |
| 205 return Status(kOk); |
| 97 } | 206 } |
| 98 | 207 |
| 99 } // namespace | 208 } // namespace |
| 100 | 209 |
| 101 base::DictionaryValue* CreateElement(const std::string& element_id) { | 210 base::DictionaryValue* CreateElement(const std::string& element_id) { |
| 102 base::DictionaryValue* element = new base::DictionaryValue(); | 211 base::DictionaryValue* element = new base::DictionaryValue(); |
| 103 element->SetString(kElementKey, element_id); | 212 element->SetString(kElementKey, element_id); |
| 104 return element; | 213 return element; |
| 105 } | 214 } |
| 106 | 215 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 128 locator->SetString(strategy, target); | 237 locator->SetString(strategy, target); |
| 129 base::ListValue arguments; | 238 base::ListValue arguments; |
| 130 arguments.Append(locator.release()); | 239 arguments.Append(locator.release()); |
| 131 if (root_element_id) | 240 if (root_element_id) |
| 132 arguments.Append(CreateElement(*root_element_id)); | 241 arguments.Append(CreateElement(*root_element_id)); |
| 133 | 242 |
| 134 base::Time start_time = base::Time::Now(); | 243 base::Time start_time = base::Time::Now(); |
| 135 while (true) { | 244 while (true) { |
| 136 scoped_ptr<base::Value> temp; | 245 scoped_ptr<base::Value> temp; |
| 137 Status status = web_view->CallFunction( | 246 Status status = web_view->CallFunction( |
| 138 session->frame, script, arguments, &temp); | 247 session->GetCurrentFrameId(), script, arguments, &temp); |
| 139 if (status.IsError()) | 248 if (status.IsError()) |
| 140 return status; | 249 return status; |
| 141 | 250 |
| 142 if (!temp->IsType(base::Value::TYPE_NULL)) { | 251 if (!temp->IsType(base::Value::TYPE_NULL)) { |
| 143 if (only_one) { | 252 if (only_one) { |
| 144 value->reset(temp.release()); | 253 value->reset(temp.release()); |
| 145 return Status(kOk); | 254 return Status(kOk); |
| 146 } else { | 255 } else { |
| 147 base::ListValue* result; | 256 base::ListValue* result; |
| 148 if (!temp->GetAsList(&result)) | 257 if (!temp->GetAsList(&result)) |
| (...skipping 24 matching lines...) Expand all Loading... |
| 173 Status GetElementAttribute( | 282 Status GetElementAttribute( |
| 174 Session* session, | 283 Session* session, |
| 175 WebView* web_view, | 284 WebView* web_view, |
| 176 const std::string& element_id, | 285 const std::string& element_id, |
| 177 const std::string& attribute_name, | 286 const std::string& attribute_name, |
| 178 scoped_ptr<base::Value>* value) { | 287 scoped_ptr<base::Value>* value) { |
| 179 base::ListValue args; | 288 base::ListValue args; |
| 180 args.Append(CreateElement(element_id)); | 289 args.Append(CreateElement(element_id)); |
| 181 args.AppendString(attribute_name); | 290 args.AppendString(attribute_name); |
| 182 return CallAtomsJs( | 291 return CallAtomsJs( |
| 183 session, web_view, webdriver::atoms::GET_ATTRIBUTE, args, value); | 292 session->GetCurrentFrameId(), web_view, webdriver::atoms::GET_ATTRIBUTE, |
| 293 args, value); |
| 184 } | 294 } |
| 185 | 295 |
| 186 Status IsElementAttributeEqualToIgnoreCase( | 296 Status IsElementAttributeEqualToIgnoreCase( |
| 187 Session* session, | 297 Session* session, |
| 188 WebView* web_view, | 298 WebView* web_view, |
| 189 const std::string& element_id, | 299 const std::string& element_id, |
| 190 const std::string& attribute_name, | 300 const std::string& attribute_name, |
| 191 const std::string& attribute_value, | 301 const std::string& attribute_value, |
| 192 bool* is_equal) { | 302 bool* is_equal) { |
| 193 scoped_ptr<base::Value> result; | 303 scoped_ptr<base::Value> result; |
| 194 Status status = GetElementAttribute( | 304 Status status = GetElementAttribute( |
| 195 session, web_view, element_id, attribute_name, &result); | 305 session, web_view, element_id, attribute_name, &result); |
| 196 if (status.IsError()) | 306 if (status.IsError()) |
| 197 return status; | 307 return status; |
| 198 std::string actual_value; | 308 std::string actual_value; |
| 199 if (result->GetAsString(&actual_value)) | 309 if (result->GetAsString(&actual_value)) |
| 200 *is_equal = LowerCaseEqualsASCII(actual_value, attribute_value.c_str()); | 310 *is_equal = LowerCaseEqualsASCII(actual_value, attribute_value.c_str()); |
| 201 else | 311 else |
| 202 *is_equal = false; | 312 *is_equal = false; |
| 203 return status; | 313 return status; |
| 204 } | 314 } |
| 205 | 315 |
| 206 Status GetElementClickableLocation( | 316 Status GetElementClickableLocation( |
| 207 Session* session, | 317 Session* session, |
| 208 WebView* web_view, | 318 WebView* web_view, |
| 209 const std::string& element_id, | 319 const std::string& element_id, |
| 210 WebPoint* location, | 320 WebPoint* location) { |
| 211 bool* is_clickable) { | |
| 212 bool is_displayed = false; | 321 bool is_displayed = false; |
| 213 Status status = IsElementDisplayed( | 322 Status status = IsElementDisplayed( |
| 214 session, web_view, element_id, true, &is_displayed); | 323 session, web_view, element_id, true, &is_displayed); |
| 215 if (status.IsError()) | 324 if (status.IsError()) |
| 216 return status; | 325 return status; |
| 217 if (!is_displayed) | 326 if (!is_displayed) |
| 218 return Status(kElementNotVisible); | 327 return Status(kElementNotVisible); |
| 219 | 328 |
| 220 WebRect rect; | 329 WebRect rect; |
| 221 status = GetElementRegion(session, web_view, element_id, &rect); | 330 status = GetElementRegion(session, web_view, element_id, &rect); |
| 222 if (status.IsError()) | 331 if (status.IsError()) |
| 223 return status; | 332 return status; |
| 224 | 333 |
| 225 status = ScrollElementRegionIntoView( | 334 status = ScrollElementRegionIntoView( |
| 226 session, web_view, element_id, rect, true, location); | 335 session, web_view, element_id, rect, |
| 336 true /* center */, true /* verify_clickable */, location); |
| 227 if (status.IsError()) | 337 if (status.IsError()) |
| 228 return status; | 338 return status; |
| 229 location->offset(rect.width() / 2, rect.height() / 2); | 339 location->Offset(rect.Width() / 2, rect.Height() / 2); |
| 230 if (is_clickable) { | |
| 231 return IsElementClickable( | |
| 232 session, web_view, element_id, location, is_clickable); | |
| 233 } | |
| 234 return Status(kOk); | 340 return Status(kOk); |
| 235 } | 341 } |
| 236 | 342 |
| 237 Status GetElementRegion( | 343 Status GetElementRegion( |
| 238 Session* session, | 344 Session* session, |
| 239 WebView* web_view, | 345 WebView* web_view, |
| 240 const std::string& element_id, | 346 const std::string& element_id, |
| 241 WebRect* rect) { | 347 WebRect* rect) { |
| 242 base::ListValue args; | 348 base::ListValue args; |
| 243 args.Append(CreateElement(element_id)); | 349 args.Append(CreateElement(element_id)); |
| 244 scoped_ptr<base::Value> result; | 350 scoped_ptr<base::Value> result; |
| 245 Status status = web_view->CallFunction( | 351 Status status = web_view->CallFunction( |
| 246 session->frame, kGetElementRegionScript, args, &result); | 352 session->GetCurrentFrameId(), kGetElementRegionScript, args, &result); |
| 247 if (status.IsError()) | 353 if (status.IsError()) |
| 248 return status; | 354 return status; |
| 249 if (!ParseFromValue(result.get(), rect)) { | 355 if (!ParseFromValue(result.get(), rect)) { |
| 250 return Status(kUnknownError, | 356 return Status(kUnknownError, |
| 251 "fail to parse value of getElementRegion"); | 357 "fail to parse value of getElementRegion"); |
| 252 } | 358 } |
| 253 return Status(kOk); | 359 return Status(kOk); |
| 254 } | 360 } |
| 255 | 361 |
| 256 Status GetElementTagName( | 362 Status GetElementTagName( |
| 257 Session* session, | 363 Session* session, |
| 258 WebView* web_view, | 364 WebView* web_view, |
| 259 const std::string& element_id, | 365 const std::string& element_id, |
| 260 std::string* name) { | 366 std::string* name) { |
| 261 base::ListValue args; | 367 base::ListValue args; |
| 262 args.Append(CreateElement(element_id)); | 368 args.Append(CreateElement(element_id)); |
| 263 scoped_ptr<base::Value> result; | 369 scoped_ptr<base::Value> result; |
| 264 Status status = web_view->CallFunction( | 370 Status status = web_view->CallFunction( |
| 265 session->frame, "function(elem) { return elem.tagName.toLowerCase(); }", | 371 session->GetCurrentFrameId(), |
| 372 "function(elem) { return elem.tagName.toLowerCase(); }", |
| 266 args, &result); | 373 args, &result); |
| 267 if (status.IsError()) | 374 if (status.IsError()) |
| 268 return status; | 375 return status; |
| 269 if (!result->GetAsString(name)) | 376 if (!result->GetAsString(name)) |
| 270 return Status(kUnknownError, "fail to get element tag name"); | 377 return Status(kUnknownError, "fail to get element tag name"); |
| 271 return Status(kOk); | 378 return Status(kOk); |
| 272 } | 379 } |
| 273 | 380 |
| 274 Status GetElementSize( | 381 Status GetElementSize( |
| 275 Session* session, | 382 Session* session, |
| 276 WebView* web_view, | 383 WebView* web_view, |
| 277 const std::string& element_id, | 384 const std::string& element_id, |
| 278 WebSize* size) { | 385 WebSize* size) { |
| 279 base::ListValue args; | 386 base::ListValue args; |
| 280 args.Append(CreateElement(element_id)); | 387 args.Append(CreateElement(element_id)); |
| 281 scoped_ptr<base::Value> result; | 388 scoped_ptr<base::Value> result; |
| 282 Status status = CallAtomsJs( | 389 Status status = CallAtomsJs( |
| 283 session, web_view, webdriver::atoms::GET_SIZE, args, &result); | 390 session->GetCurrentFrameId(), web_view, webdriver::atoms::GET_SIZE, |
| 391 args, &result); |
| 284 if (status.IsError()) | 392 if (status.IsError()) |
| 285 return status; | 393 return status; |
| 286 if (!ParseFromValue(result.get(), size)) | 394 if (!ParseFromValue(result.get(), size)) |
| 287 return Status(kUnknownError, "fail to parse value of GET_SIZE"); | 395 return Status(kUnknownError, "fail to parse value of GET_SIZE"); |
| 288 return Status(kOk); | 396 return Status(kOk); |
| 289 } | 397 } |
| 290 | 398 |
| 291 Status IsElementClickable( | |
| 292 Session* session, | |
| 293 WebView* web_view, | |
| 294 const std::string& element_id, | |
| 295 WebPoint* location, | |
| 296 bool* is_clickable) { | |
| 297 base::ListValue args; | |
| 298 args.Append(CreateElement(element_id)); | |
| 299 args.Append(CreateValueFrom(location)); | |
| 300 scoped_ptr<base::Value> result; | |
| 301 Status status = CallAtomsJs( | |
| 302 session, web_view, webdriver::atoms::IS_ELEMENT_CLICKABLE, args, &result); | |
| 303 if (status.IsError()) | |
| 304 return status; | |
| 305 base::DictionaryValue* dict; | |
| 306 if (!result->GetAsDictionary(&dict) || | |
| 307 !dict->GetBoolean("clickable", is_clickable)) | |
| 308 return Status(kUnknownError, "fail to parse value of IS_ELEMENT_CLICKABLE"); | |
| 309 | |
| 310 if (!*is_clickable) { | |
| 311 std::string message; | |
| 312 if (!dict->GetString("message", &message)) | |
| 313 message = "element is not clickable"; | |
| 314 return Status(kOk, message); | |
| 315 } | |
| 316 return Status(kOk); | |
| 317 } | |
| 318 | |
| 319 Status IsElementDisplayed( | 399 Status IsElementDisplayed( |
| 320 Session* session, | 400 Session* session, |
| 321 WebView* web_view, | 401 WebView* web_view, |
| 322 const std::string& element_id, | 402 const std::string& element_id, |
| 323 bool ignore_opacity, | 403 bool ignore_opacity, |
| 324 bool* is_displayed) { | 404 bool* is_displayed) { |
| 325 base::ListValue args; | 405 base::ListValue args; |
| 326 args.Append(CreateElement(element_id)); | 406 args.Append(CreateElement(element_id)); |
| 327 args.AppendBoolean(ignore_opacity); | 407 args.AppendBoolean(ignore_opacity); |
| 328 scoped_ptr<base::Value> result; | 408 scoped_ptr<base::Value> result; |
| 329 Status status = CallAtomsJs( | 409 Status status = CallAtomsJs( |
| 330 session, web_view, webdriver::atoms::IS_DISPLAYED, args, &result); | 410 session->GetCurrentFrameId(), web_view, webdriver::atoms::IS_DISPLAYED, |
| 411 args, &result); |
| 331 if (status.IsError()) | 412 if (status.IsError()) |
| 332 return status; | 413 return status; |
| 333 if (!result->GetAsBoolean(is_displayed)) | 414 if (!result->GetAsBoolean(is_displayed)) |
| 334 return Status(kUnknownError, "IS_DISPLAYED should return a boolean value"); | 415 return Status(kUnknownError, "IS_DISPLAYED should return a boolean value"); |
| 335 return Status(kOk); | 416 return Status(kOk); |
| 336 } | 417 } |
| 337 | 418 |
| 338 Status IsElementEnabled( | 419 Status IsElementEnabled( |
| 339 Session* session, | 420 Session* session, |
| 340 WebView* web_view, | 421 WebView* web_view, |
| 341 const std::string& element_id, | 422 const std::string& element_id, |
| 342 bool* is_enabled) { | 423 bool* is_enabled) { |
| 343 base::ListValue args; | 424 base::ListValue args; |
| 344 args.Append(CreateElement(element_id)); | 425 args.Append(CreateElement(element_id)); |
| 345 scoped_ptr<base::Value> result; | 426 scoped_ptr<base::Value> result; |
| 346 Status status = CallAtomsJs( | 427 Status status = CallAtomsJs( |
| 347 session, web_view, webdriver::atoms::IS_ENABLED, args, &result); | 428 session->GetCurrentFrameId(), web_view, webdriver::atoms::IS_ENABLED, |
| 429 args, &result); |
| 348 if (status.IsError()) | 430 if (status.IsError()) |
| 349 return status; | 431 return status; |
| 350 if (!result->GetAsBoolean(is_enabled)) | 432 if (!result->GetAsBoolean(is_enabled)) |
| 351 return Status(kUnknownError, "IS_ENABLED should return a boolean value"); | 433 return Status(kUnknownError, "IS_ENABLED should return a boolean value"); |
| 352 return Status(kOk); | 434 return Status(kOk); |
| 353 } | 435 } |
| 354 | 436 |
| 355 Status IsOptionElementSelected( | 437 Status IsOptionElementSelected( |
| 356 Session* session, | 438 Session* session, |
| 357 WebView* web_view, | 439 WebView* web_view, |
| 358 const std::string& element_id, | 440 const std::string& element_id, |
| 359 bool* is_selected) { | 441 bool* is_selected) { |
| 360 base::ListValue args; | 442 base::ListValue args; |
| 361 args.Append(CreateElement(element_id)); | 443 args.Append(CreateElement(element_id)); |
| 362 scoped_ptr<base::Value> result; | 444 scoped_ptr<base::Value> result; |
| 363 Status status = CallAtomsJs( | 445 Status status = CallAtomsJs( |
| 364 session, web_view, webdriver::atoms::IS_SELECTED, args, &result); | 446 session->GetCurrentFrameId(), web_view, webdriver::atoms::IS_SELECTED, |
| 447 args, &result); |
| 365 if (status.IsError()) | 448 if (status.IsError()) |
| 366 return status; | 449 return status; |
| 367 if (!result->GetAsBoolean(is_selected)) | 450 if (!result->GetAsBoolean(is_selected)) |
| 368 return Status(kUnknownError, "IS_SELECTED should return a boolean value"); | 451 return Status(kUnknownError, "IS_SELECTED should return a boolean value"); |
| 369 return Status(kOk); | 452 return Status(kOk); |
| 370 } | 453 } |
| 371 | 454 |
| 372 Status IsOptionElementTogglable( | 455 Status IsOptionElementTogglable( |
| 373 Session* session, | 456 Session* session, |
| 374 WebView* web_view, | 457 WebView* web_view, |
| 375 const std::string& element_id, | 458 const std::string& element_id, |
| 376 bool* is_togglable) { | 459 bool* is_togglable) { |
| 377 base::ListValue args; | 460 base::ListValue args; |
| 378 args.Append(CreateElement(element_id)); | 461 args.Append(CreateElement(element_id)); |
| 379 scoped_ptr<base::Value> result; | 462 scoped_ptr<base::Value> result; |
| 380 Status status = web_view->CallFunction( | 463 Status status = web_view->CallFunction( |
| 381 session->frame, kIsOptionElementToggleableScript, args, &result); | 464 session->GetCurrentFrameId(), kIsOptionElementToggleableScript, |
| 465 args, &result); |
| 382 if (status.IsError()) | 466 if (status.IsError()) |
| 383 return status; | 467 return status; |
| 384 if (!result->GetAsBoolean(is_togglable)) | 468 if (!result->GetAsBoolean(is_togglable)) |
| 385 return Status(kUnknownError, "fail check if option togglable or not"); | 469 return Status(kUnknownError, "fail check if option togglable or not"); |
| 386 return Status(kOk); | 470 return Status(kOk); |
| 387 } | 471 } |
| 388 | 472 |
| 389 Status SetOptionElementSelected( | 473 Status SetOptionElementSelected( |
| 390 Session* session, | 474 Session* session, |
| 391 WebView* web_view, | 475 WebView* web_view, |
| 392 const std::string& element_id, | 476 const std::string& element_id, |
| 393 bool selected) { | 477 bool selected) { |
| 394 // TODO(171034): need to fix throwing error if an alert is triggered. | 478 // TODO(171034): need to fix throwing error if an alert is triggered. |
| 395 base::ListValue args; | 479 base::ListValue args; |
| 396 args.Append(CreateElement(element_id)); | 480 args.Append(CreateElement(element_id)); |
| 397 args.AppendBoolean(selected); | 481 args.AppendBoolean(selected); |
| 398 scoped_ptr<base::Value> result; | 482 scoped_ptr<base::Value> result; |
| 399 return CallAtomsJs( | 483 return CallAtomsJs( |
| 400 session, web_view, webdriver::atoms::CLICK, args, &result); | 484 session->GetCurrentFrameId(), web_view, webdriver::atoms::CLICK, |
| 485 args, &result); |
| 401 } | 486 } |
| 402 | 487 |
| 403 Status ToggleOptionElement( | 488 Status ToggleOptionElement( |
| 404 Session* session, | 489 Session* session, |
| 405 WebView* web_view, | 490 WebView* web_view, |
| 406 const std::string& element_id) { | 491 const std::string& element_id) { |
| 407 bool is_selected; | 492 bool is_selected; |
| 408 Status status = IsOptionElementSelected( | 493 Status status = IsOptionElementSelected( |
| 409 session, web_view, element_id, &is_selected); | 494 session, web_view, element_id, &is_selected); |
| 410 if (status.IsError()) | 495 if (status.IsError()) |
| 411 return status; | 496 return status; |
| 412 return SetOptionElementSelected(session, web_view, element_id, !is_selected); | 497 return SetOptionElementSelected(session, web_view, element_id, !is_selected); |
| 413 } | 498 } |
| 414 | 499 |
| 415 Status ScrollElementIntoView( | 500 Status ScrollElementIntoView( |
| 416 Session* session, | 501 Session* session, |
| 417 WebView* web_view, | 502 WebView* web_view, |
| 418 const std::string& id, | 503 const std::string& id, |
| 419 WebPoint* location) { | 504 WebPoint* location) { |
| 420 WebSize size; | 505 WebSize size; |
| 421 Status status = GetElementSize(session, web_view, id, &size); | 506 Status status = GetElementSize(session, web_view, id, &size); |
| 422 if (status.IsError()) | 507 if (status.IsError()) |
| 423 return status; | 508 return status; |
| 424 return ScrollElementRegionIntoView( | 509 return ScrollElementRegionIntoView( |
| 425 session, web_view, id, WebRect(WebPoint(0, 0), size), false, location); | 510 session, web_view, id, WebRect(WebPoint(0, 0), size), |
| 511 false /* center */, false /* verify_clickable */, location); |
| 426 } | 512 } |
| 427 | 513 |
| 428 Status ScrollElementRegionIntoView( | 514 Status ScrollElementRegionIntoView( |
| 429 Session* session, | 515 Session* session, |
| 430 WebView* web_view, | 516 WebView* web_view, |
| 431 const std::string& element_id, | 517 const std::string& element_id, |
| 432 const WebRect& region, | 518 const WebRect& region, |
| 433 bool center, | 519 bool center, |
| 520 bool verify_clickable, |
| 434 WebPoint* location) { | 521 WebPoint* location) { |
| 435 WebPoint region_offset = region.origin; | 522 WebPoint region_offset = region.origin; |
| 436 base::ListValue args; | 523 WebSize region_size = region.size; |
| 437 args.Append(CreateElement(element_id)); | 524 Status status = ScrollElementRegionIntoViewHelper( |
| 438 args.AppendBoolean(center); | 525 session->GetCurrentFrameId(), web_view, element_id, region, |
| 439 args.Append(CreateValueFrom(®ion)); | 526 center, verify_clickable, ®ion_offset); |
| 440 scoped_ptr<base::Value> result; | |
| 441 | |
| 442 // TODO(chrisgao): Nested frame. See http://crbug.com/170998. | |
| 443 Status status = CallAtomsJs( | |
| 444 session, web_view, webdriver::atoms::GET_LOCATION_IN_VIEW, args, &result); | |
| 445 if (status.IsError()) | 527 if (status.IsError()) |
| 446 return status; | 528 return status; |
| 447 if (!ParseFromValue(result.get(), ®ion_offset)) | 529 const char* kFindSubFrameScript = |
| 448 return Status(kUnknownError, "fail to parse value of GET_LOCATION_IN_VIEW"); | 530 "function(xpath) {" |
| 531 " return document.evaluate(xpath, document, null," |
| 532 " XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;" |
| 533 "}"; |
| 534 for (std::list<FrameInfo>::reverse_iterator rit = session->frames.rbegin(); |
| 535 rit != session->frames.rend(); ++rit) { |
| 536 base::ListValue args; |
| 537 args.AppendString( |
| 538 base::StringPrintf("//*[@cd_frame_id_ = '%s']", |
| 539 rit->chromedriver_frame_id.c_str())); |
| 540 scoped_ptr<base::Value> result; |
| 541 status = web_view->CallFunction( |
| 542 rit->parent_frame_id, kFindSubFrameScript, args, &result); |
| 543 if (status.IsError()) |
| 544 return status; |
| 545 const base::DictionaryValue* element_dict; |
| 546 if (!result->GetAsDictionary(&element_dict)) |
| 547 return Status(kUnknownError, "no element reference returned by script"); |
| 548 std::string frame_element_id; |
| 549 if (!element_dict->GetString(kElementKey, &frame_element_id)) |
| 550 return Status(kUnknownError, "fail to locate a sub frame"); |
| 551 |
| 552 // Modify |region_offset| by the frame's border. |
| 553 int border_left = -1; |
| 554 int border_top = -1; |
| 555 status = GetElementBorder( |
| 556 rit->parent_frame_id, web_view, frame_element_id, |
| 557 &border_left, &border_top); |
| 558 if (status.IsError()) |
| 559 return status; |
| 560 region_offset.Offset(border_left, border_top); |
| 561 |
| 562 status = ScrollElementRegionIntoViewHelper( |
| 563 rit->parent_frame_id, web_view, frame_element_id, |
| 564 WebRect(region_offset, region_size), |
| 565 center, verify_clickable, ®ion_offset); |
| 566 if (status.IsError()) |
| 567 return status; |
| 568 } |
| 449 *location = region_offset; | 569 *location = region_offset; |
| 450 return Status(kOk); | 570 return Status(kOk); |
| 451 } | 571 } |
| OLD | NEW |