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