Skip to content

Fix two separate issues regarding hovering and Safari compatibility #1503

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion examples/test_apple_site.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ def test_apple_developer_site_webdriver_instructions(self):
self.assert_element("nav.documentation-nav")
self.assert_text(title, "h1")
self.assert_text("Enable WebDriver and run a test.", "div.abstract")
self.highlight("div.content h2")
if self.demo_mode:
self.highlight("div.content h2")
else:
self.assert_element("div.content h2")
h3 = "div.content h3:nth-of-type(%s)"
self.assert_text("Make Sure You Have Safari’s WebDriver", h3 % "1")
self.assert_text("Get the Correct Selenium Library", h3 % "2")
Expand Down
2 changes: 1 addition & 1 deletion mkdocs_build/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ nltk==3.7
tornado==6.2
watchdog==2.1.9
mkdocs==1.3.1
mkdocs-material==8.4.2
mkdocs-material==8.4.3
mkdocs-exclude-search==0.6.4
mkdocs-simple-hooks==0.1.5
mkdocs-material-extensions==1.0.3
Expand Down
2 changes: 1 addition & 1 deletion seleniumbase/__version__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# seleniumbase package
__version__ = "4.3.5"
__version__ = "4.3.6"
118 changes: 65 additions & 53 deletions seleniumbase/fixtures/base_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,20 +291,19 @@ def click(
pre_action_url = self.driver.current_url
pre_window_count = len(self.driver.window_handles)
try:
if self.browser == "ie" and by == By.LINK_TEXT:
# An issue with clicking Link Text on IE means using jquery
if (
by == By.LINK_TEXT
and (
self.browser == "ie" or self.browser == "safari"
)
):
self.__jquery_click(selector, by=by)
elif self.browser == "safari":
if by == By.LINK_TEXT:
self.__jquery_click(selector, by=by)
else:
self.__js_click(selector, by=by)
else:
href = None
new_tab = False
onclick = None
try:
if self.headless and element.tag_name == "a":
if self.headless and element.tag_name.lower() == "a":
# Handle a special case of opening a new tab (headless)
href = element.get_attribute("href").strip()
onclick = element.get_attribute("onclick")
Expand Down Expand Up @@ -343,11 +342,8 @@ def click(
self.__scroll_to_element(element, selector, by)
except Exception:
pass
if self.browser == "safari":
if by == By.LINK_TEXT:
self.__jquery_click(selector, by=by)
else:
self.__js_click(selector, by=by)
if self.browser == "safari" and by == By.LINK_TEXT:
self.__jquery_click(selector, by=by)
else:
element.click()
except ENI_Exception:
Expand All @@ -364,7 +360,7 @@ def click(
new_tab = False
onclick = None
try:
if element.tag_name == "a":
if element.tag_name.lower() == "a":
# Handle a special case of opening a new tab (non-headless)
href = element.get_attribute("href").strip()
onclick = element.get_attribute("onclick")
Expand Down Expand Up @@ -1449,10 +1445,11 @@ def get_text(self, selector, by="css selector", timeout=None):
try:
element_text = element.text
if self.browser == "safari":
element_text = element.get_attribute("innerText")
if element.tag_name == "input":
element_text = element.get_property("value")
if element.tag_name == "textarea":
if element.tag_name.lower() in ["input", "textarea"]:
element_text = element.get_attribute("value")
else:
element_text = element.get_attribute("innerText")
elif element.tag_name.lower() in ["input", "textarea"]:
element_text = element.get_property("value")
except (StaleElementReferenceException, ENI_Exception):
self.wait_for_ready_state_complete()
Expand All @@ -1462,8 +1459,11 @@ def get_text(self, selector, by="css selector", timeout=None):
)
element_text = element.text
if self.browser == "safari":
element_text = element.get_attribute("innerText")
if element.tag_name == "input":
if element.tag_name.lower() in ["input", "textarea"]:
element_text = element.get_attribute("value")
else:
element_text = element.get_attribute("innerText")
elif element.tag_name.lower() in ["input", "textarea"]:
element_text = element.get_property("value")
return element_text

Expand Down Expand Up @@ -2128,21 +2128,18 @@ def hover_on_element(self, selector, by="css selector"):
original_selector = selector
original_by = by
selector, by = self.__recalculate_selector(selector, by)
if page_utils.is_xpath_selector(selector):
selector = self.convert_to_css_selector(selector, By.XPATH)
by = By.CSS_SELECTOR
self.wait_for_element_visible(
original_selector, by=original_by, timeout=settings.SMALL_TIMEOUT
)
self.__demo_mode_highlight_if_active(original_selector, original_by)
self.scroll_to(selector, by=by)
time.sleep(0.05) # Settle down from scrolling before hovering
if self.browser != "chrome":
return page_actions.hover_on_element(self.driver, selector)
return page_actions.hover_on_element(self.driver, selector, by)
# Using Chrome
# (Pure hover actions won't work on early chromedriver versions)
try:
return page_actions.hover_on_element(self.driver, selector)
return page_actions.hover_on_element(self.driver, selector, by)
except WebDriverException as e:
driver_capabilities = self.driver.capabilities
if "version" in driver_capabilities:
Expand Down Expand Up @@ -2191,8 +2188,6 @@ def hover_and_click(
hover_selector, hover_by = self.__recalculate_selector(
hover_selector, hover_by
)
hover_selector = self.convert_to_css_selector(hover_selector, hover_by)
hover_by = By.CSS_SELECTOR
original_click_selector = click_selector
click_selector, click_by = self.__recalculate_selector(
click_selector, click_by
Expand Down Expand Up @@ -2224,9 +2219,6 @@ def hover_and_click(
if self.mobile_emulator:
# On mobile, click to hover the element
dropdown_element.click()
elif self.browser == "safari":
# Use the workaround for hover-clicking on Safari
raise Exception("This Exception will be caught.")
else:
page_actions.hover_element(self.driver, dropdown_element)
except Exception:
Expand Down Expand Up @@ -2269,6 +2261,12 @@ def hover_and_click(
)
):
self.__switch_to_newest_window_if_not_blank()
elif self.browser == "safari":
# Release the hover by hovering elsewhere
try:
page_actions.hover_on_element(self.driver, "body")
except Exception:
pass
if self.demo_mode:
if self.driver.current_url != pre_action_url:
self.__demo_mode_pause_if_active()
Expand Down Expand Up @@ -2630,10 +2628,11 @@ def get_select_options(
raise Exception("The attribute must be in %s" % allowed_attributes)
selector, by = self.__recalculate_selector(selector, by)
element = self.wait_for_element(selector, by=by, timeout=timeout)
if element.tag_name != "select":
if element.tag_name.lower() != "select":
raise Exception(
'Element tag_name for get_select_options(selector) must be a '
'"select"! Actual tag_name found was: "%s"' % element.tag_name
'"select"! Actual tag_name found was: "%s"'
% element.tag_name.lower()
)
if by != "css selector":
selector = self.convert_to_css_selector(selector, by=by)
Expand Down Expand Up @@ -2717,9 +2716,13 @@ def load_html_string(self, html_string, new_page=True):
html_string = html_string.replace("\\ ", " ")

if new_page:
self.open("data:text/html,")
self.open("data:text/html,<head></head><body></body>")
inner_head = """document.getElementsByTagName("head")[0].innerHTML"""
inner_body = """document.getElementsByTagName("body")[0].innerHTML"""
try:
self.wait_for_element_present("body", timeout=1)
except Exception:
pass
if not found_body:
self.execute_script('''%s = \"%s\"''' % (inner_body, html_string))
elif found_body and not found_head:
Expand Down Expand Up @@ -5102,13 +5105,16 @@ def slow_scroll_to(self, selector, by="css selector", timeout=None):
original_selector, by=original_by, timeout=timeout
)
try:
scroll_distance = js_utils.get_scroll_distance_to_element(
self.driver, element
)
if abs(scroll_distance) > constants.Values.SSMD:
self.__jquery_slow_scroll_to(selector, by)
if self.browser != "safari":
scroll_distance = js_utils.get_scroll_distance_to_element(
self.driver, element
)
if abs(scroll_distance) > constants.Values.SSMD:
self.__jquery_slow_scroll_to(selector, by)
else:
self.__slow_scroll_to_element(element)
else:
self.__slow_scroll_to_element(element)
self.__jquery_slow_scroll_to(selector, by)
except Exception:
self.wait_for_ready_state_complete()
time.sleep(0.12)
Expand Down Expand Up @@ -6721,7 +6727,7 @@ def set_text(self, selector, text, by="css selector", timeout=None):
element = page_actions.wait_for_element_present(
self.driver, selector, by, timeout
)
if element.tag_name == "input" or element.tag_name == "textarea":
if element.tag_name.lower() in ["input", "textarea"]:
self.js_update_text(selector, text, by=by, timeout=timeout)
else:
self.set_text_content(selector, text, by=by, timeout=timeout)
Expand All @@ -6741,7 +6747,7 @@ def set_text_content(
element = page_actions.wait_for_element_present(
self.driver, selector, by, timeout
)
if element.tag_name == "input" or element.tag_name == "textarea":
if element.tag_name.lower() in ["input", "textarea"]:
self.js_update_text(selector, text, by=by, timeout=timeout)
return
orginal_selector = selector
Expand Down Expand Up @@ -12255,13 +12261,16 @@ def __demo_mode_highlight_if_active(self, selector, by):
selector, by=by, timeout=settings.SMALL_TIMEOUT
)
try:
scroll_distance = js_utils.get_scroll_distance_to_element(
self.driver, element
)
if abs(scroll_distance) > constants.Values.SSMD:
self.__jquery_slow_scroll_to(selector, by)
if self.browser != "safari":
scroll_distance = js_utils.get_scroll_distance_to_element(
self.driver, element
)
if abs(scroll_distance) > constants.Values.SSMD:
self.__jquery_slow_scroll_to(selector, by)
else:
self.__slow_scroll_to_element(element)
else:
self.__slow_scroll_to_element(element)
self.__jquery_slow_scroll_to(selector, by)
except (StaleElementReferenceException, ENI_Exception):
self.wait_for_ready_state_complete()
time.sleep(0.12)
Expand Down Expand Up @@ -12295,13 +12304,16 @@ def __highlight_with_assert_success(
selector, by=by, timeout=settings.SMALL_TIMEOUT
)
try:
scroll_distance = js_utils.get_scroll_distance_to_element(
self.driver, element
)
if abs(scroll_distance) > constants.Values.SSMD:
self.__jquery_slow_scroll_to(selector, by)
if self.browser != "safari":
scroll_distance = js_utils.get_scroll_distance_to_element(
self.driver, element
)
if abs(scroll_distance) > constants.Values.SSMD:
self.__jquery_slow_scroll_to(selector, by)
else:
self.__slow_scroll_to_element(element)
else:
self.__slow_scroll_to_element(element)
self.__jquery_slow_scroll_to(selector, by)
except Exception:
self.wait_for_ready_state_complete()
time.sleep(0.12)
Expand Down
30 changes: 21 additions & 9 deletions seleniumbase/fixtures/page_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,13 @@ def is_text_visible(driver, text, selector, by="css selector", browser=None):
try:
element = driver.find_element(by=by, value=selector)
element_text = element.text
if element.tag_name == "input" or element.tag_name == "textarea":
if browser == "safari":
if element.tag_name.lower() in ["input", "textarea"]:
element_text = element.get_attribute("value")
else:
element_text = element.get_attribute("innerText")
elif element.tag_name.lower() in ["input", "textarea"]:
element_text = element.get_property("value")
elif browser == "safari":
element_text = element.get_attribute("innerText")
return element.is_displayed() and text in element_text
except Exception:
return False
Expand Down Expand Up @@ -477,7 +480,10 @@ def wait_for_text_visible(
try:
element = driver.find_element(by=by, value=selector)
is_present = True
if element.tag_name == "input" or element.tag_name == "textarea":
if (
element.tag_name.lower() in ["input", "textarea"]
and browser != "safari"
):
if (
element.is_displayed()
and text in element.get_property("value")
Expand All @@ -489,14 +495,17 @@ def wait_for_text_visible(
element = None
raise Exception()
elif browser == "safari":
text_attr = "innerText"
if element.tag_name.lower() in ["input", "textarea"]:
text_attr = "value"
if (
element.is_displayed()
and text in element.get_attribute("innerText")
and text in element.get_attribute(text_attr)
):
return element
else:
if element.is_displayed():
full_text = element.get_attribute("innerText")
full_text = element.get_attribute(text_attr)
full_text = full_text.strip()
element = None
raise Exception()
Expand Down Expand Up @@ -582,7 +591,7 @@ def wait_for_exact_text_visible(
try:
element = driver.find_element(by=by, value=selector)
is_present = True
if element.tag_name == "input" or element.tag_name == "textarea":
if element.tag_name.lower() in ["input", "textarea"]:
if (
element.is_displayed()
and text.strip() == element.get_property("value").strip()
Expand All @@ -594,13 +603,16 @@ def wait_for_exact_text_visible(
element = None
raise Exception()
elif browser == "safari":
text_attr = "innerText"
if element.tag_name.lower() in ["input", "textarea"]:
text_attr = "value"
if element.is_displayed() and (
text.strip() == element.get_attribute("innerText").strip()
text.strip() == element.get_attribute(text_attr).strip()
):
return element
else:
if element.is_displayed():
actual_text = element.get_attribute("innerText")
actual_text = element.get_attribute(text_attr)
actual_text = actual_text.strip()
element = None
raise Exception()
Expand Down