errorhandler.py 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. # Licensed to the Software Freedom Conservancy (SFC) under one
  2. # or more contributor license agreements. See the NOTICE file
  3. # distributed with this work for additional information
  4. # regarding copyright ownership. The SFC licenses this file
  5. # to you under the Apache License, Version 2.0 (the
  6. # "License"); you may not use this file except in compliance
  7. # with the License. You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing,
  12. # software distributed under the License is distributed on an
  13. # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. # KIND, either express or implied. See the License for the
  15. # specific language governing permissions and limitations
  16. # under the License.
  17. from selenium.common.exceptions import (ElementNotInteractableException,
  18. ElementNotSelectableException,
  19. ElementNotVisibleException,
  20. ErrorInResponseException,
  21. InvalidElementStateException,
  22. InvalidSelectorException,
  23. ImeNotAvailableException,
  24. ImeActivationFailedException,
  25. MoveTargetOutOfBoundsException,
  26. NoSuchElementException,
  27. NoSuchFrameException,
  28. NoSuchWindowException,
  29. NoAlertPresentException,
  30. StaleElementReferenceException,
  31. TimeoutException,
  32. UnexpectedAlertPresentException,
  33. WebDriverException)
  34. try:
  35. basestring
  36. except NameError: # Python 3.x
  37. basestring = str
  38. class ErrorCode(object):
  39. """
  40. Error codes defined in the WebDriver wire protocol.
  41. """
  42. # Keep in sync with org.openqa.selenium.remote.ErrorCodes and errorcodes.h
  43. SUCCESS = 0
  44. NO_SUCH_ELEMENT = [7, 'no such element']
  45. NO_SUCH_FRAME = [8, 'no such frame']
  46. UNKNOWN_COMMAND = [9, 'unknown command']
  47. STALE_ELEMENT_REFERENCE = [10, 'stale element reference']
  48. ELEMENT_NOT_VISIBLE = [11, 'element not visible']
  49. INVALID_ELEMENT_STATE = [12, 'invalid element state']
  50. UNKNOWN_ERROR = [13, 'unknown error']
  51. ELEMENT_NOT_INTERACTABLE = ["element not interactable"]
  52. ELEMENT_IS_NOT_SELECTABLE = [15, 'element not selectable']
  53. JAVASCRIPT_ERROR = [17, 'javascript error']
  54. XPATH_LOOKUP_ERROR = [19, 'invalid selector']
  55. TIMEOUT = [21, 'timeout']
  56. NO_SUCH_WINDOW = [23, 'no such window']
  57. INVALID_COOKIE_DOMAIN = [24, 'invalid cookie domain']
  58. UNABLE_TO_SET_COOKIE = [25, 'unable to set cookie']
  59. UNEXPECTED_ALERT_OPEN = [26, 'unexpected alert open']
  60. NO_ALERT_OPEN = [27, 'no such alert']
  61. SCRIPT_TIMEOUT = [28, 'script timeout']
  62. INVALID_ELEMENT_COORDINATES = [29, 'invalid element coordinates']
  63. IME_NOT_AVAILABLE = [30, 'ime not available']
  64. IME_ENGINE_ACTIVATION_FAILED = [31, 'ime engine activation failed']
  65. INVALID_SELECTOR = [32, 'invalid selector']
  66. MOVE_TARGET_OUT_OF_BOUNDS = [34, 'move target out of bounds']
  67. INVALID_XPATH_SELECTOR = [51, 'invalid selector']
  68. INVALID_XPATH_SELECTOR_RETURN_TYPER = [52, 'invalid selector']
  69. METHOD_NOT_ALLOWED = [405, 'unsupported operation']
  70. class ErrorHandler(object):
  71. """
  72. Handles errors returned by the WebDriver server.
  73. """
  74. def check_response(self, response):
  75. """
  76. Checks that a JSON response from the WebDriver does not have an error.
  77. :Args:
  78. - response - The JSON response from the WebDriver server as a dictionary
  79. object.
  80. :Raises: If the response contains an error message.
  81. """
  82. status = response.get('status', None)
  83. if status is None or status == ErrorCode.SUCCESS:
  84. return
  85. value = None
  86. message = response.get("message", "")
  87. screen = response.get("screen", "")
  88. stacktrace = None
  89. if isinstance(status, int):
  90. value_json = response.get('value', None)
  91. if value_json and isinstance(value_json, basestring):
  92. import json
  93. try:
  94. value = json.loads(value_json)
  95. if len(value.keys()) == 1:
  96. value = value['value']
  97. status = value.get('error', None)
  98. if status is None:
  99. status = value["status"]
  100. message = value["value"]
  101. if not isinstance(message, basestring):
  102. value = message
  103. message = message.get('message')
  104. else:
  105. message = value.get('message', None)
  106. except ValueError:
  107. pass
  108. exception_class = ErrorInResponseException
  109. if status in ErrorCode.NO_SUCH_ELEMENT:
  110. exception_class = NoSuchElementException
  111. elif status in ErrorCode.NO_SUCH_FRAME:
  112. exception_class = NoSuchFrameException
  113. elif status in ErrorCode.NO_SUCH_WINDOW:
  114. exception_class = NoSuchWindowException
  115. elif status in ErrorCode.STALE_ELEMENT_REFERENCE:
  116. exception_class = StaleElementReferenceException
  117. elif status in ErrorCode.ELEMENT_NOT_VISIBLE:
  118. exception_class = ElementNotVisibleException
  119. elif status in ErrorCode.INVALID_ELEMENT_STATE:
  120. exception_class = InvalidElementStateException
  121. elif status in ErrorCode.INVALID_SELECTOR \
  122. or status in ErrorCode.INVALID_XPATH_SELECTOR \
  123. or status in ErrorCode.INVALID_XPATH_SELECTOR_RETURN_TYPER:
  124. exception_class = InvalidSelectorException
  125. elif status in ErrorCode.ELEMENT_IS_NOT_SELECTABLE:
  126. exception_class = ElementNotSelectableException
  127. elif status in ErrorCode.ELEMENT_NOT_INTERACTABLE:
  128. exception_class = ElementNotInteractableException
  129. elif status in ErrorCode.INVALID_COOKIE_DOMAIN:
  130. exception_class = WebDriverException
  131. elif status in ErrorCode.UNABLE_TO_SET_COOKIE:
  132. exception_class = WebDriverException
  133. elif status in ErrorCode.TIMEOUT:
  134. exception_class = TimeoutException
  135. elif status in ErrorCode.SCRIPT_TIMEOUT:
  136. exception_class = TimeoutException
  137. elif status in ErrorCode.UNKNOWN_ERROR:
  138. exception_class = WebDriverException
  139. elif status in ErrorCode.UNEXPECTED_ALERT_OPEN:
  140. exception_class = UnexpectedAlertPresentException
  141. elif status in ErrorCode.NO_ALERT_OPEN:
  142. exception_class = NoAlertPresentException
  143. elif status in ErrorCode.IME_NOT_AVAILABLE:
  144. exception_class = ImeNotAvailableException
  145. elif status in ErrorCode.IME_ENGINE_ACTIVATION_FAILED:
  146. exception_class = ImeActivationFailedException
  147. elif status in ErrorCode.MOVE_TARGET_OUT_OF_BOUNDS:
  148. exception_class = MoveTargetOutOfBoundsException
  149. else:
  150. exception_class = WebDriverException
  151. if value == '' or value is None:
  152. value = response['value']
  153. if isinstance(value, basestring):
  154. if exception_class == ErrorInResponseException:
  155. raise exception_class(response, value)
  156. raise exception_class(value)
  157. if message == "" and 'message' in value:
  158. message = value['message']
  159. screen = None
  160. if 'screen' in value:
  161. screen = value['screen']
  162. stacktrace = None
  163. if 'stackTrace' in value and value['stackTrace']:
  164. stacktrace = []
  165. try:
  166. for frame in value['stackTrace']:
  167. line = self._value_or_default(frame, 'lineNumber', '')
  168. file = self._value_or_default(frame, 'fileName', '<anonymous>')
  169. if line:
  170. file = "%s:%s" % (file, line)
  171. meth = self._value_or_default(frame, 'methodName', '<anonymous>')
  172. if 'className' in frame:
  173. meth = "%s.%s" % (frame['className'], meth)
  174. msg = " at %s (%s)"
  175. msg = msg % (meth, file)
  176. stacktrace.append(msg)
  177. except TypeError:
  178. pass
  179. if exception_class == ErrorInResponseException:
  180. raise exception_class(response, message)
  181. elif exception_class == UnexpectedAlertPresentException and 'alert' in value:
  182. raise exception_class(message, screen, stacktrace, value['alert'].get('text'))
  183. raise exception_class(message, screen, stacktrace)
  184. def _value_or_default(self, obj, key, default):
  185. return obj[key] if key in obj else default