diff --git a/help_docs/method_summary.md b/help_docs/method_summary.md index a9267810148..9a9cb37d9fc 100644 --- a/help_docs/method_summary.md +++ b/help_docs/method_summary.md @@ -161,7 +161,7 @@ self.set_window_position(x, y) self.maximize_window() self.minimize_window() self.reset_window_size() -self.switch_to_frame(frame="iframe", timeout=None) +self.switch_to_frame(frame="iframe", timeout=None, invisible=False) self.switch_to_default_content() self.switch_to_parent_frame() with self.frame_switch(frame, timeout=None): diff --git a/requirements.txt b/requirements.txt index 3806ba3b716..ebf9051c68a 100755 --- a/requirements.txt +++ b/requirements.txt @@ -5,7 +5,7 @@ setuptools~=70.2;python_version<"3.10" setuptools>=80.9.0;python_version>="3.10" wheel>=0.45.1 attrs>=25.3.0 -certifi>=2025.6.15 +certifi>=2025.7.9 exceptiongroup>=1.3.0 websockets~=13.1;python_version<"3.9" websockets>=15.0.1;python_version>="3.9" diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py index 60a75a7ccaf..0afde471397 100755 --- a/seleniumbase/__version__.py +++ b/seleniumbase/__version__.py @@ -1,2 +1,2 @@ # seleniumbase package -__version__ = "4.40.2" +__version__ = "4.40.3" diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index 8c8018e4031..d9a44881820 100644 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -3591,7 +3591,7 @@ def reset_window_size(self): self.set_window_rect(x, y, width, height) self.__demo_mode_pause_if_active(tiny=True) - def switch_to_frame(self, frame="iframe", timeout=None): + def switch_to_frame(self, frame="iframe", timeout=None, invisible=False): """Wait for an iframe to appear, and switch to it. This should be usable as a drop-in replacement for driver.switch_to.frame(). The iframe identifier can be a selector, an index, an id, a name, @@ -3599,7 +3599,8 @@ def switch_to_frame(self, frame="iframe", timeout=None): for visible iframes with a string selector. @Params frame - the frame element, name, id, index, or selector - timeout - the time to wait for the alert in seconds """ + timeout - the time to wait for the alert in seconds + invisible - if True, the iframe can be invisible """ self.__check_scope() if not timeout: timeout = settings.LARGE_TIMEOUT @@ -3649,7 +3650,9 @@ def switch_to_frame(self, frame="iframe", timeout=None): time.sleep(0.035) if self.undetectable: time.sleep(0.035) - page_actions.switch_to_frame(self.driver, frame, timeout) + page_actions.switch_to_frame( + self.driver, frame, timeout, invisible=invisible + ) self.wait_for_ready_state_complete() if self.__needs_minimum_wait(): time.sleep(0.015) diff --git a/seleniumbase/fixtures/page_actions.py b/seleniumbase/fixtures/page_actions.py index ac84428d9be..66b0bf554dc 100644 --- a/seleniumbase/fixtures/page_actions.py +++ b/seleniumbase/fixtures/page_actions.py @@ -1572,7 +1572,9 @@ def wait_for_and_switch_to_alert(driver, timeout=settings.LARGE_TIMEOUT): timeout_exception(Exception, message) -def switch_to_frame(driver, frame, timeout=settings.SMALL_TIMEOUT): +def switch_to_frame( + driver, frame, timeout=settings.SMALL_TIMEOUT, invisible=False +): """ Wait for an iframe to appear, and switch to it. This should be usable as a drop-in replacement for driver.switch_to.frame(). @@ -1580,6 +1582,7 @@ def switch_to_frame(driver, frame, timeout=settings.SMALL_TIMEOUT): driver - the webdriver object (required) frame - the frame element, name, id, index, or selector timeout - the time to wait for the alert in seconds + invisible - if True, the iframe can be invisible """ _reconnect_if_disconnected(driver) start_ms = time.time() * 1000.0 @@ -1596,7 +1599,10 @@ def switch_to_frame(driver, frame, timeout=settings.SMALL_TIMEOUT): by = "xpath" else: by = "css selector" - if is_element_visible(driver, frame, by=by): + if ( + is_element_visible(driver, frame, by=by) + or (invisible and is_element_present(driver, frame, by=by)) + ): with suppress(Exception): element = driver.find_element(by=by, value=frame) driver.switch_to.frame(element) @@ -1608,8 +1614,12 @@ def switch_to_frame(driver, frame, timeout=settings.SMALL_TIMEOUT): plural = "s" if timeout == 1: plural = "" - message = "Frame {%s} was not visible after %s second%s!" % ( + presence = "visible" + if invisible: + presence = "present" + message = "Frame {%s} was not %s after %s second%s!" % ( frame, + presence, timeout, plural, ) diff --git a/setup.py b/setup.py index a7279207bf0..27339fbcb52 100755 --- a/setup.py +++ b/setup.py @@ -153,7 +153,7 @@ 'setuptools>=80.9.0;python_version>="3.10"', 'wheel>=0.45.1', 'attrs>=25.3.0', - "certifi>=2025.6.15", + "certifi>=2025.7.9", "exceptiongroup>=1.3.0", 'websockets~=13.1;python_version<"3.9"', 'websockets>=15.0.1;python_version>="3.9"',