event_firing_webdriver.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  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 WebDriverException
  18. from selenium.webdriver.common.by import By
  19. from selenium.webdriver.remote.webdriver import WebDriver
  20. from selenium.webdriver.remote.webelement import WebElement
  21. from .abstract_event_listener import AbstractEventListener
  22. def _wrap_elements(result, ef_driver):
  23. if isinstance(result, WebElement):
  24. return EventFiringWebElement(result, ef_driver)
  25. elif isinstance(result, list):
  26. return [_wrap_elements(item, ef_driver) for item in result]
  27. else:
  28. return result
  29. class EventFiringWebDriver(object):
  30. """
  31. A wrapper around an arbitrary WebDriver instance which supports firing events
  32. """
  33. def __init__(self, driver, event_listener):
  34. """
  35. Creates a new instance of the EventFiringWebDriver
  36. :Args:
  37. - driver : A WebDriver instance
  38. - event_listener : Instance of a class that subclasses AbstractEventListener and implements it fully or partially
  39. Example:
  40. .. code-block:: python
  41. from selenium.webdriver import Firefox
  42. from selenium.webdriver.support.events import EventFiringWebDriver, AbstractEventListener
  43. class MyListener(AbstractEventListener):
  44. def before_navigate_to(self, url, driver):
  45. print("Before navigate to %s" % url)
  46. def after_navigate_to(self, url, driver):
  47. print("After navigate to %s" % url)
  48. driver = Firefox()
  49. ef_driver = EventFiringWebDriver(driver, MyListener())
  50. ef_driver.get("http://www.google.co.in/")
  51. """
  52. if not isinstance(driver, WebDriver):
  53. raise WebDriverException("A WebDriver instance must be supplied")
  54. if not isinstance(event_listener, AbstractEventListener):
  55. raise WebDriverException("Event listener must be a subclass of AbstractEventListener")
  56. self._driver = driver
  57. self._driver._wrap_value = self._wrap_value
  58. self._listener = event_listener
  59. @property
  60. def wrapped_driver(self):
  61. """Returns the WebDriver instance wrapped by this EventsFiringWebDriver"""
  62. return self._driver
  63. def get(self, url):
  64. self._dispatch("navigate_to", (url, self._driver), "get", (url, ))
  65. def back(self):
  66. self._dispatch("navigate_back", (self._driver,), "back", ())
  67. def forward(self):
  68. self._dispatch("navigate_forward", (self._driver,), "forward", ())
  69. def execute_script(self, script, *args):
  70. unwrapped_args = (script,) + self._unwrap_element_args(args)
  71. return self._dispatch("execute_script", (script, self._driver), "execute_script", unwrapped_args)
  72. def execute_async_script(self, script, *args):
  73. unwrapped_args = (script,) + self._unwrap_element_args(args)
  74. return self._dispatch("execute_script", (script, self._driver), "execute_async_script", unwrapped_args)
  75. def close(self):
  76. self._dispatch("close", (self._driver,), "close", ())
  77. def quit(self):
  78. self._dispatch("quit", (self._driver,), "quit", ())
  79. def find_element(self, by=By.ID, value=None):
  80. return self._dispatch("find", (by, value, self._driver), "find_element", (by, value))
  81. def find_elements(self, by=By.ID, value=None):
  82. return self._dispatch("find", (by, value, self._driver), "find_elements", (by, value))
  83. def find_element_by_id(self, id_):
  84. return self.find_element(by=By.ID, value=id_)
  85. def find_elements_by_id(self, id_):
  86. return self.find_elements(by=By.ID, value=id_)
  87. def find_element_by_xpath(self, xpath):
  88. return self.find_element(by=By.XPATH, value=xpath)
  89. def find_elements_by_xpath(self, xpath):
  90. return self.find_elements(by=By.XPATH, value=xpath)
  91. def find_element_by_link_text(self, link_text):
  92. return self.find_element(by=By.LINK_TEXT, value=link_text)
  93. def find_elements_by_link_text(self, text):
  94. return self.find_elements(by=By.LINK_TEXT, value=text)
  95. def find_element_by_partial_link_text(self, link_text):
  96. return self.find_element(by=By.PARTIAL_LINK_TEXT, value=link_text)
  97. def find_elements_by_partial_link_text(self, link_text):
  98. return self.find_elements(by=By.PARTIAL_LINK_TEXT, value=link_text)
  99. def find_element_by_name(self, name):
  100. return self.find_element(by=By.NAME, value=name)
  101. def find_elements_by_name(self, name):
  102. return self.find_elements(by=By.NAME, value=name)
  103. def find_element_by_tag_name(self, name):
  104. return self.find_element(by=By.TAG_NAME, value=name)
  105. def find_elements_by_tag_name(self, name):
  106. return self.find_elements(by=By.TAG_NAME, value=name)
  107. def find_element_by_class_name(self, name):
  108. return self.find_element(by=By.CLASS_NAME, value=name)
  109. def find_elements_by_class_name(self, name):
  110. return self.find_elements(by=By.CLASS_NAME, value=name)
  111. def find_element_by_css_selector(self, css_selector):
  112. return self.find_element(by=By.CSS_SELECTOR, value=css_selector)
  113. def find_elements_by_css_selector(self, css_selector):
  114. return self.find_elements(by=By.CSS_SELECTOR, value=css_selector)
  115. def _dispatch(self, l_call, l_args, d_call, d_args):
  116. getattr(self._listener, "before_%s" % l_call)(*l_args)
  117. try:
  118. result = getattr(self._driver, d_call)(*d_args)
  119. except Exception as e:
  120. self._listener.on_exception(e, self._driver)
  121. raise e
  122. getattr(self._listener, "after_%s" % l_call)(*l_args)
  123. return _wrap_elements(result, self)
  124. def _unwrap_element_args(self, args):
  125. if isinstance(args, EventFiringWebElement):
  126. return args.wrapped_element
  127. elif isinstance(args, tuple):
  128. return tuple([self._unwrap_element_args(item) for item in args])
  129. elif isinstance(args, list):
  130. return [self._unwrap_element_args(item) for item in args]
  131. else:
  132. return args
  133. def _wrap_value(self, value):
  134. if isinstance(value, EventFiringWebElement):
  135. return WebDriver._wrap_value(self._driver, value.wrapped_element)
  136. return WebDriver._wrap_value(self._driver, value)
  137. def __setattr__(self, item, value):
  138. if item.startswith("_") or not hasattr(self._driver, item):
  139. object.__setattr__(self, item, value)
  140. else:
  141. try:
  142. object.__setattr__(self._driver, item, value)
  143. except Exception as e:
  144. self._listener.on_exception(e, self._driver)
  145. raise e
  146. def __getattr__(self, name):
  147. def _wrap(*args, **kwargs):
  148. try:
  149. result = attrib(*args, **kwargs)
  150. return _wrap_elements(result, self)
  151. except Exception as e:
  152. self._listener.on_exception(e, self._driver)
  153. raise
  154. try:
  155. attrib = getattr(self._driver, name)
  156. return _wrap if callable(attrib) else attrib
  157. except Exception as e:
  158. self._listener.on_exception(e, self._driver)
  159. raise
  160. class EventFiringWebElement(object):
  161. """"
  162. A wrapper around WebElement instance which supports firing events
  163. """
  164. def __init__(self, webelement, ef_driver):
  165. """
  166. Creates a new instance of the EventFiringWebElement
  167. """
  168. self._webelement = webelement
  169. self._ef_driver = ef_driver
  170. self._driver = ef_driver.wrapped_driver
  171. self._listener = ef_driver._listener
  172. @property
  173. def wrapped_element(self):
  174. """Returns the WebElement wrapped by this EventFiringWebElement instance"""
  175. return self._webelement
  176. def click(self):
  177. self._dispatch("click", (self._webelement, self._driver), "click", ())
  178. def clear(self):
  179. self._dispatch("change_value_of", (self._webelement, self._driver), "clear", ())
  180. def send_keys(self, *value):
  181. self._dispatch("change_value_of", (self._webelement, self._driver), "send_keys", value)
  182. def find_element(self, by=By.ID, value=None):
  183. return self._dispatch("find", (by, value, self._driver), "find_element", (by, value))
  184. def find_elements(self, by=By.ID, value=None):
  185. return self._dispatch("find", (by, value, self._driver), "find_elements", (by, value))
  186. def find_element_by_id(self, id_):
  187. return self.find_element(by=By.ID, value=id_)
  188. def find_elements_by_id(self, id_):
  189. return self.find_elements(by=By.ID, value=id_)
  190. def find_element_by_name(self, name):
  191. return self.find_element(by=By.NAME, value=name)
  192. def find_elements_by_name(self, name):
  193. return self.find_elements(by=By.NAME, value=name)
  194. def find_element_by_link_text(self, link_text):
  195. return self.find_element(by=By.LINK_TEXT, value=link_text)
  196. def find_elements_by_link_text(self, link_text):
  197. return self.find_elements(by=By.LINK_TEXT, value=link_text)
  198. def find_element_by_partial_link_text(self, link_text):
  199. return self.find_element(by=By.PARTIAL_LINK_TEXT, value=link_text)
  200. def find_elements_by_partial_link_text(self, link_text):
  201. return self.find_elements(by=By.PARTIAL_LINK_TEXT, value=link_text)
  202. def find_element_by_tag_name(self, name):
  203. return self.find_element(by=By.TAG_NAME, value=name)
  204. def find_elements_by_tag_name(self, name):
  205. return self.find_elements(by=By.TAG_NAME, value=name)
  206. def find_element_by_xpath(self, xpath):
  207. return self.find_element(by=By.XPATH, value=xpath)
  208. def find_elements_by_xpath(self, xpath):
  209. return self.find_elements(by=By.XPATH, value=xpath)
  210. def find_element_by_class_name(self, name):
  211. return self.find_element(by=By.CLASS_NAME, value=name)
  212. def find_elements_by_class_name(self, name):
  213. return self.find_elements(by=By.CLASS_NAME, value=name)
  214. def find_element_by_css_selector(self, css_selector):
  215. return self.find_element(by=By.CSS_SELECTOR, value=css_selector)
  216. def find_elements_by_css_selector(self, css_selector):
  217. return self.find_elements(by=By.CSS_SELECTOR, value=css_selector)
  218. def _dispatch(self, l_call, l_args, d_call, d_args):
  219. getattr(self._listener, "before_%s" % l_call)(*l_args)
  220. try:
  221. result = getattr(self._webelement, d_call)(*d_args)
  222. except Exception as e:
  223. self._listener.on_exception(e, self._driver)
  224. raise e
  225. getattr(self._listener, "after_%s" % l_call)(*l_args)
  226. return _wrap_elements(result, self._ef_driver)
  227. def __setattr__(self, item, value):
  228. if item.startswith("_") or not hasattr(self._webelement, item):
  229. object.__setattr__(self, item, value)
  230. else:
  231. try:
  232. object.__setattr__(self._webelement, item, value)
  233. except Exception as e:
  234. self._listener.on_exception(e, self._driver)
  235. raise e
  236. def __getattr__(self, name):
  237. def _wrap(*args, **kwargs):
  238. try:
  239. result = attrib(*args, **kwargs)
  240. return _wrap_elements(result, self._ef_driver)
  241. except Exception as e:
  242. self._listener.on_exception(e, self._driver)
  243. raise
  244. try:
  245. attrib = getattr(self._webelement, name)
  246. return _wrap if callable(attrib) else attrib
  247. except Exception as e:
  248. self._listener.on_exception(e, self._driver)
  249. raise