| OLD | NEW |
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import ctypes | 5 import ctypes |
| 6 import json | 6 import json |
| 7 | 7 |
| 8 from webelement import WebElement |
| 9 |
| 8 class ChromeDriverException(Exception): | 10 class ChromeDriverException(Exception): |
| 9 pass | 11 pass |
| 10 class NoSuchElement(ChromeDriverException): | 12 class NoSuchElement(ChromeDriverException): |
| 11 pass | 13 pass |
| 12 class UnknownCommand(ChromeDriverException): | 14 class UnknownCommand(ChromeDriverException): |
| 13 pass | 15 pass |
| 16 class StaleElementReference(ChromeDriverException): |
| 17 pass |
| 14 class UnknownError(ChromeDriverException): | 18 class UnknownError(ChromeDriverException): |
| 15 pass | 19 pass |
| 16 class XPathLookupError(ChromeDriverException): | 20 class XPathLookupError(ChromeDriverException): |
| 17 pass | 21 pass |
| 18 class InvalidSelector(ChromeDriverException): | 22 class InvalidSelector(ChromeDriverException): |
| 19 pass | 23 pass |
| 20 class SessionNotCreatedException(ChromeDriverException): | 24 class SessionNotCreatedException(ChromeDriverException): |
| 21 pass | 25 pass |
| 22 class NoSuchSession(ChromeDriverException): | 26 class NoSuchSession(ChromeDriverException): |
| 23 pass | 27 pass |
| 24 | 28 |
| 25 def _ExceptionForResponse(response): | 29 def _ExceptionForResponse(response): |
| 26 exception_class_map = { | 30 exception_class_map = { |
| 27 7: NoSuchElement, | 31 7: NoSuchElement, |
| 28 9: UnknownCommand, | 32 9: UnknownCommand, |
| 33 10: StaleElementReference, |
| 29 13: UnknownError, | 34 13: UnknownError, |
| 30 19: XPathLookupError, | 35 19: XPathLookupError, |
| 31 32: InvalidSelector, | 36 32: InvalidSelector, |
| 32 33: SessionNotCreatedException, | 37 33: SessionNotCreatedException, |
| 33 100: NoSuchSession | 38 100: NoSuchSession |
| 34 } | 39 } |
| 35 status = response['status'] | 40 status = response['status'] |
| 36 msg = response['value']['message'] | 41 msg = response['value']['message'] |
| 37 return exception_class_map.get(status, ChromeDriverException)(msg) | 42 return exception_class_map.get(status, ChromeDriverException)(msg) |
| 38 | 43 |
| 39 class ChromeDriver(object): | 44 class ChromeDriver(object): |
| 40 """Starts and controls a single Chrome instance on this machine.""" | 45 """Starts and controls a single Chrome instance on this machine.""" |
| 41 | 46 |
| 42 def __init__(self, lib_path, chrome_binary=None): | 47 def __init__(self, lib_path, chrome_binary=None): |
| 43 self._lib = ctypes.CDLL(lib_path) | 48 self._lib = ctypes.CDLL(lib_path) |
| 44 if chrome_binary is None: | 49 if chrome_binary is None: |
| 45 params = {} | 50 params = {} |
| 46 else: | 51 else: |
| 47 params = { | 52 params = { |
| 48 'desiredCapabilities': { | 53 'desiredCapabilities': { |
| 49 'chromeOptions': { | 54 'chromeOptions': { |
| 50 'binary': chrome_binary | 55 'binary': chrome_binary |
| 51 } | 56 } |
| 52 } | 57 } |
| 53 } | 58 } |
| 54 self._session_id = self._ExecuteCommand('newSession', params)['sessionId'] | 59 self._session_id = self._ExecuteCommand('newSession', params)['sessionId'] |
| 55 | 60 |
| 61 def _WrapValue(self, value): |
| 62 """Wrap value from client side for chromedriver side.""" |
| 63 if isinstance(value, dict): |
| 64 converted = {} |
| 65 for key, val in value.items(): |
| 66 converted[key] = self._WrapValue(val) |
| 67 return converted |
| 68 elif isinstance(value, WebElement): |
| 69 return {'ELEMENT': value._id} |
| 70 elif isinstance(value, list): |
| 71 return list(self._WrapValue(item) for item in value) |
| 72 else: |
| 73 return value |
| 74 |
| 75 def _UnwrapValue(self, value): |
| 76 """Unwrap value from chromedriver side for client side.""" |
| 77 if isinstance(value, dict): |
| 78 if (len(value) == 1 and 'ELEMENT' in value |
| 79 and isinstance(value['ELEMENT'], basestring)): |
| 80 return WebElement(self, value['ELEMENT']) |
| 81 else: |
| 82 unwraped = {} |
| 83 for key, val in value.items(): |
| 84 unwraped[key] = self._UnwrapValue(val) |
| 85 return unwraped |
| 86 elif isinstance(value, list): |
| 87 return list(self._UnwrapValue(item) for item in value) |
| 88 else: |
| 89 return value |
| 90 |
| 56 def _ExecuteCommand(self, name, params={}, session_id=''): | 91 def _ExecuteCommand(self, name, params={}, session_id=''): |
| 57 cmd = { | 92 cmd = { |
| 58 'name': name, | 93 'name': name, |
| 59 'parameters': params, | 94 'parameters': params, |
| 60 'sessionId': session_id | 95 'sessionId': session_id |
| 61 } | 96 } |
| 62 cmd_json = json.dumps(cmd) | 97 cmd_json = json.dumps(cmd) |
| 63 response_data = ctypes.c_char_p() | 98 response_data = ctypes.c_char_p() |
| 64 response_size = ctypes.c_uint() | 99 response_size = ctypes.c_uint() |
| 65 self._lib.ExecuteCommand( | 100 self._lib.ExecuteCommand( |
| 66 ctypes.c_char_p(cmd_json), | 101 ctypes.c_char_p(cmd_json), |
| 67 ctypes.c_uint(len(cmd_json)), | 102 ctypes.c_uint(len(cmd_json)), |
| 68 ctypes.byref(response_data), | 103 ctypes.byref(response_data), |
| 69 ctypes.byref(response_size)) | 104 ctypes.byref(response_size)) |
| 70 response_json = ctypes.string_at(response_data, response_size.value) | 105 response_json = ctypes.string_at(response_data, response_size.value) |
| 71 self._lib.Free(response_data) | 106 self._lib.Free(response_data) |
| 72 response = json.loads(response_json) | 107 response = json.loads(response_json) |
| 73 if response['status'] != 0: | 108 if response['status'] != 0: |
| 74 raise _ExceptionForResponse(response) | 109 raise _ExceptionForResponse(response) |
| 75 return response | 110 return response |
| 76 | 111 |
| 77 def _ExecuteSessionCommand(self, name, params={}): | 112 def ExecuteSessionCommand(self, name, params={}): |
| 78 return self._ExecuteCommand(name, params, self._session_id)['value'] | 113 params = self._WrapValue(params) |
| 114 return self._UnwrapValue( |
| 115 self._ExecuteCommand(name, params, self._session_id)['value']) |
| 79 | 116 |
| 80 def Load(self, url): | 117 def Load(self, url): |
| 81 self._ExecuteSessionCommand('get', {'url': url}) | 118 self.ExecuteSessionCommand('get', {'url': url}) |
| 82 | 119 |
| 83 def ExecuteScript(self, script, *args): | 120 def ExecuteScript(self, script, *args): |
| 84 return self._ExecuteSessionCommand( | 121 converted_args = list(args) |
| 85 'executeScript', {'script': script, 'args': args}) | 122 return self.ExecuteSessionCommand( |
| 123 'executeScript', {'script': script, 'args': converted_args}) |
| 86 | 124 |
| 87 def SwitchToFrame(self, id_or_name): | 125 def SwitchToFrame(self, id_or_name): |
| 88 self._ExecuteSessionCommand('switchToFrame', {'id': id_or_name}) | 126 self.ExecuteSessionCommand('switchToFrame', {'id': id_or_name}) |
| 89 | 127 |
| 90 def SwitchToFrameByIndex(self, index): | 128 def SwitchToFrameByIndex(self, index): |
| 91 self.SwitchToFrame(index) | 129 self.SwitchToFrame(index) |
| 92 | 130 |
| 93 def SwitchToMainFrame(self): | 131 def SwitchToMainFrame(self): |
| 94 self.SwitchToFrame(None) | 132 self.SwitchToFrame(None) |
| 95 | 133 |
| 96 def GetTitle(self): | 134 def GetTitle(self): |
| 97 return self._ExecuteSessionCommand('getTitle') | 135 return self.ExecuteSessionCommand('getTitle') |
| 98 | 136 |
| 99 def FindElement(self, strategy, target): | 137 def FindElement(self, strategy, target): |
| 100 return self._ExecuteSessionCommand( | 138 return self.ExecuteSessionCommand( |
| 101 'findElement', {'using': strategy, 'value': target}) | 139 'findElement', {'using': strategy, 'value': target}) |
| 102 | 140 |
| 103 def FindElements(self, strategy, target): | 141 def FindElements(self, strategy, target): |
| 104 return self._ExecuteSessionCommand( | 142 return self.ExecuteSessionCommand( |
| 105 'findElements', {'using': strategy, 'value': target}) | 143 'findElements', {'using': strategy, 'value': target}) |
| 106 | 144 |
| 107 def SetTimeout(self, type, timeout): | 145 def SetTimeout(self, type, timeout): |
| 108 return self._ExecuteSessionCommand( | 146 return self.ExecuteSessionCommand( |
| 109 'setTimeout', {'type' : type, 'ms': timeout}) | 147 'setTimeout', {'type' : type, 'ms': timeout}) |
| 110 | 148 |
| 111 def Quit(self): | 149 def Quit(self): |
| 112 """Quits the browser and ends the session.""" | 150 """Quits the browser and ends the session.""" |
| 113 self._ExecuteSessionCommand('quit') | 151 self.ExecuteSessionCommand('quit') |
| OLD | NEW |