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 5import command_executor 6from command_executor import Command 7from webelement import WebElement 8 9 10class ChromeDriverException(Exception): 11 pass 12class NoSuchElement(ChromeDriverException): 13 pass 14class NoSuchFrame(ChromeDriverException): 15 pass 16class UnknownCommand(ChromeDriverException): 17 pass 18class StaleElementReference(ChromeDriverException): 19 pass 20class UnknownError(ChromeDriverException): 21 pass 22class JavaScriptError(ChromeDriverException): 23 pass 24class XPathLookupError(ChromeDriverException): 25 pass 26class NoSuchWindow(ChromeDriverException): 27 pass 28class InvalidCookieDomain(ChromeDriverException): 29 pass 30class ScriptTimeout(ChromeDriverException): 31 pass 32class InvalidSelector(ChromeDriverException): 33 pass 34class SessionNotCreatedException(ChromeDriverException): 35 pass 36class NoSuchSession(ChromeDriverException): 37 pass 38 39def _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 60class 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