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