Source code for galaxy.selenium.sizzle

"""Utilities for using sizzle (jQuery-style) selectors with Selenium."""

import json

from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.support.wait import WebDriverWait

from .has_driver import exception_indicates_stale_element

SIZZLE_LOAD_TIMEOUT = 5
SIZZLE_URL = "//cdnjs.cloudflare.com/ajax/libs/sizzle/1.10.18/sizzle.js"


[docs]def sizzle_selector_clickable(selector): def ec(driver): elements = find_elements_by_sizzle(driver, selector) if not elements: return False element = elements[0] try: clickable = element.is_displayed() and element.is_enabled() except Exception as e: # Handle the case where the element is detached between when it is # discovered and when it is checked - it is likely changing quickly # and the next pass will be the final state. If not, this should be # wrapped in a wait anyway - so no problems there. For other # non-custom selectors I believe this all happens on the Selenium # server and so there is likely no need to handle this case - they # are effectively atomic. if exception_indicates_stale_element(e): return None raise if clickable: return element else: return None return ec
[docs]def sizzle_presence_of_selector(selector): def ec(driver): elements = find_elements_by_sizzle(driver, selector) if not elements: return False element = elements[0] try: displayed = element.is_displayed() except Exception as e: # See note above insizzle_selector_clickable about this exception. if exception_indicates_stale_element(e): return None raise if displayed: return element else: return None return ec
[docs]def find_element_by_sizzle(driver, sizzle_selector: str): """ Finds an element by sizzle selector. :param sizzle_selector: The sizzle selector to use when finding element. """ if elements := driver.find_elements_by_sizzle(sizzle_selector): return elements[0] else: raise NoSuchElementException(f"Unable to locate element by Sizzle: {sizzle_selector}")
[docs]def find_elements_by_sizzle(driver, sizzle_selector: str): """ Finds elements by sizzle selector. :param sizzle_selector: The sizzle selector to use when finding elements. """ if not _is_sizzle_loaded(driver): _inject_sizzle(driver, SIZZLE_URL, SIZZLE_LOAD_TIMEOUT) elements = driver.execute_script(_make_sizzle_string(sizzle_selector)) return elements
def _inject_sizzle(driver, sizzle_url, timeout): script = f""" if(typeof(window.$) != "undefined") {{ // Just reuse jQuery if it is available, avoids potential amd problems // that have cropped up with Galaxy for instance. window.Sizzle = window.$; }} else {{ var _s = document.createElement("script"); _s.type = "text/javascript"; _s.src = "{sizzle_url}"; var _h = document.getElementsByTagName("head")[0]; _h.appendChild(_s); }} """ driver.execute_script(script) wait = WebDriverWait(driver, timeout) wait.until(lambda d: _is_sizzle_loaded(d), f"Can't inject Sizzle in {timeout} seconds") def _is_sizzle_loaded(driver): script = 'return typeof(Sizzle) != "undefined";' return driver.execute_script(script) def _make_sizzle_string(sizzle_selector): # Use json.dumps to escape quotes selector = json.dumps(sizzle_selector) return f"return Sizzle({selector});" __all__ = ( "find_element_by_sizzle", "find_elements_by_sizzle", "sizzle_selector_clickable", "sizzle_presence_of_selector", )