Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / chrome / test / chromedriver / client / chromedriver.py
blobe084e57722ad9c37477b8d2dc92f0706d7813ded
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.
5 import command_executor
6 from command_executor import Command
7 from webelement import WebElement
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
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
55 status = response['status']
56 msg = response['value']['message']
57 return exception_class_map.get(status, ChromeDriverException)(msg)
60 class ChromeDriver(object):
61 """Starts and controls a single Chrome instance on this machine."""
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, download_dir=None):
70 self._executor = command_executor.CommandExecutor(server_url)
72 options = {}
74 if experimental_options:
75 assert isinstance(experimental_options, dict)
76 options = experimental_options.copy()
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
89 if chrome_switches:
90 assert type(chrome_switches) is list
91 options['args'] = chrome_switches
93 if mobile_emulation:
94 assert type(mobile_emulation) is dict
95 options['mobileEmulation'] = mobile_emulation
97 if chrome_extensions:
98 assert type(chrome_extensions) is list
99 options['extensions'] = chrome_extensions
101 if chrome_log_path:
102 assert type(chrome_log_path) is str
103 options['logPath'] = chrome_log_path
105 if debugger_address:
106 assert type(debugger_address) is str
107 options['debuggerAddress'] = debugger_address
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
118 download_prefs = {}
119 if download_dir:
120 if 'prefs' not in options:
121 options['prefs'] = {}
122 if 'download' not in options['prefs']:
123 options['prefs']['download'] = {}
124 options['prefs']['download']['default_directory'] = download_dir
126 params = {
127 'desiredCapabilities': {
128 'chromeOptions': options,
129 'loggingPrefs': logging_prefs
133 response = self._ExecuteCommand(Command.NEW_SESSION, params)
134 self._session_id = response['sessionId']
135 self.capabilities = self._UnwrapValue(response['value'])
137 def _WrapValue(self, value):
138 """Wrap value from client side for chromedriver side."""
139 if isinstance(value, dict):
140 converted = {}
141 for key, val in value.items():
142 converted[key] = self._WrapValue(val)
143 return converted
144 elif isinstance(value, WebElement):
145 return {'ELEMENT': value._id}
146 elif isinstance(value, list):
147 return list(self._WrapValue(item) for item in value)
148 else:
149 return value
151 def _UnwrapValue(self, value):
152 """Unwrap value from chromedriver side for client side."""
153 if isinstance(value, dict):
154 if (len(value) == 1 and 'ELEMENT' in value
155 and isinstance(value['ELEMENT'], basestring)):
156 return WebElement(self, value['ELEMENT'])
157 else:
158 unwraped = {}
159 for key, val in value.items():
160 unwraped[key] = self._UnwrapValue(val)
161 return unwraped
162 elif isinstance(value, list):
163 return list(self._UnwrapValue(item) for item in value)
164 else:
165 return value
167 def _ExecuteCommand(self, command, params={}):
168 params = self._WrapValue(params)
169 response = self._executor.Execute(command, params)
170 if response['status'] != 0:
171 raise _ExceptionForResponse(response)
172 return response
174 def ExecuteCommand(self, command, params={}):
175 params['sessionId'] = self._session_id
176 response = self._ExecuteCommand(command, params)
177 return self._UnwrapValue(response['value'])
179 def GetWindowHandles(self):
180 return self.ExecuteCommand(Command.GET_WINDOW_HANDLES)
182 def SwitchToWindow(self, handle_or_name):
183 self.ExecuteCommand(Command.SWITCH_TO_WINDOW, {'name': handle_or_name})
185 def GetCurrentWindowHandle(self):
186 return self.ExecuteCommand(Command.GET_CURRENT_WINDOW_HANDLE)
188 def CloseWindow(self):
189 self.ExecuteCommand(Command.CLOSE)
191 def Load(self, url):
192 self.ExecuteCommand(Command.GET, {'url': url})
194 def LaunchApp(self, app_id):
195 self.ExecuteCommand(Command.LAUNCH_APP, {'id': app_id})
197 def ExecuteScript(self, script, *args):
198 converted_args = list(args)
199 return self.ExecuteCommand(
200 Command.EXECUTE_SCRIPT, {'script': script, 'args': converted_args})
202 def ExecuteAsyncScript(self, script, *args):
203 converted_args = list(args)
204 return self.ExecuteCommand(
205 Command.EXECUTE_ASYNC_SCRIPT,
206 {'script': script, 'args': converted_args})
208 def SwitchToFrame(self, id_or_name):
209 self.ExecuteCommand(Command.SWITCH_TO_FRAME, {'id': id_or_name})
211 def SwitchToFrameByIndex(self, index):
212 self.SwitchToFrame(index)
214 def SwitchToMainFrame(self):
215 self.SwitchToFrame(None)
217 def SwitchToParentFrame(self):
218 self.ExecuteCommand(Command.SWITCH_TO_PARENT_FRAME)
220 def GetSessions(self):
221 return self.ExecuteCommand(Command.GET_SESSIONS)
223 def GetTitle(self):
224 return self.ExecuteCommand(Command.GET_TITLE)
226 def GetPageSource(self):
227 return self.ExecuteCommand(Command.GET_PAGE_SOURCE)
229 def FindElement(self, strategy, target):
230 return self.ExecuteCommand(
231 Command.FIND_ELEMENT, {'using': strategy, 'value': target})
233 def FindElements(self, strategy, target):
234 return self.ExecuteCommand(
235 Command.FIND_ELEMENTS, {'using': strategy, 'value': target})
237 def SetTimeout(self, type, timeout):
238 return self.ExecuteCommand(
239 Command.SET_TIMEOUT, {'type' : type, 'ms': timeout})
241 def GetCurrentUrl(self):
242 return self.ExecuteCommand(Command.GET_CURRENT_URL)
244 def GoBack(self):
245 return self.ExecuteCommand(Command.GO_BACK)
247 def GoForward(self):
248 return self.ExecuteCommand(Command.GO_FORWARD)
250 def Refresh(self):
251 return self.ExecuteCommand(Command.REFRESH)
253 def MouseMoveTo(self, element=None, x_offset=None, y_offset=None):
254 params = {}
255 if element is not None:
256 params['element'] = element._id
257 if x_offset is not None:
258 params['xoffset'] = x_offset
259 if y_offset is not None:
260 params['yoffset'] = y_offset
261 self.ExecuteCommand(Command.MOUSE_MOVE_TO, params)
263 def MouseClick(self, button=0):
264 self.ExecuteCommand(Command.MOUSE_CLICK, {'button': button})
266 def MouseButtonDown(self, button=0):
267 self.ExecuteCommand(Command.MOUSE_BUTTON_DOWN, {'button': button})
269 def MouseButtonUp(self, button=0):
270 self.ExecuteCommand(Command.MOUSE_BUTTON_UP, {'button': button})
272 def MouseDoubleClick(self, button=0):
273 self.ExecuteCommand(Command.MOUSE_DOUBLE_CLICK, {'button': button})
275 def TouchDown(self, x, y):
276 self.ExecuteCommand(Command.TOUCH_DOWN, {'x': x, 'y': y})
278 def TouchUp(self, x, y):
279 self.ExecuteCommand(Command.TOUCH_UP, {'x': x, 'y': y})
281 def TouchMove(self, x, y):
282 self.ExecuteCommand(Command.TOUCH_MOVE, {'x': x, 'y': y})
284 def TouchScroll(self, element, xoffset, yoffset):
285 params = {'element': element._id, 'xoffset': xoffset, 'yoffset': yoffset}
286 self.ExecuteCommand(Command.TOUCH_SCROLL, params)
288 def TouchFlick(self, element, xoffset, yoffset, speed):
289 params = {
290 'element': element._id,
291 'xoffset': xoffset,
292 'yoffset': yoffset,
293 'speed': speed
295 self.ExecuteCommand(Command.TOUCH_FLICK, params)
297 def TouchPinch(self, x, y, scale):
298 params = {'x': x, 'y': y, 'scale': scale}
299 self.ExecuteCommand(Command.TOUCH_PINCH, params)
301 def GetCookies(self):
302 return self.ExecuteCommand(Command.GET_COOKIES)
304 def AddCookie(self, cookie):
305 self.ExecuteCommand(Command.ADD_COOKIE, {'cookie': cookie})
307 def DeleteCookie(self, name):
308 self.ExecuteCommand(Command.DELETE_COOKIE, {'name': name})
310 def DeleteAllCookies(self):
311 self.ExecuteCommand(Command.DELETE_ALL_COOKIES)
313 def IsAlertOpen(self):
314 return self.ExecuteCommand(Command.GET_ALERT)
316 def GetAlertMessage(self):
317 return self.ExecuteCommand(Command.GET_ALERT_TEXT)
319 def HandleAlert(self, accept, prompt_text=''):
320 if prompt_text:
321 self.ExecuteCommand(Command.SET_ALERT_VALUE, {'text': prompt_text})
322 if accept:
323 cmd = Command.ACCEPT_ALERT
324 else:
325 cmd = Command.DISMISS_ALERT
326 self.ExecuteCommand(cmd)
328 def IsLoading(self):
329 return self.ExecuteCommand(Command.IS_LOADING)
331 def GetWindowPosition(self):
332 position = self.ExecuteCommand(Command.GET_WINDOW_POSITION,
333 {'windowHandle': 'current'})
334 return [position['x'], position['y']]
336 def SetWindowPosition(self, x, y):
337 self.ExecuteCommand(Command.SET_WINDOW_POSITION,
338 {'windowHandle': 'current', 'x': x, 'y': y})
340 def GetWindowSize(self):
341 size = self.ExecuteCommand(Command.GET_WINDOW_SIZE,
342 {'windowHandle': 'current'})
343 return [size['width'], size['height']]
345 def SetWindowSize(self, width, height):
346 self.ExecuteCommand(
347 Command.SET_WINDOW_SIZE,
348 {'windowHandle': 'current', 'width': width, 'height': height})
350 def MaximizeWindow(self):
351 self.ExecuteCommand(Command.MAXIMIZE_WINDOW, {'windowHandle': 'current'})
353 def Quit(self):
354 """Quits the browser and ends the session."""
355 self.ExecuteCommand(Command.QUIT)
357 def GetLog(self, type):
358 return self.ExecuteCommand(Command.GET_LOG, {'type': type})
360 def GetAvailableLogTypes(self):
361 return self.ExecuteCommand(Command.GET_AVAILABLE_LOG_TYPES)
363 def IsAutoReporting(self):
364 return self.ExecuteCommand(Command.IS_AUTO_REPORTING)
366 def SetAutoReporting(self, enabled):
367 self.ExecuteCommand(Command.SET_AUTO_REPORTING, {'enabled': enabled})
369 def SetNetworkConditions(self, latency, download_throughput,
370 upload_throughput, offline=False):
371 # Until http://crbug.com/456324 is resolved, we'll always set 'offline' to
372 # False, as going "offline" will sever Chromedriver's connection to Chrome.
373 params = {
374 'network_conditions': {
375 'offline': offline,
376 'latency': latency,
377 'download_throughput': download_throughput,
378 'upload_throughput': upload_throughput
381 self.ExecuteCommand(Command.SET_NETWORK_CONDITIONS, params)
383 def SetNetworkConditionsName(self, network_name):
384 self.ExecuteCommand(
385 Command.SET_NETWORK_CONDITIONS, {'network_name': network_name})
387 def GetNetworkConditions(self):
388 conditions = self.ExecuteCommand(Command.GET_NETWORK_CONDITIONS)
389 return {
390 'latency': conditions['latency'],
391 'download_throughput': conditions['download_throughput'],
392 'upload_throughput': conditions['upload_throughput'],
393 'offline': conditions['offline']
396 def DeleteNetworkConditions(self):
397 self.ExecuteCommand(Command.DELETE_NETWORK_CONDITIONS)