Home | History | Annotate | Download | only in client
      1 # Copyright 2013 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 import command_executor
      6 from command_executor import Command
      7 from webelement import WebElement
      8 
      9 
     10 class ChromeDriverException(Exception):
     11   pass
     12 class NoSuchElement(ChromeDriverException):
     13   pass
     14 class NoSuchFrame(ChromeDriverException):
     15   pass
     16 class UnknownCommand(ChromeDriverException):
     17   pass
     18 class StaleElementReference(ChromeDriverException):
     19   pass
     20 class UnknownError(ChromeDriverException):
     21   pass
     22 class JavaScriptError(ChromeDriverException):
     23   pass
     24 class XPathLookupError(ChromeDriverException):
     25   pass
     26 class NoSuchWindow(ChromeDriverException):
     27   pass
     28 class InvalidCookieDomain(ChromeDriverException):
     29   pass
     30 class ScriptTimeout(ChromeDriverException):
     31   pass
     32 class InvalidSelector(ChromeDriverException):
     33   pass
     34 class SessionNotCreatedException(ChromeDriverException):
     35   pass
     36 class NoSuchSession(ChromeDriverException):
     37   pass
     38 
     39 def _ExceptionForResponse(response):
     40   exception_class_map = {
     41     7: NoSuchElement,
     42     8: NoSuchFrame,
     43     9: UnknownCommand,
     44     10: StaleElementReference,
     45     13: UnknownError,
     46     17: JavaScriptError,
     47     19: XPathLookupError,
     48     23: NoSuchWindow,
     49     24: InvalidCookieDomain,
     50     28: ScriptTimeout,
     51     32: InvalidSelector,
     52     33: SessionNotCreatedException,
     53     100: NoSuchSession
     54   }
     55   status = response['status']
     56   msg = response['value']['message']
     57   return exception_class_map.get(status, ChromeDriverException)(msg)
     58 
     59 
     60 class ChromeDriver(object):
     61   """Starts and controls a single Chrome instance on this machine."""
     62 
     63   def __init__(self, server_url, chrome_binary=None, android_package=None,
     64                chrome_switches=None, chrome_extensions=None,
     65                chrome_log_path=None):
     66     self._executor = command_executor.CommandExecutor(server_url)
     67 
     68     options = {}
     69     if android_package:
     70       options['androidPackage'] = android_package
     71     elif chrome_binary:
     72       options['binary'] = chrome_binary
     73 
     74     if chrome_switches:
     75       assert type(chrome_switches) is list
     76       options['args'] = chrome_switches
     77 
     78     if chrome_extensions:
     79       assert type(chrome_extensions) is list
     80       options['extensions'] = chrome_extensions
     81 
     82     if chrome_log_path:
     83       assert type(chrome_log_path) is str
     84       options['logPath'] = chrome_log_path
     85 
     86     params = {
     87       'desiredCapabilities': {
     88         'chromeOptions': options
     89       }
     90     }
     91 
     92     self._session_id = self._executor.Execute(
     93         Command.NEW_SESSION, params)['sessionId']
     94 
     95   def _WrapValue(self, value):
     96     """Wrap value from client side for chromedriver side."""
     97     if isinstance(value, dict):
     98       converted = {}
     99       for key, val in value.items():
    100         converted[key] = self._WrapValue(val)
    101       return converted
    102     elif isinstance(value, WebElement):
    103       return {'ELEMENT': value._id}
    104     elif isinstance(value, list):
    105       return list(self._WrapValue(item) for item in value)
    106     else:
    107       return value
    108 
    109   def _UnwrapValue(self, value):
    110     """Unwrap value from chromedriver side for client side."""
    111     if isinstance(value, dict):
    112       if (len(value) == 1 and 'ELEMENT' in value
    113           and isinstance(value['ELEMENT'], basestring)):
    114         return WebElement(self, value['ELEMENT'])
    115       else:
    116         unwraped = {}
    117         for key, val in value.items():
    118           unwraped[key] = self._UnwrapValue(val)
    119         return unwraped
    120     elif isinstance(value, list):
    121       return list(self._UnwrapValue(item) for item in value)
    122     else:
    123       return value
    124 
    125   def ExecuteCommand(self, command, params={}):
    126     params['sessionId'] = self._session_id
    127     params = self._WrapValue(params)
    128     response = self._executor.Execute(command, params)
    129     if response['status'] != 0:
    130       raise _ExceptionForResponse(response)
    131     return self._UnwrapValue(response['value'])
    132 
    133   def GetWindowHandles(self):
    134     return self.ExecuteCommand(Command.GET_WINDOW_HANDLES)
    135 
    136   def SwitchToWindow(self, handle_or_name):
    137     self.ExecuteCommand(Command.SWITCH_TO_WINDOW, {'name': handle_or_name})
    138 
    139   def GetCurrentWindowHandle(self):
    140     return self.ExecuteCommand(Command.GET_CURRENT_WINDOW_HANDLE)
    141 
    142   def CloseWindow(self):
    143     self.ExecuteCommand(Command.CLOSE)
    144 
    145   def Load(self, url):
    146     self.ExecuteCommand(Command.GET, {'url': url})
    147 
    148   def ExecuteScript(self, script, *args):
    149     converted_args = list(args)
    150     return self.ExecuteCommand(
    151         Command.EXECUTE_SCRIPT, {'script': script, 'args': converted_args})
    152 
    153   def ExecuteAsyncScript(self, script, *args):
    154     converted_args = list(args)
    155     return self.ExecuteCommand(
    156         Command.EXECUTE_ASYNC_SCRIPT,
    157         {'script': script, 'args': converted_args})
    158 
    159   def SwitchToFrame(self, id_or_name):
    160     self.ExecuteCommand(Command.SWITCH_TO_FRAME, {'id': id_or_name})
    161 
    162   def SwitchToFrameByIndex(self, index):
    163     self.SwitchToFrame(index)
    164 
    165   def SwitchToMainFrame(self):
    166     self.SwitchToFrame(None)
    167 
    168   def GetTitle(self):
    169     return self.ExecuteCommand(Command.GET_TITLE)
    170 
    171   def GetPageSource(self):
    172     return self.ExecuteCommand(Command.GET_PAGE_SOURCE)
    173 
    174   def FindElement(self, strategy, target):
    175     return self.ExecuteCommand(
    176         Command.FIND_ELEMENT, {'using': strategy, 'value': target})
    177 
    178   def FindElements(self, strategy, target):
    179     return self.ExecuteCommand(
    180         Command.FIND_ELEMENTS, {'using': strategy, 'value': target})
    181 
    182   def SetTimeout(self, type, timeout):
    183     return self.ExecuteCommand(
    184         Command.SET_TIMEOUT, {'type' : type, 'ms': timeout})
    185 
    186   def GetCurrentUrl(self):
    187     return self.ExecuteCommand(Command.GET_CURRENT_URL)
    188 
    189   def GoBack(self):
    190     return self.ExecuteCommand(Command.GO_BACK)
    191 
    192   def GoForward(self):
    193     return self.ExecuteCommand(Command.GO_FORWARD)
    194 
    195   def Refresh(self):
    196     return self.ExecuteCommand(Command.REFRESH)
    197 
    198   def MouseMoveTo(self, element=None, x_offset=None, y_offset=None):
    199     params = {}
    200     if element is not None:
    201       params['element'] = element._id
    202     if x_offset is not None:
    203       params['xoffset'] = x_offset
    204     if y_offset is not None:
    205       params['yoffset'] = y_offset
    206     self.ExecuteCommand(Command.MOUSE_MOVE_TO, params)
    207 
    208   def MouseClick(self, button=0):
    209     self.ExecuteCommand(Command.MOUSE_CLICK, {'button': button})
    210 
    211   def MouseButtonDown(self, button=0):
    212     self.ExecuteCommand(Command.MOUSE_BUTTON_DOWN, {'button': button})
    213 
    214   def MouseButtonUp(self, button=0):
    215     self.ExecuteCommand(Command.MOUSE_BUTTON_UP, {'button': button})
    216 
    217   def MouseDoubleClick(self, button=0):
    218     self.ExecuteCommand(Command.MOUSE_DOUBLE_CLICK, {'button': button})
    219 
    220   def GetCookies(self):
    221     return self.ExecuteCommand(Command.GET_COOKIES)
    222 
    223   def AddCookie(self, cookie):
    224     self.ExecuteCommand(Command.ADD_COOKIE, {'cookie': cookie})
    225 
    226   def DeleteCookie(self, name):
    227     self.ExecuteCommand(Command.DELETE_COOKIE, {'name': name})
    228 
    229   def DeleteAllCookies(self):
    230     self.ExecuteCommand(Command.DELETE_ALL_COOKIES)
    231 
    232   def IsAlertOpen(self):
    233     return self.ExecuteCommand(Command.GET_ALERT)
    234 
    235   def GetAlertMessage(self):
    236     return self.ExecuteCommand(Command.GET_ALERT_TEXT)
    237 
    238   def HandleAlert(self, accept, prompt_text=''):
    239     if prompt_text:
    240       self.ExecuteCommand(Command.SET_ALERT_VALUE, {'text': prompt_text})
    241     if accept:
    242       cmd = Command.ACCEPT_ALERT
    243     else:
    244       cmd = Command.DISMISS_ALERT
    245     self.ExecuteCommand(cmd)
    246 
    247   def IsLoading(self):
    248     return self.ExecuteCommand(Command.IS_LOADING)
    249 
    250   def GetWindowPosition(self):
    251     position = self.ExecuteCommand(Command.GET_WINDOW_POSITION,
    252                                    {'windowHandle': 'current'})
    253     return [position['x'], position['y']]
    254 
    255   def SetWindowPosition(self, x, y):
    256     self.ExecuteCommand(Command.SET_WINDOW_POSITION,
    257                         {'windowHandle': 'current', 'x': x, 'y': y})
    258 
    259   def GetWindowSize(self):
    260     size = self.ExecuteCommand(Command.GET_WINDOW_SIZE,
    261                                {'windowHandle': 'current'})
    262     return [size['width'], size['height']]
    263 
    264   def SetWindowSize(self, width, height):
    265     self.ExecuteCommand(
    266         Command.SET_WINDOW_SIZE,
    267         {'windowHandle': 'current', 'width': width, 'height': height})
    268 
    269   def MaximizeWindow(self):
    270     self.ExecuteCommand(Command.MAXIMIZE_WINDOW, {'windowHandle': 'current'})
    271 
    272   def Quit(self):
    273     """Quits the browser and ends the session."""
    274     self.ExecuteCommand(Command.QUIT)
    275