diff --git a/examples/cdp_mode/ReadMe.md b/examples/cdp_mode/ReadMe.md index 79e96643291..97b7edecd08 100644 --- a/examples/cdp_mode/ReadMe.md +++ b/examples/cdp_mode/ReadMe.md @@ -507,6 +507,7 @@ element.clear_input() element.click() element.flash(duration=0.5, color="EE4488") element.focus() +element.gui_click(timeframe=0.25) element.highlight_overlay() element.mouse_click() element.mouse_drag(destination) diff --git a/examples/cdp_mode/raw_cf.py b/examples/cdp_mode/raw_cf.py index 0d64a2d20e5..cb4652f9fa8 100644 --- a/examples/cdp_mode/raw_cf.py +++ b/examples/cdp_mode/raw_cf.py @@ -1,14 +1,14 @@ """Using CDP Mode with PyAutoGUI to bypass CAPTCHAs.""" from seleniumbase import SB -with SB(uc=True, test=True, locale_code="en") as sb: +with SB(uc=True, test=True, locale_code="en", incognito=True) as sb: url = "https://www.cloudflare.com/login" sb.activate_cdp_mode(url) sb.sleep(3) sb.uc_gui_handle_captcha() # PyAutoGUI press Tab and Spacebar sb.sleep(2) -with SB(uc=True, test=True, locale_code="en") as sb: +with SB(uc=True, test=True, locale_code="en", incognito=True) as sb: url = "https://www.cloudflare.com/login" sb.activate_cdp_mode(url) sb.sleep(2) diff --git a/examples/cdp_mode/raw_elal.py b/examples/cdp_mode/raw_elal.py index f5003db4f30..110b1e2b15c 100644 --- a/examples/cdp_mode/raw_elal.py +++ b/examples/cdp_mode/raw_elal.py @@ -26,6 +26,8 @@ print("*** Lowest Price: ***") lowest_price = sorted(prices)[0] print(lowest_price) + sb.cdp.scroll_down(12) + sb.sleep(1) sb.cdp.find_element_by_text(lowest_price).click() sb.sleep(1) search_cell = 'button[aria-label*="Search.cell.buttonTitle"]' diff --git a/examples/test_usefixtures.py b/examples/test_usefixtures.py index c08539961c5..1c7676105bc 100644 --- a/examples/test_usefixtures.py +++ b/examples/test_usefixtures.py @@ -4,6 +4,9 @@ @pytest.mark.usefixtures("sb") class Test_UseFixtures: def test_usefixtures_on_class(self): + if not hasattr(self, "sb"): + print("This test is for pytest only!") + return sb = self.sb sb.open("https://seleniumbase.io/realworld/login") sb.type("#username", "demo_user") diff --git a/mkdocs_build/requirements.txt b/mkdocs_build/requirements.txt index fc5cc0f18e8..cbf662fa655 100644 --- a/mkdocs_build/requirements.txt +++ b/mkdocs_build/requirements.txt @@ -14,7 +14,7 @@ pathspec==0.12.1 Babel==2.17.0 paginate==0.5.7 mkdocs==1.6.1 -mkdocs-material==9.6.4 +mkdocs-material==9.6.5 mkdocs-exclude-search==0.6.6 mkdocs-simple-hooks==0.1.5 mkdocs-material-extensions==1.3.1 diff --git a/requirements.txt b/requirements.txt index 2c05747d7f7..8763830f299 100755 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ filelock~=3.16.1;python_version<"3.9" filelock>=3.17.0;python_version>="3.9" fasteners>=0.19 mycdp>=1.1.0 -pynose>=1.5.3 +pynose>=1.5.4 platformdirs>=4.3.6 typing-extensions>=4.12.2 sbvirtualdisplay>=1.4.0 diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py index a304fe8573d..ae694d9e912 100755 --- a/seleniumbase/__version__.py +++ b/seleniumbase/__version__.py @@ -1,2 +1,2 @@ # seleniumbase package -__version__ = "4.34.16" +__version__ = "4.34.17" diff --git a/seleniumbase/core/sb_cdp.py b/seleniumbase/core/sb_cdp.py index 59a6a7e5328..2b0003df107 100644 --- a/seleniumbase/core/sb_cdp.py +++ b/seleniumbase/core/sb_cdp.py @@ -56,6 +56,9 @@ def __add_sync_methods(self, element): element, *args, **kwargs ) element.focus = lambda: self.__focus(element) + element.gui_click = ( + lambda *args, **kwargs: self.__gui_click(element, *args, **kwargs) + ) element.highlight_overlay = lambda: self.__highlight_overlay(element) element.mouse_click = lambda: self.__mouse_click(element) element.mouse_drag = ( @@ -426,6 +429,39 @@ def __focus(self, element): self.loop.run_until_complete(element.focus_async()) ) + def __gui_click(self, element, timeframe=None): + element.scroll_into_view() + self.__add_light_pause() + position = element.get_position() + x = position.x + y = position.y + e_width = position.width + e_height = position.height + # Relative to window + element_rect = {"height": e_height, "width": e_width, "x": x, "y": y} + window_rect = self.get_window_rect() + w_bottom_y = window_rect["y"] + window_rect["height"] + viewport_height = window_rect["innerHeight"] + x = window_rect["x"] + element_rect["x"] + y = w_bottom_y - viewport_height + element_rect["y"] + y_scroll_offset = window_rect["pageYOffset"] + y = y - y_scroll_offset + x = x + window_rect["scrollX"] + y = y + window_rect["scrollY"] + # Relative to screen + element_rect = {"height": e_height, "width": e_width, "x": x, "y": y} + e_width = element_rect["width"] + e_height = element_rect["height"] + e_x = element_rect["x"] + e_y = element_rect["y"] + x, y = ((e_x + e_width / 2.0) + 0.5), ((e_y + e_height / 2.0) + 0.5) + if not timeframe or not isinstance(timeframe, (int, float)): + timeframe = 0.25 + if timeframe > 3: + timeframe = 3 + self.gui_click_x_y(x, y, timeframe=timeframe) + return self.loop.run_until_complete(self.page.wait()) + def __highlight_overlay(self, element): return ( self.loop.run_until_complete(element.highlight_overlay_async()) @@ -461,9 +497,7 @@ def __press_keys(self, element, text): element.send_keys("\r\n") time.sleep(0.044) self.__slow_mode_pause_if_set() - return ( - self.loop.run_until_complete(self.page.wait()) - ) + return self.loop.run_until_complete(self.page.wait()) def __query_selector(self, element, selector): selector = self.__convert_to_css_if_xpath(selector) diff --git a/seleniumbase/plugins/base_plugin.py b/seleniumbase/plugins/base_plugin.py index 2c4f945a2cd..7ceb7568d42 100644 --- a/seleniumbase/plugins/base_plugin.py +++ b/seleniumbase/plugins/base_plugin.py @@ -208,7 +208,6 @@ def configure(self, options, conf): self.duration = float(0) self.page_results_list = [] self.test_count = 0 - self.import_error = False log_path = constants.Logs.LATEST + "/" archive_logs = options.archive_logs log_helper.log_folder_setup(log_path, archive_logs) @@ -238,6 +237,7 @@ def beforeTest(self, test): ) else: variables = {} + test.test.test_id = test.id() test.test.is_nosetest = True test.test.environment = self.options.environment test.test.env = self.options.environment # Add a shortened version @@ -263,17 +263,16 @@ def finalize(self, result): ) log_helper.clear_empty_logs() if self.report_on: - if not self.import_error: - report_helper.add_bad_page_log_file(self.page_results_list) - report_log_path = report_helper.archive_new_report_logs() - report_helper.build_report( - report_log_path, - self.page_results_list, - self.successes, - self.failures, - self.options.browser, - self.show_report, - ) + report_helper.add_bad_page_log_file(self.page_results_list) + report_log_path = report_helper.archive_new_report_logs() + report_helper.build_report( + report_log_path, + self.page_results_list, + self.successes, + self.failures, + self.options.browser, + self.show_report, + ) def addSuccess(self, test, capt): if self.report_on: @@ -293,9 +292,6 @@ def add_fails_or_errors(self, test, err): "%.2fs" % (float(time.time()) - float(self.start_time)) ) if test.id() == "nose.failure.Failure.runTest": - print(">>> ERROR: Could not locate tests to run!") - print(">>> The Test Report WILL NOT be generated!") - self.import_error = True return self.failures.append(test.id()) self.page_results_list.append( @@ -314,6 +310,7 @@ def add_fails_or_errors(self, test, err): test._log_fail_data() sb_config._excinfo_tb = err log_path = None + source = None if hasattr(sb_config, "_test_logpath"): log_path = sb_config._test_logpath if hasattr(sb_config, "_last_page_source"): diff --git a/seleniumbase/plugins/selenium_plugin.py b/seleniumbase/plugins/selenium_plugin.py index ba2fc7b59c2..20d48b2eeb9 100644 --- a/seleniumbase/plugins/selenium_plugin.py +++ b/seleniumbase/plugins/selenium_plugin.py @@ -1309,6 +1309,7 @@ def beforeTest(self, test): test.test.dashboard = False test.test._multithreaded = False test.test._reuse_session = False + sb_config.recorder_mode = test.test.recorder_mode sb_config.no_screenshot = test.test.no_screenshot_after_test if test.test.servername != "localhost": # Using Selenium Grid diff --git a/setup.py b/setup.py index 76871d7666f..e4890264478 100755 --- a/setup.py +++ b/setup.py @@ -161,7 +161,7 @@ 'filelock>=3.17.0;python_version>="3.9"', 'fasteners>=0.19', "mycdp>=1.1.0", - "pynose>=1.5.3", + "pynose>=1.5.4", 'platformdirs>=4.3.6', 'typing-extensions>=4.12.2', "sbvirtualdisplay>=1.4.0",