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