From b3c995f19ae48c82dd04948f930918332a2ac5f6 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Tue, 21 Mar 2023 21:44:26 -0400 Subject: [PATCH 1/6] Fix bug with "--archive-logs" --- seleniumbase/plugins/pytest_plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seleniumbase/plugins/pytest_plugin.py b/seleniumbase/plugins/pytest_plugin.py index 2a72e0728b3..550fe1b0e3b 100644 --- a/seleniumbase/plugins/pytest_plugin.py +++ b/seleniumbase/plugins/pytest_plugin.py @@ -1718,8 +1718,8 @@ def _create_dashboard_assets_(): def pytest_itemcollected(item): if "--co" in sys_argv or "--collect-only" in sys_argv: return + sb_config.item_count += 1 if sb_config.dashboard: - sb_config.item_count += 1 test_id, display_id = _get_test_ids_(item) sb_config._results[test_id] = "Untested" sb_config._duration[test_id] = "-" From 7fe33060097e7d7e05925fd896c5dc1e51e6bc93 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Tue, 21 Mar 2023 21:47:12 -0400 Subject: [PATCH 2/6] Fix bug with headless Firefox on Linux without Xvfb --- seleniumbase/core/browser_launcher.py | 36 +++++++++++++++++++++------ 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py index 4835bf53011..ac468a3c7de 100644 --- a/seleniumbase/core/browser_launcher.py +++ b/seleniumbase/core/browser_launcher.py @@ -847,6 +847,11 @@ def _set_firefox_options( ) if headless and not IS_LINUX: options.add_argument("--headless") + elif headless and IS_LINUX: + # This assumes Xvfb is running, which prevents many Linux issues. + # If not, we'll fix this later during the error-handling process. + # To override this feature: ``pytest --firefox-arg="-headless"``. + pass if locale_code: options.set_preference("intl.accept_languages", locale_code) options.set_preference("browser.shell.checkDefaultBrowser", False) @@ -1972,10 +1977,18 @@ def get_local_driver( or "A connection attempt failed" in e.msg ) ): - # Firefox probably just auto-updated itself, - # which causes intermittent issues to occur. - # Trying again right after that often works. time.sleep(0.1) + if ( + IS_LINUX + and headless + and ( + "unexpected" in str(e) + or ( + hasattr(e, "msg") and "unexpected" in e.msg + ) + ) + ): + firefox_options.add_argument("-headless") return webdriver.Firefox( service=service, options=firefox_options, @@ -1993,7 +2006,8 @@ def get_local_driver( service = FirefoxService(log_path=os.devnull) try: return webdriver.Firefox( - service=service, options=firefox_options + service=service, + options=firefox_options, ) except BaseException as e: if ( @@ -2008,10 +2022,18 @@ def get_local_driver( or "A connection attempt failed" in e.msg ) ): - # Firefox probably just auto-updated itself, - # which causes intermittent issues to occur. - # Trying again right after that often works. time.sleep(0.1) + if ( + IS_LINUX + and headless + and ( + "unexpected" in str(e) + or ( + hasattr(e, "msg") and "unexpected" in e.msg + ) + ) + ): + firefox_options.add_argument("-headless") return webdriver.Firefox( service=service, options=firefox_options, From 2788159283c1395b2895d5d583eaecc85837f37b Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Tue, 21 Mar 2023 21:50:59 -0400 Subject: [PATCH 3/6] Update commands: "sbase methods" & "sbase options" --- seleniumbase/console_scripts/run.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/seleniumbase/console_scripts/run.py b/seleniumbase/console_scripts/run.py index bc6c84a529b..db1fe08e927 100644 --- a/seleniumbase/console_scripts/run.py +++ b/seleniumbase/console_scripts/run.py @@ -717,15 +717,18 @@ def show_methods(): sbm += "*.type(selector, text) => Update the field with the text.\n" sbm += "*.click(selector) => Click the element with the selector.\n" sbm += "*.click_link(link_text) => Click the link containing text.\n" - sbm += "*.go_back() => Navigate back to the previous URL.\n" + sbm += "*.check_if_unchecked(selector) => Check checkbox if unchecked.\n" + sbm += "*.uncheck_if_checked(selector) => Uncheck checkbox if checked.\n" sbm += "*.select_option_by_text(dropdown_selector, option)\n" sbm += "*.hover_and_click(hover_selector, click_selector)\n" sbm += "*.drag_and_drop(drag_selector, drop_selector)\n" + sbm += "*.choose_file(selector, file_path) => Choose a file to upload.\n" sbm += "*.get_text(selector) => Get the text from the element.\n" sbm += "*.get_current_url() => Get the URL of the current page.\n" sbm += "*.get_page_source() => Get the HTML of the current page.\n" sbm += "*.get_attribute(selector, attribute) => Get element attribute.\n" sbm += "*.get_title() => Get the title of the current page.\n" + sbm += "*.go_back() => Navigate to the previous page in history.\n" sbm += "*.switch_to_frame(frame) => Switch into the iframe container.\n" sbm += "*.switch_to_default_content() => Exit all iframe containers.\n" sbm += "*.switch_to_parent_frame() => Exit from the current iframe.\n" @@ -736,13 +739,20 @@ def show_methods(): sbm += "*.switch_to_driver(driver) => Switch to the browser driver.\n" sbm += "*.switch_to_default_driver() => Switch to the original driver.\n" sbm += "*.wait_for_element(selector) => Wait until element is visible.\n" + sbm += "*.wait_for_element_present(selector) => Until element in HTML.\n" sbm += "*.is_element_visible(selector) => Return element visibility.\n" + sbm += "*.is_element_present(selector) => Return element is in HTML.\n" sbm += "*.is_text_visible(text, selector) => Return text visibility.\n" + sbm += "*.is_checked(selector) => Return whether the box is checked.\n" sbm += "*.sleep(seconds) => Do nothing for the given amount of time.\n" sbm += "*.save_screenshot(name) => Save a screenshot in .png format.\n" sbm += "*.assert_element(selector) => Verify the element is visible.\n" sbm += "*.assert_text(text, selector) => Verify text in the element.\n" + sbm += "*.assert_exact_text(text, selector) => Verify text is exact.\n" + sbm += "*.assert_url(url) => Verify that the current URL is the URL.\n" + sbm += "*.assert_url_contains(substring) => Verify substring in URL.\n" sbm += "*.assert_title(title) => Verify the title of the web page.\n" + sbm += "*.assert_title_contains(substring) => Verify STR in title.\n" sbm += "*.assert_downloaded_file(file) => Verify file was downloaded.\n" sbm += "*.assert_no_404_errors() => Verify there are no broken links.\n" sbm += "*.assert_no_js_errors() => Verify there are no JS errors.\n" @@ -769,15 +779,17 @@ def show_options(): line = '(Some options are Chromium-specific, e.g. "--guest --mobile")' print(line) op = "\n" - op += '--browser=BROWSER (The web browser to use. Default is "chrome")\n' - op += "--headless (Run tests headlessly. Default mode on Linux OS.)\n" + op += '--browser=BROWSER (Choice of web browser. Default is "chrome".)\n' + op += "--edge / --firefox / --safari (Shortcut for browser selection.)\n" + op += "--headless (Run tests headlessly. Default setting on Linux OS.)\n" op += "--demo (Slow down and visually see test actions as they occur.)\n" op += "--slow (Slow down the automation. Faster than using Demo Mode.)\n" op += "--reuse-session / --rs (Reuse browser session between tests.)\n" + op += "--reuse-class-session / --rcs (RS, but for class tests only.)\n" op += "--crumbs (Clear all cookies between tests reusing a session.)\n" op += "--maximize (Start tests with the web browser window maximized.)\n" op += "--dashboard (Enable SeleniumBase's Dashboard at dashboard.html)\n" - op += "--uc (Enable undetected-chromedriver to evade bot-detection.)\n" + op += "--uc (Use undetected-chromedriver mode to evade bot-detection.)\n" op += "--incognito (Enable Chromium's Incognito mode.)\n" op += "--guest (Enable Chromium's Guest mode.)\n" op += "-m=MARKER (Run tests with the specified pytest marker.)\n" @@ -794,10 +806,12 @@ def show_options(): op += " | return / r: Run until method returns. j: Jump to line. |\n" op += " | where / w: Show stack spot. u: Up stack. d: Down stack. |\n" op += " | longlist / ll: See code. dir(): List namespace objects. |\n" + op += "--help / -h (Display list of all available pytest options.)\n" op += "--final-debug (Enter Final Debug Mode after each test ends.)\n" - op += "--recorder (Record browser actions to generate test scripts.)\n" + op += "--recorder / --rec (Save browser actions as Python scripts.)\n" + op += "--rec-behave / --rec-gherkin (Save actions as Gherkin code.)\n" op += "--save-screenshot (Save a screenshot at the end of each test.)\n" - op += "--archive-logs (Archive old log files instead of deleting them.)\n" + op += "--archive-logs (Archive logs after tests to prevent deletion.)\n" op += "--check-js (Check for JavaScript errors after page loads.)\n" op += "--start-page=URL (The browser start page when tests begin.)\n" op += "--agent=STRING (Modify the web browser's User-Agent string.)\n" From e7519f7f2eff3a4228c2a5397d8a55188fae64af Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Tue, 21 Mar 2023 21:52:38 -0400 Subject: [PATCH 4/6] Update mkdocs dependencies --- mkdocs_build/requirements.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mkdocs_build/requirements.txt b/mkdocs_build/requirements.txt index ecd680f3feb..a4b0123c00e 100644 --- a/mkdocs_build/requirements.txt +++ b/mkdocs_build/requirements.txt @@ -14,15 +14,15 @@ click==8.1.3 ghp-import==2.1.0 readme-renderer==37.3 pymdown-extensions==9.10 -importlib-metadata==6.0.0 -pipdeptree==2.5.2 +importlib-metadata==6.1.0 +pipdeptree==2.6.0 bleach==6.0.0 lunr==0.6.2 nltk==3.8.1 tornado==6.2 -watchdog==2.3.1 +watchdog==3.0.0 cairocffi==1.5.0 -cairosvg==2.6.0 +cairosvg==2.7.0 cssselect2==0.7.0 tinycss2==1.2.1 defusedxml==0.7.1 From bd33162d41f417a0639b0f022fc90f328de00d28 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Tue, 21 Mar 2023 21:53:14 -0400 Subject: [PATCH 5/6] Refresh Python dependencies --- requirements.txt | 4 ++-- setup.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/requirements.txt b/requirements.txt index 122b11250f2..68e85e9ab2c 100755 --- a/requirements.txt +++ b/requirements.txt @@ -41,7 +41,7 @@ sniffio==1.3.0;python_version>="3.7" h11==0.14.0;python_version>="3.7" outcome==1.2.0;python_version>="3.7" trio==0.22.0;python_version>="3.7" -trio-websocket==0.10.0;python_version>="3.7" +trio-websocket==0.10.2;python_version>="3.7" websockets==10.4;python_version>="3.7" pyopenssl==23.0.0;python_version>="3.7" wsproto==1.2.0;python_version>="3.7" @@ -75,7 +75,7 @@ sbvirtualdisplay==1.2.0 behave==1.2.6 soupsieve==2.3.2.post1;python_version<"3.7" soupsieve==2.4;python_version>="3.7" -beautifulsoup4==4.11.2 +beautifulsoup4==4.12.0 cryptography==36.0.2;python_version<"3.7" cryptography==39.0.2;python_version>="3.7" pygments==2.14.0 diff --git a/setup.py b/setup.py index 2a58f66a416..32666393968 100755 --- a/setup.py +++ b/setup.py @@ -165,7 +165,7 @@ 'h11==0.14.0;python_version>="3.7"', 'outcome==1.2.0;python_version>="3.7"', 'trio==0.22.0;python_version>="3.7"', - 'trio-websocket==0.10.0;python_version>="3.7"', + 'trio-websocket==0.10.2;python_version>="3.7"', 'websockets==10.4;python_version>="3.7"', 'pyopenssl==23.0.0;python_version>="3.7"', 'wsproto==1.2.0;python_version>="3.7"', @@ -199,7 +199,7 @@ "behave==1.2.6", 'soupsieve==2.3.2.post1;python_version<"3.7"', 'soupsieve==2.4;python_version>="3.7"', - "beautifulsoup4==4.11.2", + "beautifulsoup4==4.12.0", 'cryptography==36.0.2;python_version<"3.7"', 'cryptography==39.0.2;python_version>="3.7"', "pygments==2.14.0", From 39708743f6e8037d10f53a733fdbf3a9e5ca33b7 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Tue, 21 Mar 2023 21:53:47 -0400 Subject: [PATCH 6/6] Version 4.13.16 --- seleniumbase/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py index 4c591f77781..c3bc2c94d50 100755 --- a/seleniumbase/__version__.py +++ b/seleniumbase/__version__.py @@ -1,2 +1,2 @@ # seleniumbase package -__version__ = "4.13.15" +__version__ = "4.13.16"