Last active
August 19, 2020 05:35
-
-
Save sergio-bershadsky/afd83c82f1e2b7d7207eb67ca48eec41 to your computer and use it in GitHub Desktop.
Selenium list waiter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from selenium.webdriver.common.by import By | |
| from selenium.webdriver.support import expected_conditions | |
| def ready_state_complete(driver): | |
| state = driver.execute_script("return document.readyState") | |
| if state == "complete": | |
| return True | |
| return False | |
| CONDITIONS = { | |
| "title_is": expected_conditions.title_is, | |
| "title_contains": expected_conditions.title_contains, | |
| "presence_of_element_located": expected_conditions.presence_of_element_located, | |
| "url_contains": expected_conditions.url_contains, | |
| "url_matches": expected_conditions.url_matches, | |
| "url_to_be": expected_conditions.url_to_be, | |
| "url_changes": expected_conditions.url_changes, | |
| "visibility_of_element_located": expected_conditions.visibility_of_element_located, | |
| "visibility_of": expected_conditions.visibility_of, | |
| "presence_of_all_elements_located": expected_conditions.presence_of_all_elements_located, | |
| "visibility_of_any_elements_located": expected_conditions.visibility_of_any_elements_located, | |
| "visibility_of_all_elements_located": expected_conditions.visibility_of_all_elements_located, | |
| "text_to_be_present_in_element": expected_conditions.text_to_be_present_in_element, | |
| "text_to_be_present_in_element_value": expected_conditions.text_to_be_present_in_element_value, | |
| "frame_to_be_available_and_switch_to_it": expected_conditions.frame_to_be_available_and_switch_to_it, | |
| "invisibility_of_element_located": expected_conditions.invisibility_of_element_located, | |
| "invisibility_of_element": expected_conditions.invisibility_of_element, | |
| "element_to_be_clickable": expected_conditions.element_to_be_clickable, | |
| "staleness_of": expected_conditions.staleness_of, | |
| "element_to_be_selected": expected_conditions.element_to_be_selected, | |
| "element_located_to_be_selected": expected_conditions.element_located_to_be_selected, | |
| "element_selection_state_to_be": expected_conditions.element_selection_state_to_be, | |
| "element_located_selection_state_to_be": expected_conditions.element_located_selection_state_to_be, | |
| "number_of_windows_to_be": expected_conditions.number_of_windows_to_be, | |
| "new_window_is_opened": expected_conditions.new_window_is_opened, | |
| "alert_is_present": expected_conditions.alert_is_present, | |
| "ready_state_complete": ready_state_complete, | |
| } | |
| LOCATOR_MAP = { | |
| "x": By.XPATH, | |
| "css": By.CSS_SELECTOR, | |
| "id": By.ID, | |
| "link": By.LINK_TEXT, | |
| "link_contains": By.PARTIAL_LINK_TEXT, | |
| "name": By.NAME, | |
| "tag": By.TAG_NAME, | |
| "class": By.CLASS_NAME, | |
| } | |
| LOCATOR_REGEX = f"({'|'.join(LOCATOR_MAP.keys())}):.*" | |
| class SeleniumWaiter(WebDriverWait): | |
| def __init__(self, driver=None, timeout=None, poll_frequency=POLL_FREQUENCY, ignored_exceptions=None): | |
| # TODO: get timeout from task config | |
| timeout = settings.selenium_timeout if timeout is None else timeout | |
| super(SeleniumWaiter, self).__init__(driver, timeout, poll_frequency=poll_frequency, ignored_exceptions=ignored_exceptions) | |
| def any(self, *methods, timeout_message=''): | |
| screen = None | |
| stacktrace = None | |
| end_time = time.time() + self._timeout | |
| while True: | |
| for method in methods: | |
| try: | |
| result = method(self._driver) | |
| if result is not False: | |
| return result | |
| except self._ignored_exceptions as exc: | |
| screen = getattr(exc, 'screen', None) | |
| stacktrace = getattr(exc, 'stacktrace', None) | |
| # Break element searching when time is out | |
| if time.time() > end_time: | |
| break | |
| # Break waiting when time is out | |
| time.sleep(self._poll) | |
| if time.time() > end_time: | |
| break | |
| raise TimeoutException(timeout_message, screen, stacktrace) | |
| def make_locator(query: str): | |
| """ | |
| :param query: Query in (protocol):(value) format | |
| :return: | |
| """ | |
| try: | |
| protocol, value = query.split(":", 1) | |
| except ValueError: | |
| raise exceptions.UsageError(f"Bad locator definition {query}") | |
| protocol = protocol.strip().lower() | |
| if protocol not in LOCATOR_MAP: | |
| raise exceptions.UsageError(f"Unknown protocol {protocol} for locator {query}") | |
| return LOCATOR_MAP[protocol], value | |
| conditions = [ | |
| condition(make_locator(l)) # condition is member if CONDITIONS | |
| for l in locator | |
| ] | |
| # Usage | |
| SeleniumWaiter(driver, timeout=timeout).any(*conditions) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment