diff --git a/help_docs/method_summary.md b/help_docs/method_summary.md index 5ab81a3a..5be4f135 100644 --- a/help_docs/method_summary.md +++ b/help_docs/method_summary.md @@ -370,6 +370,8 @@ self.highlight_type(selector, text, by="css selector", loops=3, scroll=True, tim # self.highlight_update_text( # selector, text, by="css selector", loops=3, scroll=True, timeout=None) +self.highlight_if_visible(selector, by="css selector", loops=4, scroll=True) + self.highlight(selector, by="css selector", loops=4, scroll=True, timeout=None) self.press_up_arrow(selector="html", times=1, by="css selector") @@ -742,6 +744,7 @@ self.generate_traffic_chain(pages, loops=1) self.get_element(selector, by="css selector", timeout=None) # Duplicates: +# self.wait_for_selector(selector, by="css selector", timeout=None) # self.locator(selector, by="css selector", timeout=None) # self.wait_for_element_present(selector, by="css selector", timeout=None) @@ -957,6 +960,12 @@ driver.assert_exact_text(text, selector) driver.wait_for_element(selector) +driver.wait_for_element_visible(selector) + +driver.wait_for_element_present(selector) + +driver.wait_for_selector(selector) + driver.wait_for_text(text, selector) driver.wait_for_exact_text(text, selector) @@ -991,6 +1000,8 @@ driver.highlight(selector) driver.highlight_click(selector) +driver.highlight_if_visible(selector) + driver.sleep(seconds) driver.locator(selector) @@ -1015,6 +1026,10 @@ driver.uc_open_with_reconnect(url, reconnect_time=None) driver.reconnect(timeout) +driver.disconnect() + +driver.connect() + driver.uc_click( selector, by="css selector", timeout=settings.SMALL_TIMEOUT, reconnect_time=None) diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py index 6481f7f0..fe2ef6fc 100644 --- a/seleniumbase/core/browser_launcher.py +++ b/seleniumbase/core/browser_launcher.py @@ -169,6 +169,9 @@ def extend_driver(driver): driver.assert_text = DM.assert_text driver.assert_exact_text = DM.assert_exact_text driver.wait_for_element = DM.wait_for_element + driver.wait_for_element_visible = DM.wait_for_element_visible + driver.wait_for_element_present = DM.wait_for_element_present + driver.wait_for_selector = DM.wait_for_selector driver.wait_for_text = DM.wait_for_text driver.wait_for_exact_text = DM.wait_for_exact_text driver.wait_for_and_accept_alert = DM.wait_for_and_accept_alert @@ -186,6 +189,7 @@ def extend_driver(driver): driver.get_user_agent = DM.get_user_agent driver.highlight = DM.highlight driver.highlight_click = DM.highlight_click + driver.highlight_if_visible = DM.highlight_if_visible driver.sleep = time.sleep driver.get_attribute = DM.get_attribute driver.get_page_source = DM.get_page_source @@ -458,27 +462,34 @@ def uc_click( by = "css selector" except Exception: pass - element = driver.wait_for_element(selector, by=by, timeout=timeout) + element = driver.wait_for_selector(selector, by=by, timeout=timeout) + if not element.tag_name == "span": # Element must be "visible" + element = driver.wait_for_element(selector, by=by, timeout=timeout) try: element.uc_click( driver, selector, by=by, reconnect_time=reconnect_time ) except ElementClickInterceptedException: + time.sleep(0.16) driver.js_click(selector, by=by, timeout=timeout) + if not reconnect_time: + driver.reconnect(0.1) + else: + driver.reconnect(reconnect_time) def uc_switch_to_frame(driver, frame, reconnect_time=None): from selenium.webdriver.remote.webelement import WebElement if isinstance(frame, WebElement): if not reconnect_time: - driver.reconnect(0.15) + driver.reconnect(0.1) else: driver.reconnect(reconnect_time) driver.switch_to.frame(frame) else: iframe = driver.locator(frame) if not reconnect_time: - driver.reconnect(0.15) + driver.reconnect(0.1) else: driver.reconnect(reconnect_time) driver.switch_to.frame(iframe) diff --git a/seleniumbase/core/sb_driver.py b/seleniumbase/core/sb_driver.py index 1c183167..f5054173 100644 --- a/seleniumbase/core/sb_driver.py +++ b/seleniumbase/core/sb_driver.py @@ -97,6 +97,15 @@ class DriverMethods(): def wait_for_element(self, *args, **kwargs): return page_actions.wait_for_element(self.driver, *args, **kwargs) + def wait_for_element_visible(self, *args, **kwargs): + return page_actions.wait_for_element(self.driver, *args, **kwargs) + + def wait_for_element_present(self, *args, **kwargs): + return page_actions.wait_for_selector(self.driver, *args, **kwargs) + + def wait_for_selector(self, *args, **kwargs): + return page_actions.wait_for_selector(self.driver, *args, **kwargs) + def wait_for_text(self, *args, **kwargs): return page_actions.wait_for_text(self.driver, *args, **kwargs) @@ -147,6 +156,8 @@ class DriverMethods(): return js_utils.get_user_agent(self.driver, *args, **kwargs) def highlight(self, *args, **kwargs): + if "scroll" in kwargs: + kwargs.pop("scroll") w_args = kwargs.copy() if "loops" in w_args: w_args.pop("loops") @@ -161,8 +172,16 @@ class DriverMethods(): self.highlight(*args, **kwargs) if "loops" in kwargs: kwargs.pop("loops") + if "scroll" in kwargs: + kwargs.pop("scroll") page_actions.click(self.driver, *args, **kwargs) + def highlight_if_visible( + self, selector, by="css selector", loops=4, scroll=True + ): + if self.is_element_visible(selector, by=by): + self.highlight(selector, by=by, loops=loops, scroll=scroll) + def switch_to_frame(self, frame): if isinstance(frame, WebElement): self.driver.switch_to.frame(frame) diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index da5c0fd1..b838a4ca 100644 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -5601,6 +5601,14 @@ class BaseCase(unittest.TestCase): self.__highlight(selector, by=by, loops=loops, scroll=scroll) self.update_text(selector, text, by=by) + def highlight_if_visible( + self, selector, by="css selector", loops=4, scroll=True, + ): + """Highlights the element if the element is visible.""" + self.__check_scope() + if self.is_element_visible(selector, by=by): + self.__highlight(selector, by=by, loops=loops, scroll=scroll) + def __highlight( self, selector, by="css selector", loops=None, scroll=True ): @@ -9089,6 +9097,11 @@ class BaseCase(unittest.TestCase): The element does not need be visible (it may be hidden).""" return self.wait_for_element_present(selector, by=by, timeout=timeout) + def wait_for_selector(self, selector, by="css selector", timeout=None): + """Same as wait_for_element_present() - returns the element. + The element does not need be visible (it may be hidden).""" + return self.wait_for_element_present(selector, by=by, timeout=timeout) + def wait_for_query_selector( self, selector, by="css selector", timeout=None ): diff --git a/seleniumbase/fixtures/page_actions.py b/seleniumbase/fixtures/page_actions.py index 33eb3f1a..fc69a491 100644 --- a/seleniumbase/fixtures/page_actions.py +++ b/seleniumbase/fixtures/page_actions.py @@ -1752,6 +1752,27 @@ def wait_for_element( ) +def wait_for_selector( + driver, + selector, + by="css selector", + timeout=settings.LARGE_TIMEOUT, +): + original_selector = None + if page_utils.is_valid_by(by): + original_selector = selector + elif page_utils.is_valid_by(selector): + original_selector = by + selector, by = page_utils.recalculate_selector(selector, by) + return wait_for_element_present( + driver=driver, + selector=selector, + by=by, + timeout=timeout, + original_selector=original_selector, + ) + + def wait_for_text( driver, text, diff --git a/seleniumbase/undetected/__init__.py b/seleniumbase/undetected/__init__.py index 4c8dd9c8..7e58bc37 100644 --- a/seleniumbase/undetected/__init__.py +++ b/seleniumbase/undetected/__init__.py @@ -442,6 +442,28 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver): except Exception: pass + def disconnect(self): + """Stops the chromedriver service that runs in the background. + To use driver methods again, you MUST call driver.connect()""" + if hasattr(self, "service"): + try: + self.service.stop() + except Exception: + pass + + def connect(self): + """Starts the chromedriver service that runs in the background + and recreates the session.""" + if hasattr(self, "service"): + try: + self.service.start() + except Exception: + pass + try: + self.start_session() + except Exception: + pass + def start_session(self, capabilities=None): if not capabilities: capabilities = self.options.to_capabilities()