Skip to content

Commit 24d2f3b

Browse files
authored
Merge pull request #473 from seleniumbase/improve-method-reliability
Improve method reliability
2 parents 896a803 + 8f05b70 commit 24d2f3b

File tree

3 files changed

+40
-23
lines changed

3 files changed

+40
-23
lines changed

seleniumbase/fixtures/base_case.py

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ def test_anything(self):
6060
logging.getLogger("urllib3").setLevel(logging.ERROR)
6161
urllib3.disable_warnings()
6262
LOGGER.setLevel(logging.WARNING)
63+
ECI_Exception = selenium_exceptions.ElementClickInterceptedException
6364
ENI_Exception = selenium_exceptions.ElementNotInteractableException
6465

6566

@@ -951,10 +952,11 @@ def get_image_url(self, selector, by=By.CSS_SELECTOR, timeout=None):
951952

952953
def find_elements(self, selector, by=By.CSS_SELECTOR, limit=0):
953954
""" Returns a list of matching WebElements.
955+
Elements could be either hidden or visible on the page.
954956
If "limit" is set and > 0, will only return that many elements. """
955-
self.wait_for_ready_state_complete()
956-
time.sleep(0.05)
957957
selector, by = self.__recalculate_selector(selector, by)
958+
self.wait_for_ready_state_complete()
959+
time.sleep(0.07)
958960
elements = self.driver.find_elements(by=by, value=selector)
959961
if limit and limit > 0 and len(elements) > limit:
960962
elements = elements[:limit]
@@ -963,9 +965,9 @@ def find_elements(self, selector, by=By.CSS_SELECTOR, limit=0):
963965
def find_visible_elements(self, selector, by=By.CSS_SELECTOR, limit=0):
964966
""" Returns a list of matching WebElements that are visible.
965967
If "limit" is set and > 0, will only return that many elements. """
966-
self.wait_for_ready_state_complete()
967-
time.sleep(0.05)
968968
selector, by = self.__recalculate_selector(selector, by)
969+
self.wait_for_ready_state_complete()
970+
time.sleep(0.07)
969971
v_elems = page_actions.find_visible_elements(self.driver, selector, by)
970972
if limit and limit > 0 and len(v_elems) > limit:
971973
v_elems = v_elems[:limit]
@@ -977,35 +979,34 @@ def click_visible_elements(self, selector, by=By.CSS_SELECTOR, limit=0):
977979
Works best for actions such as clicking all checkboxes on a page.
978980
Example: self.click_visible_elements('input[type="checkbox"]')
979981
If "limit" is set and > 0, will only click that many elements. """
980-
elements = self.find_elements(selector, by=by)
981-
count = 0
982+
elements = []
983+
try:
984+
elements = self.find_visible_elements(selector, by=by)
985+
except Exception:
986+
elements = self.find_elements(selector, by=by)
982987
click_count = 0
983988
for element in elements:
984989
if limit and limit > 0 and click_count >= limit:
985990
return
986-
count += 1
987-
if count == 1:
988-
self.wait_for_ready_state_complete()
989-
if self.is_element_visible(selector, by=by):
990-
self.click(selector, by=by)
991+
try:
992+
if element.is_displayed():
993+
self.__scroll_to_element(element)
994+
element.click()
991995
click_count += 1
992-
else:
996+
self.wait_for_ready_state_complete()
997+
except ECI_Exception:
998+
continue # ElementClickInterceptedException (Overlay likely)
999+
except (StaleElementReferenceException, ENI_Exception):
9931000
self.wait_for_ready_state_complete()
1001+
time.sleep(0.03)
9941002
try:
9951003
if element.is_displayed():
9961004
self.__scroll_to_element(element)
9971005
element.click()
9981006
click_count += 1
1007+
self.wait_for_ready_state_complete()
9991008
except (StaleElementReferenceException, ENI_Exception):
1000-
self.wait_for_ready_state_complete()
1001-
time.sleep(0.05)
1002-
try:
1003-
if element.is_displayed():
1004-
self.__scroll_to_element(element)
1005-
element.click()
1006-
click_count += 1
1007-
except (StaleElementReferenceException, ENI_Exception):
1008-
return # Probably on new page / Elements are all stale
1009+
return # Probably on new page / Elements are all stale
10091010

10101011
def click_nth_visible_element(self, selector, number, by=By.CSS_SELECTOR):
10111012
""" Finds all matching page elements and clicks the nth visible one.
@@ -1051,6 +1052,9 @@ def is_element_in_an_iframe(self, selector, by=By.CSS_SELECTOR):
10511052
iframe_identifier = iframe['name']
10521053
elif iframe.has_attr('id') and len(iframe['id']) > 0:
10531054
iframe_identifier = iframe['id']
1055+
elif iframe.has_attr('class') and len(iframe['class']) > 0:
1056+
iframe_class = " ".join(iframe["class"])
1057+
iframe_identifier = '[class="%s"]' % iframe_class
10541058
else:
10551059
continue
10561060
self.switch_to_frame(iframe_identifier)

seleniumbase/fixtures/page_actions.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import sys
2525
import time
2626
import traceback
27+
from selenium.common.exceptions import StaleElementReferenceException
28+
from selenium.common import exceptions as selenium_exceptions
2729
from selenium.webdriver.common.by import By
2830
from selenium.webdriver.common.action_chains import ActionChains
2931
from selenium.webdriver.remote.errorhandler import ElementNotVisibleException
@@ -34,6 +36,7 @@
3436
from seleniumbase.config import settings
3537
from seleniumbase.core import log_helper
3638
from seleniumbase.fixtures import page_utils
39+
ENI_Exception = selenium_exceptions.ElementNotInteractableException
3740

3841

3942
def is_element_present(driver, selector, by=By.CSS_SELECTOR):
@@ -459,7 +462,17 @@ def find_visible_elements(driver, selector, by=By.CSS_SELECTOR):
459462
by - the type of selector being used (Default: By.CSS_SELECTOR)
460463
"""
461464
elements = driver.find_elements(by=by, value=selector)
462-
return [element for element in elements if element.is_displayed()]
465+
try:
466+
v_elems = [element for element in elements if element.is_displayed()]
467+
return v_elems
468+
except (StaleElementReferenceException, ENI_Exception):
469+
time.sleep(0.1)
470+
elements = driver.find_elements(by=by, value=selector)
471+
v_elems = []
472+
for element in elements:
473+
if element.is_displayed():
474+
v_elems.append(element)
475+
return v_elems
463476

464477

465478
def save_screenshot(driver, name, folder=None):

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545

4646
setup(
4747
name='seleniumbase',
48-
version='1.34.16',
48+
version='1.34.17',
4949
description='Fast, Easy, and Reliable Browser Automation & Testing.',
5050
long_description=long_description,
5151
long_description_content_type='text/markdown',

0 commit comments

Comments
 (0)