Skip to content

Fix bugs with --archive-logs and headless Firefox on Linux without Xvfb #1815

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions mkdocs_build/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion seleniumbase/__version__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# seleniumbase package
__version__ = "4.13.15"
__version__ = "4.13.16"
26 changes: 20 additions & 6 deletions seleniumbase/console_scripts/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand All @@ -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"
Expand All @@ -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"
Expand Down
36 changes: 29 additions & 7 deletions seleniumbase/core/browser_launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand All @@ -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 (
Expand All @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion seleniumbase/plugins/pytest_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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] = "-"
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"',
Expand Down Expand Up @@ -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",
Expand Down