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 3 // found in the LICENSE file. 4 5 #include "chrome/test/webdriver/commands/mouse_commands.h" 6 7 #include "base/values.h" 8 #include "chrome/common/automation_constants.h" 9 #include "chrome/test/automation/value_conversion_util.h" 10 #include "chrome/test/webdriver/commands/response.h" 11 #include "chrome/test/webdriver/webdriver_basic_types.h" 12 #include "chrome/test/webdriver/webdriver_element_id.h" 13 #include "chrome/test/webdriver/webdriver_error.h" 14 #include "chrome/test/webdriver/webdriver_session.h" 15 #include "chrome/test/webdriver/webdriver_util.h" 16 17 namespace { 18 19 const int kLeftButton = 0; 20 const int kMiddleButton = 1; 21 const int kRightButton = 2; 22 23 } // namespace 24 25 namespace webdriver { 26 27 MoveAndClickCommand::MoveAndClickCommand( 28 const std::vector<std::string>& path_segments, 29 const DictionaryValue* const parameters) 30 : WebElementCommand(path_segments, parameters) {} 31 32 MoveAndClickCommand::~MoveAndClickCommand() {} 33 34 bool MoveAndClickCommand::DoesPost() { 35 return true; 36 } 37 38 void MoveAndClickCommand::ExecutePost(Response* response) { 39 std::string tag_name; 40 Error* error = session_->GetElementTagName( 41 session_->current_target(), element, &tag_name); 42 if (error) { 43 response->SetError(error); 44 return; 45 } 46 47 if (tag_name == "option") { 48 const char* kCanOptionBeToggledScript = 49 "function(option) {" 50 " for (var parent = option.parentElement;" 51 " parent;" 52 " parent = parent.parentElement) {" 53 " if (parent.tagName.toLowerCase() == 'select') {" 54 " return parent.multiple;" 55 " }" 56 " }" 57 " throw new Error('Option element is not in a select');" 58 "}"; 59 bool can_be_toggled; 60 error = session_->ExecuteScriptAndParse( 61 session_->current_target(), 62 kCanOptionBeToggledScript, 63 "canOptionBeToggled", 64 CreateListValueFrom(element), 65 CreateDirectValueParser(&can_be_toggled)); 66 if (error) { 67 response->SetError(error); 68 return; 69 } 70 71 if (can_be_toggled) { 72 error = session_->ToggleOptionElement( 73 session_->current_target(), element); 74 } else { 75 error = session_->SetOptionElementSelected( 76 session_->current_target(), element, true); 77 } 78 } else { 79 Point location; 80 error = session_->GetClickableLocation(element, &location); 81 if (!error) 82 error = session_->MouseMoveAndClick(location, automation::kLeftButton); 83 } 84 if (error) { 85 response->SetError(error); 86 return; 87 } 88 } 89 90 HoverCommand::HoverCommand(const std::vector<std::string>& path_segments, 91 const DictionaryValue* const parameters) 92 : WebElementCommand(path_segments, parameters) {} 93 94 HoverCommand::~HoverCommand() {} 95 96 bool HoverCommand::DoesPost() { 97 return true; 98 } 99 100 void HoverCommand::ExecutePost(Response* response) { 101 Error* error = NULL; 102 Point location; 103 error = session_->GetClickableLocation(element, &location); 104 if (!error) 105 error = session_->MouseMove(location); 106 if (error) { 107 response->SetError(error); 108 return; 109 } 110 } 111 112 DragCommand::DragCommand(const std::vector<std::string>& path_segments, 113 const DictionaryValue* const parameters) 114 : WebElementCommand(path_segments, parameters) {} 115 116 DragCommand::~DragCommand() {} 117 118 bool DragCommand::Init(Response* const response) { 119 if (!WebElementCommand::Init(response)) 120 return false; 121 122 if (!GetIntegerParameter("x", &drag_x_) || 123 !GetIntegerParameter("y", &drag_y_)) { 124 response->SetError(new Error(kBadRequest, "Missing (x,y) coordinates")); 125 return false; 126 } 127 128 return true; 129 } 130 131 bool DragCommand::DoesPost() { 132 return true; 133 } 134 135 void DragCommand::ExecutePost(Response* response) { 136 Error* error = NULL; 137 Point drag_from; 138 error = session_->GetClickableLocation(element, &drag_from); 139 if (error) { 140 response->SetError(error); 141 return; 142 } 143 144 Point drag_to(drag_from); 145 drag_to.Offset(drag_x_, drag_y_); 146 if (drag_to.x() < 0 || drag_to.y() < 0) 147 error = new Error(kBadRequest, "Invalid (x,y) coordinates"); 148 if (!error) 149 error = session_->MouseDrag(drag_from, drag_to); 150 151 if (error) { 152 response->SetError(error); 153 return; 154 } 155 } 156 157 AdvancedMouseCommand::AdvancedMouseCommand( 158 const std::vector<std::string>& path_segments, 159 const DictionaryValue* const parameters) 160 : WebDriverCommand(path_segments, parameters) {} 161 162 AdvancedMouseCommand::~AdvancedMouseCommand() {} 163 164 bool AdvancedMouseCommand::DoesPost() { 165 return true; 166 } 167 168 MoveToCommand::MoveToCommand( 169 const std::vector<std::string>& path_segments, 170 const DictionaryValue* const parameters) 171 : AdvancedMouseCommand(path_segments, parameters), has_element_(false), 172 has_offset_(false), x_offset_(0), y_offset_(0) {} 173 174 MoveToCommand::~MoveToCommand() {} 175 176 bool MoveToCommand::Init(Response* const response) { 177 if (!AdvancedMouseCommand::Init(response)) 178 return false; 179 180 std::string element_name; 181 has_element_ = GetStringParameter("element", &element_name); 182 183 if (has_element_) { 184 element_ = ElementId(element_name); 185 } 186 187 has_offset_ = GetIntegerParameter("xoffset", &x_offset_) && 188 GetIntegerParameter("yoffset", &y_offset_); 189 190 if (!has_element_ && !has_offset_) { 191 response->SetError(new Error( 192 kBadRequest, "Invalid command arguments")); 193 return false; 194 } 195 196 return true; 197 } 198 199 void MoveToCommand::ExecutePost(Response* const response) { 200 Point location; 201 Error* error; 202 203 if (has_element_) { 204 // If an element is specified, calculate the coordinate. 205 error = session_->GetElementLocationInView(element_, &location); 206 if (error) { 207 response->SetError(error); 208 return; 209 } 210 } else { 211 // If not, use the current mouse position. 212 location = session_->get_mouse_position(); 213 } 214 215 if (has_offset_) { 216 // If an offset is specified, translate by the offset. 217 location.Offset(x_offset_, y_offset_); 218 } else { 219 DCHECK(has_element_); 220 221 // If not, calculate the half of the element size and translate by it. 222 Size size; 223 error = session_->GetElementSize(session_->current_target(), 224 element_, &size); 225 if (error) { 226 response->SetError(error); 227 return; 228 } 229 230 location.Offset(size.width() / 2, size.height() / 2); 231 } 232 233 error = session_->MouseMove(location); 234 if (error) { 235 response->SetError(error); 236 return; 237 } 238 } 239 240 ClickCommand::ClickCommand(const std::vector<std::string>& path_segments, 241 const DictionaryValue* const parameters) 242 : AdvancedMouseCommand(path_segments, parameters) {} 243 244 ClickCommand::~ClickCommand() {} 245 246 bool ClickCommand::Init(Response* const response) { 247 if (!AdvancedMouseCommand::Init(response)) 248 return false; 249 250 if (!GetIntegerParameter("button", &button_)) { 251 response->SetError(new Error(kBadRequest, "Missing mouse button argument")); 252 return false; 253 } 254 255 return true; 256 } 257 258 void ClickCommand::ExecutePost(Response* const response) { 259 // Convert the button argument to a constant value in automation. 260 automation::MouseButton button; 261 if (button_ == kLeftButton) { 262 button = automation::kLeftButton; 263 } else if (button_ == kMiddleButton) { 264 button = automation::kMiddleButton; 265 } else if (button_ == kRightButton) { 266 button = automation::kRightButton; 267 } else { 268 response->SetError(new Error(kBadRequest, "Invalid mouse button")); 269 return; 270 } 271 272 Error* error = session_->MouseClick(button); 273 if (error) { 274 response->SetError(error); 275 return; 276 } 277 } 278 279 ButtonDownCommand::ButtonDownCommand( 280 const std::vector<std::string>& path_segments, 281 const DictionaryValue* const parameters) 282 : AdvancedMouseCommand(path_segments, parameters) {} 283 284 ButtonDownCommand::~ButtonDownCommand() {} 285 286 void ButtonDownCommand::ExecutePost(Response* const response) { 287 session_->MouseButtonDown(); 288 } 289 290 ButtonUpCommand::ButtonUpCommand(const std::vector<std::string>& path_segments, 291 const DictionaryValue* const parameters) 292 : AdvancedMouseCommand(path_segments, parameters) {} 293 294 ButtonUpCommand::~ButtonUpCommand() {} 295 296 void ButtonUpCommand::ExecutePost(Response* const response) { 297 session_->MouseButtonUp(); 298 } 299 300 DoubleClickCommand::DoubleClickCommand( 301 const std::vector<std::string>& path_segments, 302 const DictionaryValue* const parameters) 303 : AdvancedMouseCommand(path_segments, parameters) {} 304 305 DoubleClickCommand::~DoubleClickCommand() {} 306 307 void DoubleClickCommand::ExecutePost(Response* const response) { 308 Error* error = session_->MouseDoubleClick(); 309 if (error) { 310 response->SetError(error); 311 return; 312 } 313 } 314 315 } // namespace webdriver 316