Home | History | Annotate | Download | only in commands
      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