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     6: NoSuchSession,
     42     7: NoSuchElement,
     43     8: NoSuchFrame,
     44     9: UnknownCommand,
     45     10: StaleElementReference,
     46     13: UnknownError,
     47     17: JavaScriptError,
     48     19: XPathLookupError,
     49     23: NoSuchWindow,
     50     24: InvalidCookieDomain,
     51     28: ScriptTimeout,
     52     32: InvalidSelector,
     53     33: SessionNotCreatedException
     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                android_activity=None, android_process=None,
     65                android_use_running_app=None, chrome_switches=None,
     66                chrome_extensions=None, chrome_log_path=None,
     67                debugger_address=None, browser_log_level=None):
     68     self._executor = command_executor.CommandExecutor(server_url)
     69 
     70     options = {}
     71     if android_package:
     72       options['androidPackage'] = android_package
     73       if android_activity:
     74         options['androidActivity'] = android_activity
     75       if android_process:
     76         options['androidProcess'] = android_process
     77       if android_use_running_app:
     78         options['androidUseRunningApp'] = android_use_running_app
     79     elif chrome_binary:
     80       options['binary'] = chrome_binary
     81 
     82     if chrome_switches:
     83       assert type(chrome_switches) is list
     84       options['args'] = chrome_switches
     85 
     86     if chrome_extensions:
     87       assert type(chrome_extensions) is list
     88       options['extensions'] = chrome_extensions
     89 
     90     if chrome_log_path:
     91       assert type(chrome_log_path) is str
     92       options['logPath'] = chrome_log_path
     93 
     94     if debugger_address:
     95       assert type(debugger_address) is str
     96       options['debuggerAddress'] = debugger_address
     97 
     98     logging_prefs = {}
     99     log_levels = ['ALL', 'DEBUG', 'INFO', 'WARNING', 'SEVERE', 'OFF']
    100     if browser_log_level:
    101       assert browser_log_level in log_levels
    102       logging_prefs['browser'] = browser_log_level
    103 
    104     params = {
    105       'desiredCapabilities': {
    106         'chromeOptions': options,
    107         'loggingPrefs': logging_prefs
    108       }
    109     }
    110 
    111     response = self._ExecuteCommand(Command.NEW_SESSION, params)
    112     self._session_id = response['sessionId']
    113     self.capabilities = self._UnwrapValue(response['value'])
    114 
    115   def _WrapValue(self, value):
    116     """Wrap value from client side for chromedriver side."""
    117     if isinstance(value, dict):
    118       converted = {}
    119       for key, val in value.items():
    120         converted[key] = self._WrapValue(val)
    121       return converted
    122     elif isinstance(value, WebElement):
    123       return {'ELEMENT': value._id}
    124     elif isinstance(value, list):
    125       return list(self._WrapValue(item) for item in value)
    126     else:
    127       return value
    128 
    129   def _UnwrapValue(self, value):
    130     """Unwrap value from chromedriver side for client side."""
    131     if isinstance(value, dict):
    132       if (len(value) == 1 and 'ELEMENT' in value
    133           and isinstance(value['ELEMENT'], basestring)):
    134         return WebElement(self, value['ELEMENT'])
    135       else:
    136         unwraped = {}
    137         for key, val in value.items():
    138           unwraped[key] = self._UnwrapValue(val)
    139         return unwraped
    140     elif isinstance(value, list):
    141       return list(self._UnwrapValue(item) for item in value)
    142     else:
    143       return value
    144 
    145   def _ExecuteCommand(self, command, params={}):
    146     params = self._WrapValue(params)
    147     response = self._executor.Execute(command, params)
    148     if response['status'] != 0:
    149       raise _ExceptionForResponse(response)
    150     return response
    151 
    152   def ExecuteCommand(self, command, params={}):
    153     params['sessionId'] = self._session_id
    154     response = self._ExecuteCommand(command, params)
    155     return self._UnwrapValue(response['value'])
    156 
    157   def GetWindowHandles(self):
    158     return self.ExecuteCommand(Command.GET_WINDOW_HANDLES)
    159 
    160   def SwitchToWindow(self, handle_or_name):
    161     self.ExecuteCommand(Command.SWITCH_TO_WINDOW, {'name': handle_or_name})
    162 
    163   def GetCurrentWindowHandle(self):
    164     return self.ExecuteCommand(Command.GET_CURRENT_WINDOW_HANDLE)
    165 
    166   def CloseWindow(self):
    167     self.ExecuteCommand(Command.CLOSE)
    168 
    169   def Load(self, url):
    170     self.ExecuteCommand(Command.GET, {'url': url})
    171 
    172   def ExecuteScript(self, script, *args):
    173     converted_args = list(args)
    174     return self.ExecuteCommand(
    175         Command.EXECUTE_SCRIPT, {'script': script, 'args': converted_args})
    176 
    177   def ExecuteAsyncScript(self, script, *args):
    178     converted_args = list(args)
    179     return self.ExecuteCommand(
    180         Command.EXECUTE_ASYNC_SCRIPT,
    181         {'script': script, 'args': converted_args})
    182 
    183   def SwitchToFrame(self, id_or_name):
    184     self.ExecuteCommand(Command.SWITCH_TO_FRAME, {'id': id_or_name})
    185 
    186   def SwitchToFrameByIndex(self, index):
    187     self.SwitchToFrame(index)
    188 
    189   def SwitchToMainFrame(self):
    190     self.SwitchToFrame(None)
    191 
    192   def GetTitle(self):
    193     return self.ExecuteCommand(Command.GET_TITLE)
    194 
    195   def GetPageSource(self):
    196     return self.ExecuteCommand(Command.GET_PAGE_SOURCE)
    197 
    198   def FindElement(self, strategy, target):
    199     return self.ExecuteCommand(
    200         Command.FIND_ELEMENT, {'using': strategy, 'value': target})
    201 
    202   def FindElements(self, strategy, target):
    203     return self.ExecuteCommand(
    204         Command.FIND_ELEMENTS, {'using': strategy, 'value': target})
    205 
    206   def SetTimeout(self, type, timeout):
    207     return self.ExecuteCommand(
    208         Command.SET_TIMEOUT, {'type' : type, 'ms': timeout})
    209 
    210   def GetCurrentUrl(self):
    211     return self.ExecuteCommand(Command.GET_CURRENT_URL)
    212 
    213   def GoBack(self):
    214     return self.ExecuteCommand(Command.GO_BACK)
    215 
    216   def GoForward(self):
    217     return self.ExecuteCommand(Command.GO_FORWARD)
    218 
    219   def Refresh(self):
    220     return self.ExecuteCommand(Command.REFRESH)
    221 
    222   def MouseMoveTo(self, element=None, x_offset=None, y_offset=None):
    223     params = {}
    224     if element is not None:
    225       params['element'] = element._id
    226     if x_offset is not None:
    227       params['xoffset'] = x_offset
    228     if y_offset is not None:
    229       params['yoffset'] = y_offset
    230     self.ExecuteCommand(Command.MOUSE_MOVE_TO, params)
    231 
    232   def MouseClick(self, button=0):
    233     self.ExecuteCommand(Command.MOUSE_CLICK, {'button': button})
    234 
    235   def MouseButtonDown(self, button=0):
    236     self.ExecuteCommand(Command.MOUSE_BUTTON_DOWN, {'button': button})
    237 
    238   def MouseButtonUp(self, button=0):
    239     self.ExecuteCommand(Command.MOUSE_BUTTON_UP, {'button': button})
    240 
    241   def MouseDoubleClick(self, button=0):
    242     self.ExecuteCommand(Command.MOUSE_DOUBLE_CLICK, {'button': button})
    243 
    244   def TouchDown(self, x, y):
    245     self.ExecuteCommand(Command.TOUCH_DOWN, {'x': x, 'y': y})
    246 
    247   def TouchUp(self, x, y):
    248     self.ExecuteCommand(Command.TOUCH_UP, {'x': x, 'y': y})
    249 
    250   def TouchMove(self, x, y):
    251     self.ExecuteCommand(Command.TOUCH_MOVE, {'x': x, 'y': y})
    252 
    253   def GetCookies(self):
    254     return self.ExecuteCommand(Command.GET_COOKIES)
    255 
    256   def AddCookie(self, cookie):
    257     self.ExecuteCommand(Command.ADD_COOKIE, {'cookie': cookie})
    258 
    259   def DeleteCookie(self, name):
    260     self.ExecuteCommand(Command.DELETE_COOKIE, {'name': name})
    261 
    262   def DeleteAllCookies(self):
    263     self.ExecuteCommand(Command.DELETE_ALL_COOKIES)
    264 
    265   def IsAlertOpen(self):
    266     return self.ExecuteCommand(Command.GET_ALERT)
    267 
    268   def GetAlertMessage(self):
    269     return self.ExecuteCommand(Command.GET_ALERT_TEXT)
    270 
    271   def HandleAlert(self, accept, prompt_text=''):
    272     if prompt_text:
    273       self.ExecuteCommand(Command.SET_ALERT_VALUE, {'text': prompt_text})
    274     if accept:
    275       cmd = Command.ACCEPT_ALERT
    276     else:
    277       cmd = Command.DISMISS_ALERT
    278     self.ExecuteCommand(cmd)
    279 
    280   def IsLoading(self):
    281     return self.ExecuteCommand(Command.IS_LOADING)
    282 
    283   def GetWindowPosition(self):
    284     position = self.ExecuteCommand(Command.GET_WINDOW_POSITION,
    285                                    {'windowHandle': 'current'})
    286     return [position['x'], position['y']]
    287 
    288   def SetWindowPosition(self, x, y):
    289     self.ExecuteCommand(Command.SET_WINDOW_POSITION,
    290                         {'windowHandle': 'current', 'x': x, 'y': y})
    291 
    292   def GetWindowSize(self):
    293     size = self.ExecuteCommand(Command.GET_WINDOW_SIZE,
    294                                {'windowHandle': 'current'})
    295     return [size['width'], size['height']]
    296 
    297   def SetWindowSize(self, width, height):
    298     self.ExecuteCommand(
    299         Command.SET_WINDOW_SIZE,
    300         {'windowHandle': 'current', 'width': width, 'height': height})
    301 
    302   def MaximizeWindow(self):
    303     self.ExecuteCommand(Command.MAXIMIZE_WINDOW, {'windowHandle': 'current'})
    304 
    305   def Quit(self):
    306     """Quits the browser and ends the session."""
    307     self.ExecuteCommand(Command.QUIT)
    308 
    309   def GetLog(self, type):
    310     return self.ExecuteCommand(Command.GET_LOG, {'type': type})
    311 
    312   def GetAvailableLogTypes(self):
    313     return self.ExecuteCommand(Command.GET_AVAILABLE_LOG_TYPES)
    314