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