diff --git a/examples/boilerplates/samples/test_page_objects.py b/examples/boilerplates/samples/test_page_objects.py index c485fd1b893..bc08dae243d 100644 --- a/examples/boilerplates/samples/test_page_objects.py +++ b/examples/boilerplates/samples/test_page_objects.py @@ -34,10 +34,12 @@ def do_search_and_click(self, sb, search_term): class MyTests(BaseCase): def test_page_objects(self): - if self.headless and self._multithreaded: + if self.headless: self.open_if_not_url("about:blank") - print("\n Skipping test in headless multi-threaded mode.") - self.skip("Skipping test in headless multi-threaded mode.") + print("\n Skipping test in headless mode.") + self.skip("Skipping test in headless mode.") + if not self.undetectable: + self.get_new_driver(undetectable=True) search_term = "SeleniumBase.io Docs" expected_text = "SeleniumBase" GooglePage().go_to_google(self) diff --git a/examples/cdp_mode/raw_cdp_turnstile.py b/examples/cdp_mode/raw_cdp_turnstile.py index 6a5aab576a0..34bab0f3888 100644 --- a/examples/cdp_mode/raw_cdp_turnstile.py +++ b/examples/cdp_mode/raw_cdp_turnstile.py @@ -4,5 +4,6 @@ sb = sb_cdp.Chrome(url) sb.gui_click_captcha() sb.assert_element("img#captcha-success") -sb.sleep(2) +sb.set_messenger_theme(location="top_left") +sb.post_message("SeleniumBase wasn't detected", duration=3) sb.driver.stop() diff --git a/examples/test_hack_search.py b/examples/test_hack_search.py index 80090729a57..9f27e4c480d 100644 --- a/examples/test_hack_search.py +++ b/examples/test_hack_search.py @@ -12,20 +12,21 @@ def test_hack_search(self): self.open_if_not_url("about:blank") print("\n Skipping test in headless mode.") self.skip('Skipping test in headless mode.') + if not self.undetectable: + self.get_new_driver(undetectable=True) self.open("https://google.com/ncr") self.hide_elements("iframe") self.assert_element('[title="Search"]') self.sleep(0.5) self.set_attribute('[action="/search"]', "action", "//bing.com/search") self.set_attributes('[value="Google Search"]', "value", "Bing Search") - self.type('[title="Search"]', "GitHub SeleniumBase Docs Install") + self.type('[title="Search"]', "SeleniumBase GitHub Page URL") self.sleep(0.5) self.js_click('[value="Bing Search"]') self.highlight("h1.b_logo", loops=8) - self.highlight_click('[href*="github.com/seleniumbase/SeleniumBase"]') - self.highlight_click('[href="/seleniumbase/SeleniumBase"]') - self.assert_text("SeleniumBase", "strong a") - self.highlight("strong a") + source = self.get_page_source() + self.assert_true("github.com/seleniumbase/SeleniumBase" in source) + self.click('a:contains("seleniumbase/SeleniumBase")') self.js_click('a[title="examples"]') self.highlight('#repo-content-turbo-frame') self.js_click('a[title="test_hack_search.py"]') diff --git a/help_docs/how_it_works.md b/help_docs/how_it_works.md index e97a0e0607c..4e6b8f6f834 100644 --- a/help_docs/how_it_works.md +++ b/help_docs/how_it_works.md @@ -4,7 +4,7 @@ -👁️🔎 The primary [SeleniumBase syntax format](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/syntax_formats.md) works by extending [pytest](https://docs.pytest.org/en/latest/) as a direct plugin. SeleniumBase automatically spins up web browsers for tests (using [Selenium WebDriver](https://www.selenium.dev/documentation/webdriver/)), and then gives those tests access to the SeleniumBase libraries through the [BaseCase class](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/fixtures/base_case.py). Tests are also given access to [SeleniumBase command-line options](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/customizing_test_runs.md) and [SeleniumBase methods](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/method_summary.md), which provide additional functionality. +👁️🔎 The primary [SeleniumBase syntax format](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/syntax_formats.md) works by extending [pytest](https://docs.pytest.org/en/latest/) as a direct plugin. SeleniumBase automatically spins up web browsers for tests, and then gives those tests access to the SeleniumBase libraries through the [BaseCase class](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/fixtures/base_case.py). Tests are also given access to [SeleniumBase command-line options](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/customizing_test_runs.md) and [SeleniumBase methods](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/method_summary.md). 👁️🔎 ``pytest`` uses a feature called test discovery to automatically find and run Python methods that start with ``test_`` when those methods are located in Python files that start with ``test_`` or end with ``_test.py``. @@ -50,7 +50,7 @@ BaseCase.main(__name__, __file__) class TestSimpleLogin(BaseCase): def test_simple_login(self): - self.open("https://seleniumbase.io/simple/login") + self.open("seleniumbase.io/simple/login") self.type("#username", "demo_user") self.type("#password", "secret_pass") self.click('a:contains("Sign in")') @@ -80,7 +80,7 @@ from seleniumbase import Driver driver = Driver() try: - driver.get("https://seleniumbase.io/simple/login") + driver.open("seleniumbase.io/simple/login") driver.type("#username", "demo_user") driver.type("#password", "secret_pass") driver.click('a:contains("Sign in")') diff --git a/help_docs/install.md b/help_docs/install.md index c0a5f73230e..470473eee1e 100644 --- a/help_docs/install.md +++ b/help_docs/install.md @@ -47,7 +47,6 @@ pip install git+https://github.com/seleniumbase/SeleniumBase.git@master#egg=sele * (Add ``--upgrade`` OR ``-U`` to upgrade SeleniumBase.) * (Add ``--force-reinstall`` to upgrade indirect libraries.) -* (Use ``pip3`` if multiple versions of Python are present.) (If you're not using a virtual environment, you may need to add ``--user`` to your ``pip`` command if you're seeing errors during installation.) diff --git a/mkdocs_build/prepare.py b/mkdocs_build/prepare.py index e2a000fe5c6..1e268808ae6 100644 --- a/mkdocs_build/prepare.py +++ b/mkdocs_build/prepare.py @@ -117,7 +117,7 @@ def main(*args, **kwargs): for file_ in updated_files_to_process: readme_file = "./mkdocs_build/" + file_ - with open(readme_file, "r", encoding="utf-8") as f: + with open(readme_file, mode="r", encoding="utf-8") as f: all_code = f.read() code_lines = all_code.split("\n") @@ -195,6 +195,6 @@ def main(*args, **kwargs): ) seleniumbase_lines.append(line) if changed: - out_file = open(readme_file, "w+", encoding="utf-8") + out_file = open(readme_file, mode="w+", encoding="utf-8") out_file.writelines("\r\n".join(seleniumbase_lines)) out_file.close() diff --git a/requirements.txt b/requirements.txt index a2c52fc2523..9ea30632e58 100755 --- a/requirements.txt +++ b/requirements.txt @@ -33,7 +33,7 @@ pyyaml>=6.0.3 pygments>=2.19.2 pyreadline3>=3.5.4;platform_system=="Windows" tabcompleter>=1.4.0 -pdbp>=1.7.1 +pdbp>=1.8.0 idna>=3.11 chardet==5.2.0 charset-normalizer>=3.4.4,<4 diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py index 5116ba8828f..a61c32f5597 100755 --- a/seleniumbase/__version__.py +++ b/seleniumbase/__version__.py @@ -1,2 +1,2 @@ # seleniumbase package -__version__ = "4.43.1" +__version__ = "4.43.2" diff --git a/seleniumbase/behave/behave_sb.py b/seleniumbase/behave/behave_sb.py index cc447014fc2..991ec5fc088 100644 --- a/seleniumbase/behave/behave_sb.py +++ b/seleniumbase/behave/behave_sb.py @@ -1216,24 +1216,24 @@ def _create_dashboard_assets_(): add_pytest_style_css = True if os.path.exists(pytest_style_css): existing_pytest_style = None - with open(pytest_style_css, "r") as f: + with open(pytest_style_css, mode="r") as f: existing_pytest_style = f.read() if existing_pytest_style == get_pytest_style(): add_pytest_style_css = False if add_pytest_style_css: - out_file = open(pytest_style_css, "w+", encoding="utf-8") + out_file = open(pytest_style_css, mode="w+", encoding="utf-8") out_file.writelines(get_pytest_style()) out_file.close() live_js_file = os.path.join(assets_folder, "live.js") add_live_js_file = True if os.path.exists(live_js_file): existing_live_js = None - with open(live_js_file, "r") as f: + with open(live_js_file, mode="r") as f: existing_live_js = f.read() if existing_live_js == live_js: add_live_js_file = False if add_live_js_file: - out_file = open(live_js_file, "w+", encoding="utf-8") + out_file = open(live_js_file, mode="w+", encoding="utf-8") out_file.writelines(live_js) out_file.close() @@ -1306,7 +1306,7 @@ def _perform_behave_unconfigure_(): # Part 1: Finalizing the dashboard / integrating html report if os.path.exists(dashboard_path): the_html_d = None - with open(dashboard_path, "r", encoding="utf-8") as f: + with open(dashboard_path, mode="r", encoding="utf-8") as f: the_html_d = f.read() if sb_config._multithreaded and "-c" in sys.argv: # Threads have "-c" in sys.argv, except for the last @@ -1317,7 +1317,7 @@ def _perform_behave_unconfigure_(): if os.path.exists(pie_path): import json - with open(pie_path, "r") as f: + with open(pie_path, mode="r") as f: dash_pie = f.read().strip() sb_config._saved_dashboard_pie = json.loads(dash_pie) # If the test run doesn't complete by itself, stop refresh @@ -1326,7 +1326,7 @@ def _perform_behave_unconfigure_(): the_html_d = the_html_d.replace(find_it_3, swap_with_3) the_html_d = the_html_d.replace(find_it_4, swap_with_4) the_html_d += stamp - with open(dashboard_path, "w", encoding="utf-8") as f: + with open(dashboard_path, mode="w", encoding="utf-8") as f: f.write(the_html_d) # Finalize the dashboard except KeyboardInterrupt: pass diff --git a/seleniumbase/console_scripts/sb_caseplans.py b/seleniumbase/console_scripts/sb_caseplans.py index 56d7ff3882d..68e1b2804f4 100644 --- a/seleniumbase/console_scripts/sb_caseplans.py +++ b/seleniumbase/console_scripts/sb_caseplans.py @@ -134,7 +134,7 @@ def generate_case_plan_boilerplates( file_name = case_id file_path = os.path.join(full_folder_path, file_name) if not os.path.exists(file_path): - out_file = open(file_path, "w+", "utf-8") + out_file = open(file_path, mode="w+", encoding="utf-8") out_file.writelines("\r\n".join(data)) out_file.close() new_plans += 1 @@ -182,7 +182,7 @@ def view_summary_of_existing_case_plans(root, tests): else: case_path = os.path.join(folder_path, "case_plans", case_id) if os.path.exists(case_path): - f = open(case_path, "r") + f = open(case_path, mode="r") case_data = f.read() f.close() case_data_storage.append(case_data) @@ -315,7 +315,7 @@ def view_summary_of_existing_case_plans(root, tests): full_plan = plan_head file_path = "case_summary.md" - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(full_plan)) file.close() diff --git a/seleniumbase/console_scripts/sb_mkchart.py b/seleniumbase/console_scripts/sb_mkchart.py index d6ab0e9bd67..54d8fa0ccd4 100644 --- a/seleniumbase/console_scripts/sb_mkchart.py +++ b/seleniumbase/console_scripts/sb_mkchart.py @@ -253,7 +253,7 @@ def main(): continue new_data.append(line) data = new_data - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() if " " not in file_name: diff --git a/seleniumbase/console_scripts/sb_mkdir.py b/seleniumbase/console_scripts/sb_mkdir.py index 10810ddd60e..b2e4379aa93 100644 --- a/seleniumbase/console_scripts/sb_mkdir.py +++ b/seleniumbase/console_scripts/sb_mkdir.py @@ -113,7 +113,7 @@ def main(): data.append(seleniumbase_req) data.append("") file_path = "%s/%s" % (dir_name, "requirements.txt") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() @@ -151,7 +151,7 @@ def main(): data.append(" production: custom marker") data.append("") file_path = "%s/%s" % (dir_name, "pytest.ini") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() @@ -168,14 +168,14 @@ def main(): data.append("show_skipped=false") data.append("show_timings=false") file_path = "%s/%s" % (dir_name, "setup.cfg") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() data = [] data.append("") file_path = "%s/%s" % (dir_name, "__init__.py") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() @@ -311,7 +311,7 @@ def main(): data.append("temp_*/") data.append("node_modules") file_path = "%s/%s" % (dir_name, ".gitignore") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() @@ -323,7 +323,7 @@ def main(): data.append(" ├── requirements.txt") data.append(" └── setup.cfg") file_path = "%s/%s" % (dir_name, "outline.rst") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() os.system("sbase print %s -n" % file_path) @@ -367,7 +367,7 @@ def main(): data.append(' self.assert_element("div#login_button_container")') data.append("") file_path = "%s/%s" % (dir_name, "my_first_test.py") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() @@ -460,7 +460,7 @@ def main(): data.append(' self.assert_text("SeleniumBase", "h2")') data.append("") file_path = "%s/%s" % (dir_name, "test_demo_site.py") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() @@ -499,7 +499,7 @@ def main(): data.append(' self.assert_title_contains(title_text)') data.append("") file_path = "%s/%s" % (dir_name, "parameterized_test.py") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() @@ -509,7 +509,7 @@ def main(): data = [] data.append("") file_path = "%s/%s" % (dir_name_2, "__init__.py") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() @@ -544,7 +544,7 @@ def main(): data.append(" pass") data.append("") file_path = "%s/%s" % (dir_name_2, "base_test_case.py") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() @@ -553,7 +553,7 @@ def main(): data.append(' html = "html"') data.append("") file_path = "%s/%s" % (dir_name_2, "page_objects.py") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() @@ -569,7 +569,7 @@ def main(): data.append(" self.assert_element(Page.html)") data.append("") file_path = "%s/%s" % (dir_name_2, "boilerplate_test.py") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() @@ -593,7 +593,7 @@ def main(): data.append(' DataPage().add_input_text(self, "Goodbye!")') data.append("") file_path = "%s/%s" % (dir_name_2, "classic_obj_test.py") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() @@ -613,7 +613,7 @@ def main(): data.append(' DataPage().add_input_text(sb, "Goodbye!")') data.append("") file_path = "%s/%s" % (dir_name_2, "sb_fixture_test.py") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() @@ -623,7 +623,7 @@ def main(): data = [] data.append("") file_path = "%s/%s" % (dir_name_3, "__init__.py") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() @@ -651,7 +651,7 @@ def main(): ) data.append("") file_path = "%s/%s" % (dir_name_3, "google_test.py") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() @@ -669,7 +669,7 @@ def main(): data.append(' search_results = "div#center_col"') data.append("") file_path = "%s/%s" % (dir_name_3, "google_objects.py") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() @@ -701,7 +701,7 @@ def main(): data.append(' self.assert_element("div#login_button_container")') data.append("") file_path = "%s/%s" % (dir_name_3, "swag_labs_test.py") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() @@ -728,7 +728,7 @@ def main(): data.append(' sb.assert_element("div#login_button_container")') data.append("") file_path = "%s/%s" % (dir_name_3, "sb_swag_test.py") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() @@ -755,7 +755,7 @@ def main(): data.append(" ├── sb_swag_test.py") data.append(" └── swag_labs_test.py") file_path = "%s/%s" % (dir_name, "outline.rst") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() if " " not in file_path: diff --git a/seleniumbase/console_scripts/sb_mkfile.py b/seleniumbase/console_scripts/sb_mkfile.py index 370139f5f6c..6087922a82e 100644 --- a/seleniumbase/console_scripts/sb_mkfile.py +++ b/seleniumbase/console_scripts/sb_mkfile.py @@ -412,7 +412,7 @@ def main(): continue new_data.append(line) data = new_data - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() if " " not in file_name: diff --git a/seleniumbase/console_scripts/sb_mkpres.py b/seleniumbase/console_scripts/sb_mkpres.py index fc00b0f1080..f29978d7f93 100644 --- a/seleniumbase/console_scripts/sb_mkpres.py +++ b/seleniumbase/console_scripts/sb_mkpres.py @@ -272,7 +272,7 @@ def main(): continue new_data.append(line) data = new_data - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() if " " not in file_name: diff --git a/seleniumbase/console_scripts/sb_mkrec.py b/seleniumbase/console_scripts/sb_mkrec.py index ad29f4c378a..bc312802fbb 100644 --- a/seleniumbase/console_scripts/sb_mkrec.py +++ b/seleniumbase/console_scripts/sb_mkrec.py @@ -239,7 +239,7 @@ def main(): d2.append("") data = d2 - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() success = ( diff --git a/seleniumbase/console_scripts/sb_objectify.py b/seleniumbase/console_scripts/sb_objectify.py index 0eb2be0e116..61f63e59966 100644 --- a/seleniumbase/console_scripts/sb_objectify.py +++ b/seleniumbase/console_scripts/sb_objectify.py @@ -135,7 +135,7 @@ def create_objects_file(selector_list_dict=None): data.append(' html = "html"') data.append("") file_path = PAGE_OBJECTS_FILE - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() if not selector_list_dict: @@ -149,7 +149,7 @@ def scan_objects_file(): create_objects_file() page_selectors = {} - with open(PAGE_OBJECTS_FILE, "r", encoding="utf-8") as f: + with open(PAGE_OBJECTS_FILE, mode="r", encoding="utf-8") as f: all_code = f.read() var_names = [] @@ -3089,7 +3089,7 @@ def main(shell_command): "Expecting: %s\n" % (seleniumbase_file, expected_arg) ) - with open(seleniumbase_file, "r", encoding="utf-8") as f: + with open(seleniumbase_file, mode="r", encoding="utf-8") as f: all_code = f.read() if "def test_" not in all_code: raise Exception( @@ -3188,7 +3188,7 @@ def main(shell_command): # Create SeleniumBase test file base_file_name = seleniumbase_file.split(".py")[0] converted_file_name = base_file_name + ".py" # Change end to make a copy - out_file = open(converted_file_name, "w+", encoding="utf-8") + out_file = open(converted_file_name, mode="w+", encoding="utf-8") out_file.writelines(seleniumbase_code) out_file.close() print('\n>>> ["%s"] was updated!\n' % converted_file_name) diff --git a/seleniumbase/console_scripts/sb_print.py b/seleniumbase/console_scripts/sb_print.py index 105846aadb1..d6833930b76 100644 --- a/seleniumbase/console_scripts/sb_print.py +++ b/seleniumbase/console_scripts/sb_print.py @@ -123,7 +123,7 @@ def main(): all_code = None with open( - file_to_print, "r+", encoding="utf-8", errors="ignore" + file_to_print, mode="r+", encoding="utf-8", errors="ignore" ) as f: all_code = f.read() all_code = all_code.replace("\t", " ") diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py index d17438f5e51..1216bb57939 100644 --- a/seleniumbase/core/browser_launcher.py +++ b/seleniumbase/core/browser_launcher.py @@ -2011,7 +2011,7 @@ def _mark_driver_repaired(): file_path = os.path.join(abs_path, driver_repaired_lock) if not os.path.exists(DOWNLOADS_FOLDER): os.makedirs(DOWNLOADS_FOLDER) - out_file = open(file_path, "w+", encoding="utf-8") + out_file = open(file_path, mode="w+", encoding="utf-8") out_file.writelines("") out_file.close() @@ -2396,6 +2396,19 @@ def _set_chrome_options( and not recorder_ext and (not extension_zip and not extension_dir) ): + if ( + binary_location + and isinstance(binary_location, str) + and ( + binary_location.lower().endswith("comet") + or binary_location.lower().endswith("comet.exe") + or binary_location.lower().endswith("atlas") + or binary_location.lower().endswith("atlas.exe") + ) + ): + # AI browsers don't like Incognito / Guest Mode + incognito = False + guest_mode = False if incognito: # Use Chrome's Incognito Mode # Incognito Mode prevents Chrome extensions from loading, diff --git a/seleniumbase/core/detect_b_ver.py b/seleniumbase/core/detect_b_ver.py index e8dd71d0505..0125cdab15c 100644 --- a/seleniumbase/core/detect_b_ver.py +++ b/seleniumbase/core/detect_b_ver.py @@ -40,6 +40,10 @@ class OSType(object): class ChromeType(object): GOOGLE = "google-chrome" MSEDGE = "edge" + OPERA = "opera" + BRAVE = "brave" + COMET = "comet" + ATLAS = "atlas" PATTERN = { @@ -96,7 +100,9 @@ def linux_browser_apps_to_cmd(*apps): ) -def chrome_on_linux_path(chromium_ok=False): +def chrome_on_linux_path(chromium_ok=False, browser_type=None): + if browser_type and browser_type != ChromeType.GOOGLE: + return "" if os_name() != OSType.LINUX: return "" paths = ["/bin/google-chrome", "/bin/google-chrome-stable"] @@ -126,7 +132,9 @@ def chrome_on_linux_path(chromium_ok=False): return "/usr/bin/google-chrome" -def edge_on_linux_path(): +def edge_on_linux_path(browser_type=None): + if browser_type and browser_type != ChromeType.MSEDGE: + return "" if os_name() != OSType.LINUX: return "" paths = os.environ["PATH"].split(os.pathsep) @@ -143,7 +151,60 @@ def edge_on_linux_path(): return "/usr/bin/microsoft-edge" -def chrome_on_windows_path(): +def opera_on_linux_path(browser_type=None): + if browser_type and browser_type != ChromeType.OPERA: + return "" + if os_name() != OSType.LINUX: + return "" + paths = os.environ["PATH"].split(os.pathsep) + binaries = [] + binaries.append("opera") + binaries.append("opera-stable") + for binary in binaries: + for path in paths: + full_path = os.path.join(path, binary) + if os.path.exists(full_path) and os.access(full_path, os.X_OK): + return full_path + return "/usr/bin/opera-stable" + + +def brave_on_linux_path(browser_type=None): + if browser_type and browser_type != ChromeType.BRAVE: + return "" + if os_name() != OSType.LINUX: + return "" + paths = os.environ["PATH"].split(os.pathsep) + binaries = [] + binaries.append("brave-browser") + binaries.append("brave") + binaries.append("brave-browser-stable") + for binary in binaries: + for path in paths: + full_path = os.path.join(path, binary) + if os.path.exists(full_path) and os.access(full_path, os.X_OK): + return full_path + return "/usr/bin/brave-browser" + + +def comet_on_linux_path(browser_type=None): + if browser_type and browser_type != ChromeType.COMET: + return "" + if os_name() != OSType.LINUX: + return "" + return "" # Comet Browser isn't supported on Linux yet + + +def atlas_on_linux_path(browser_type=None): + if browser_type and browser_type != ChromeType.ATLAS: + return "" + if os_name() != OSType.LINUX: + return "" + return "" # Atlas Browser isn't supported on Linux yet + + +def chrome_on_windows_path(browser_type=None): + if browser_type and browser_type != ChromeType.GOOGLE: + return "" if os_name() != OSType.WIN: return "" candidates = [] @@ -171,7 +232,9 @@ def chrome_on_windows_path(): return "" -def edge_on_windows_path(): +def edge_on_windows_path(browser_type=None): + if browser_type and browser_type != ChromeType.MSEDGE: + return "" if os_name() != OSType.WIN: return "" candidates = [] @@ -199,6 +262,119 @@ def edge_on_windows_path(): return "" +def opera_on_windows_path(browser_type=None): + if browser_type and browser_type != ChromeType.OPERA: + return "" + if os_name() != OSType.WIN: + return "" + candidates = [] + for item in map( + os.environ.get, + ( + "PROGRAMFILES", + "PROGRAMFILES(X86)", + "LOCALAPPDATA", + "PROGRAMW6432", + ), + ): + for subitem in ( + "Opera", + "Opera/Application", + ): + try: + candidates.append(os.sep.join((item, subitem, "launcher.exe"))) + except TypeError: + pass + for candidate in candidates: + if os.path.exists(candidate) and os.access(candidate, os.X_OK): + return os.path.normpath(candidate) + return "" + + +def brave_on_windows_path(browser_type=None): + if browser_type and browser_type != ChromeType.BRAVE: + return "" + if os_name() != OSType.WIN: + return "" + candidates = [] + for item in map( + os.environ.get, + ( + "PROGRAMFILES", + "PROGRAMFILES(X86)", + "LOCALAPPDATA", + "PROGRAMW6432", + ), + ): + for subitem in ( + "BraveSoftware/Brave-Browser/Application", + ): + try: + candidates.append(os.sep.join((item, subitem, "brave.exe"))) + except TypeError: + pass + for candidate in candidates: + if os.path.exists(candidate) and os.access(candidate, os.X_OK): + return os.path.normpath(candidate) + return "" + + +def comet_on_windows_path(browser_type=None): + if browser_type and browser_type != ChromeType.COMET: + return "" + if os_name() != OSType.WIN: + return "" + candidates = [] + for item in map( + os.environ.get, + ( + "PROGRAMFILES", + "PROGRAMFILES(X86)", + "LOCALAPPDATA", + "PROGRAMW6432", + ), + ): + for subitem in ( + "Comet/Application", + ): + try: + candidates.append(os.sep.join((item, subitem, "Comet.exe"))) + except TypeError: + pass + for candidate in candidates: + if os.path.exists(candidate) and os.access(candidate, os.X_OK): + return os.path.normpath(candidate) + return "" + + +def atlas_on_windows_path(browser_type=None): + if browser_type and browser_type != ChromeType.ATLAS: + return "" + if os_name() != OSType.WIN: + return "" + candidates = [] + for item in map( + os.environ.get, + ( + "PROGRAMFILES", + "PROGRAMFILES(X86)", + "LOCALAPPDATA", + "PROGRAMW6432", + ), + ): + for subitem in ( + "Atlas/Application", + ): + try: + candidates.append(os.sep.join((item, subitem, "Atlas.exe"))) + except TypeError: + pass + for candidate in candidates: + if os.path.exists(candidate) and os.access(candidate, os.X_OK): + return os.path.normpath(candidate) + return "" + + def windows_browser_apps_to_cmd(*apps): """Create analogue of browser --version command for windows.""" powershell = determine_powershell() @@ -211,18 +387,48 @@ def windows_browser_apps_to_cmd(*apps): def get_binary_location(browser_type, chromium_ok=False): """Return the full path of the browser binary.""" + if browser_type.lower() == "chrome": + browser_type = "google-chrome" + elif browser_type.lower() == "msedge": + browser_type = "edge" + else: + browser_type = browser_type.lower() cmd_mapping = { ChromeType.GOOGLE: { - OSType.LINUX: chrome_on_linux_path(chromium_ok), + OSType.LINUX: chrome_on_linux_path(chromium_ok, browser_type), OSType.MAC: r"/Applications/Google Chrome.app" r"/Contents/MacOS/Google Chrome", - OSType.WIN: chrome_on_windows_path(), + OSType.WIN: chrome_on_windows_path(browser_type), }, ChromeType.MSEDGE: { - OSType.LINUX: edge_on_linux_path(), + OSType.LINUX: edge_on_linux_path(browser_type), OSType.MAC: r"/Applications/Microsoft Edge.app" r"/Contents/MacOS/Microsoft Edge", - OSType.WIN: edge_on_windows_path(), + OSType.WIN: edge_on_windows_path(browser_type), + }, + ChromeType.OPERA: { + OSType.LINUX: opera_on_linux_path(browser_type), + OSType.MAC: r"/Applications/Opera.app" + r"/Contents/MacOS/Opera", + OSType.WIN: opera_on_windows_path(browser_type), + }, + ChromeType.BRAVE: { + OSType.LINUX: brave_on_linux_path(browser_type), + OSType.MAC: r"/Applications/Brave Browser.app" + r"/Contents/MacOS/Brave Browser", + OSType.WIN: brave_on_windows_path(browser_type), + }, + ChromeType.COMET: { + OSType.LINUX: comet_on_linux_path(browser_type), + OSType.MAC: r"/Applications/Comet.app" + r"/Contents/MacOS/Comet", + OSType.WIN: comet_on_windows_path(browser_type), + }, + ChromeType.ATLAS: { + OSType.LINUX: atlas_on_linux_path(browser_type), + OSType.MAC: r"/Applications/Atlas.app" + r"/Contents/MacOS/Atlas", + OSType.WIN: atlas_on_windows_path(browser_type), }, } return cmd_mapping[browser_type][os_name()] diff --git a/seleniumbase/core/log_helper.py b/seleniumbase/core/log_helper.py index e03a47ee307..17d9f851f78 100644 --- a/seleniumbase/core/log_helper.py +++ b/seleniumbase/core/log_helper.py @@ -36,7 +36,7 @@ def log_screenshot(test_logpath, driver, screenshot=None, get=False): element = driver.find_element("tag name", "body") screenshot = element.screenshot_as_base64 if screenshot != screenshot_warning: - with open(screenshot_path, "wb") as file: + with open(screenshot_path, mode="wb") as file: file.write(screenshot) with suppress(Exception): shared_utils.make_writable(screenshot_path) @@ -297,7 +297,7 @@ def log_test_failure_data(test, test_logpath, driver, browser, url=None): with suppress(Exception): os.makedirs(test_logpath) with suppress(Exception): - log_file = open(basic_file_path, "w+", encoding="utf-8") + log_file = open(basic_file_path, mode="w+", encoding="utf-8") log_file.writelines("\r\n".join(data_to_save)) log_file.close() shared_utils.make_writable(basic_file_path) @@ -352,7 +352,7 @@ def log_skipped_test_data(test, test_logpath, driver, browser, reason): data_to_save.append("") file_path = os.path.join(test_logpath, "skip_reason.txt") with suppress(Exception): - log_file = open(file_path, "w+", encoding="utf-8") + log_file = open(file_path, mode="w+", encoding="utf-8") log_file.writelines("\r\n".join(data_to_save)) log_file.close() shared_utils.make_writable(file_path) @@ -387,7 +387,7 @@ def log_page_source(test_logpath, driver, source=None): os.makedirs(test_logpath) html_file_path = os.path.join(test_logpath, html_file_name) with suppress(Exception): - html_file = open(html_file_path, "w+", encoding="utf-8") + html_file = open(html_file_path, mode="w+", encoding="utf-8") html_file.write(page_source) html_file.close() shared_utils.make_writable(html_file_path) diff --git a/seleniumbase/core/report_helper.py b/seleniumbase/core/report_helper.py index 99bbeffda8d..2712c8397e9 100644 --- a/seleniumbase/core/report_helper.py +++ b/seleniumbase/core/report_helper.py @@ -47,7 +47,9 @@ def save_test_failure_data(test, name, folder=None): failure_data_file_path = os.path.join(file_path, name) else: failure_data_file_path = name - failure_data_file = open(failure_data_file_path, "w+", "utf-8") + failure_data_file = open( + failure_data_file_path, mode="w+", encoding="utf-8" + ) data_to_save = [] if not hasattr(sb_config, "_report_test_id"): exc_message = "(Unknown Exception)" @@ -99,7 +101,7 @@ def process_failures(test, test_count, duration): bad_page_data = "failure_%s.txt" % test_count screenshot_path = os.path.join(LATEST_REPORT_DIR, bad_page_image) if hasattr(test, "_last_page_screenshot") and test._last_page_screenshot: - with open(screenshot_path, "wb") as file: + with open(screenshot_path, mode="wb") as file: file.write(test._last_page_screenshot) save_test_failure_data(test, bad_page_data, folder=LATEST_REPORT_DIR) exc_message = None @@ -172,7 +174,7 @@ def add_bad_page_log_file(page_results_list): abs_path = os.path.abspath(".") file_path = os.path.join(abs_path, LATEST_REPORT_DIR) log_file = os.path.join(file_path, RESULTS_TABLE) - f = open(log_file, "w") + f = open(log_file, mode="w") h_p1 = '"Num","Result","Stacktrace","Screenshot",' h_p2 = '"URL","Browser","Epoch Time","Duration",' h_p3 = '"Test Case Address","Additional Info"\n' @@ -197,7 +199,7 @@ def add_results_page(html): file_path = os.path.join(abs_path, LATEST_REPORT_DIR) results_file_name = HTML_REPORT results_file = os.path.join(file_path, results_file_name) - f = open(results_file, "w") + f = open(results_file, mode="w") f.write(html) f.close() return results_file diff --git a/seleniumbase/core/sb_cdp.py b/seleniumbase/core/sb_cdp.py index 2979060f906..981a23cf8ce 100644 --- a/seleniumbase/core/sb_cdp.py +++ b/seleniumbase/core/sb_cdp.py @@ -1674,6 +1674,11 @@ def __gui_click_x_y(self, x, y, timeframe=0.25, uc_lock=False): import pyautogui pyautogui = self.__get_configured_pyautogui(pyautogui) screen_width, screen_height = pyautogui.size() + if ( + hasattr(sb_config, "_cdp_browser") + and sb_config._cdp_browser == "opera" + ): + x = x + 55 if x < 0 or y < 0 or x > screen_width or y > screen_height: raise Exception( "PyAutoGUI cannot click on point (%s, %s)" @@ -1931,6 +1936,12 @@ def __gui_drag_drop(self, x1, y1, x2, y2, timeframe=0.25, uc_lock=False): import pyautogui pyautogui = self.__get_configured_pyautogui(pyautogui) screen_width, screen_height = pyautogui.size() + if ( + hasattr(sb_config, "_cdp_browser") + and sb_config._cdp_browser == "opera" + ): + x1 = x1 + 55 + x2 = x2 + 55 if x1 < 0 or y1 < 0 or x1 > screen_width or y1 > screen_height: raise Exception( "PyAutoGUI cannot drag-drop from point (%s, %s)" @@ -2022,6 +2033,11 @@ def __gui_hover_x_y(self, x, y, timeframe=0.25, uc_lock=False): import pyautogui pyautogui = self.__get_configured_pyautogui(pyautogui) screen_width, screen_height = pyautogui.size() + if ( + hasattr(sb_config, "_cdp_browser") + and sb_config._cdp_browser == "opera" + ): + x = x + 55 if x < 0 or y < 0 or x > screen_width or y > screen_height: raise Exception( "PyAutoGUI cannot hover on point (%s, %s)" @@ -2694,7 +2710,7 @@ def save_page_source(self, name, folder=None): rendered_source = "%s\n%s" % (base_href_html, page_source) else: rendered_source = page_source - html_file = open(html_file_path, "w+", "utf-8") + html_file = open(html_file_path, mode="w+", encoding="utf-8") html_file.write(rendered_source) html_file.close() diff --git a/seleniumbase/core/tour_helper.py b/seleniumbase/core/tour_helper.py index d4b96eaf352..8f6b080cde1 100644 --- a/seleniumbase/core/tour_helper.py +++ b/seleniumbase/core/tour_helper.py @@ -1136,7 +1136,7 @@ def export_tour(tour_steps, name=None, filename="my_tour.js", url=None): pass file_path = exported_tours_folder + "/" + filename - out_file = open(file_path, "w+", encoding="utf-8") + out_file = open(file_path, mode="w+", encoding="utf-8") out_file.writelines(instructions) out_file.close() print("\n>>> [%s] was saved!\n" % file_path) diff --git a/seleniumbase/fixtures/constants.py b/seleniumbase/fixtures/constants.py index 16d300a4449..75f7562c195 100644 --- a/seleniumbase/fixtures/constants.py +++ b/seleniumbase/fixtures/constants.py @@ -406,7 +406,14 @@ class ValidBinaries: "brave", "opera", "opera-stable", + "comet", + "comet-browser", + "comet-stable", + "atlas", + "atlas-browser", + "atlas-stable", "chrome.exe", # WSL (Windows Subsystem for Linux) + "chromium.exe", # WSL (Windows Subsystem for Linux) ] valid_edge_binaries_on_linux = [ "microsoft-edge", @@ -424,6 +431,8 @@ class ValidBinaries: "Google Chrome Dev", "Brave Browser", "Opera", + "Comet", + "Atlas", ] valid_edge_binaries_on_macos = [ "Microsoft Edge", @@ -434,6 +443,8 @@ class ValidBinaries: "chrome-headless-shell.exe", "brave.exe", "opera.exe", + "comet.exe", + "atlas.exe", ] valid_edge_binaries_on_windows = [ "msedge.exe", diff --git a/seleniumbase/fixtures/js_utils.py b/seleniumbase/fixtures/js_utils.py index 5178b21ff0a..fcf678c53dd 100644 --- a/seleniumbase/fixtures/js_utils.py +++ b/seleniumbase/fixtures/js_utils.py @@ -1269,10 +1269,16 @@ def scroll_to_element(driver, element): return False try: element_location_x = element.location["x"] + except Exception: + element_location_x = 0 + try: element_width = element.size["width"] + except Exception: + element_width = 0 + try: screen_width = driver.get_window_size()["width"] except Exception: - element_location_x = 0 + screen_width = execute_script("return window.innerWidth;") element_location_y = element_location_y - constants.Scroll.Y_OFFSET if element_location_y < 0: element_location_y = 0 @@ -1312,10 +1318,16 @@ def slow_scroll_to_element(driver, element, *args, **kwargs): return try: element_location_x = element.location["x"] + except Exception: + element_location_x = 0 + try: element_width = element.size["width"] + except Exception: + element_width = 0 + try: screen_width = driver.get_window_size()["width"] except Exception: - element_location_x = 0 + screen_width = execute_script("return window.innerWidth;") element_location_y = element_location_y - constants.Scroll.Y_OFFSET if element_location_y < 0: element_location_y = 0 diff --git a/seleniumbase/fixtures/page_utils.py b/seleniumbase/fixtures/page_utils.py index 7d93aa277d1..913bcddc56f 100644 --- a/seleniumbase/fixtures/page_utils.py +++ b/seleniumbase/fixtures/page_utils.py @@ -109,10 +109,10 @@ def looks_like_a_page_url(url): navigate to the page if a URL is detected, but will instead call self.get_element(URL_AS_A_SELECTOR) if the input is not a URL.""" return url.startswith(( - "http:", "https:", "://", "about:", "blob:", "chrome:", + "http:", "https:", "://", "about:", "blob:", "chrome:", "opera:", "data:", "edge:", "file:", "view-source:", "chrome-search:", "chrome-extension:", "chrome-untrusted:", "isolated-app:", - "chrome-devtools:", "devtools:" + "chrome-devtools:", "devtools:", "brave:", "comet:", "atlas:" )) @@ -304,7 +304,7 @@ def _download_file_to(file_url, destination_folder, new_file_name=None): constants.MultiBrowser.DOWNLOAD_FILE_LOCK ) with download_file_lock: - with open(file_path, "wb") as code: + with open(file_path, mode="wb") as code: code.write(r.content) @@ -314,7 +314,9 @@ def _save_data_as(data, destination_folder, file_name): ) with file_io_lock: out_file = open( - os.path.join(destination_folder, file_name), "w+", encoding="utf-8" + os.path.join(destination_folder, file_name), + mode="w+", + encoding="utf-8", ) out_file.writelines(data) out_file.close() @@ -327,12 +329,16 @@ def _append_data_to_file(data, destination_folder, file_name): with file_io_lock: existing_data = "" if os.path.exists(os.path.join(destination_folder, file_name)): - with open(os.path.join(destination_folder, file_name), "r") as f: + with open( + os.path.join(destination_folder, file_name), mode="r" + ) as f: existing_data = f.read() if not existing_data.split("\n")[-1] == "": existing_data += "\n" out_file = open( - os.path.join(destination_folder, file_name), "w+", encoding="utf-8" + os.path.join(destination_folder, file_name), + mode="w+", + encoding="utf-8", ) out_file.writelines("%s%s" % (existing_data, data)) out_file.close() @@ -345,7 +351,7 @@ def _get_file_data(folder, file_name): with file_io_lock: if not os.path.exists(os.path.join(folder, file_name)): raise Exception("File not found!") - with open(os.path.join(folder, file_name), "r") as f: + with open(os.path.join(folder, file_name), mode="r") as f: data = f.read() return data diff --git a/seleniumbase/plugins/basic_test_info.py b/seleniumbase/plugins/basic_test_info.py index f5f5f6a9068..d46e8160f1c 100644 --- a/seleniumbase/plugins/basic_test_info.py +++ b/seleniumbase/plugins/basic_test_info.py @@ -25,7 +25,7 @@ def addError(self, test, err, capt=None): if not os.path.exists(test_logpath): os.makedirs(test_logpath) file_name = "%s/%s" % (test_logpath, self.logfile_name) - basic_info_file = open(file_name, "w+", "utf-8") + basic_info_file = open(file_name, mode="w+", encoding="utf-8") self.__log_test_error_data(basic_info_file, test, err, "Error") basic_info_file.close() @@ -34,7 +34,7 @@ def addFailure(self, test, err, capt=None, tbinfo=None): if not os.path.exists(test_logpath): os.makedirs(test_logpath) file_name = "%s/%s" % (test_logpath, self.logfile_name) - basic_info_file = open(file_name, "w+", "utf-8") + basic_info_file = open(file_name, mode="w+", encoding="utf-8") self.__log_test_error_data(basic_info_file, test, err, "Error") basic_info_file.close() diff --git a/seleniumbase/plugins/page_source.py b/seleniumbase/plugins/page_source.py index e22af22cd60..6254f9b842e 100644 --- a/seleniumbase/plugins/page_source.py +++ b/seleniumbase/plugins/page_source.py @@ -28,7 +28,7 @@ def addError(self, test, err, capt=None): if not os.path.exists(test_logpath): os.makedirs(test_logpath) html_file_name = os.path.join(test_logpath, self.logfile_name) - html_file = open(html_file_name, "w+", "utf-8") + html_file = open(html_file_name, mode="w+", encoding="utf-8") rendered_source = log_helper.get_html_source_with_base_href( test.driver, page_source ) @@ -44,7 +44,7 @@ def addFailure(self, test, err, capt=None, tbinfo=None): if not os.path.exists(test_logpath): os.makedirs(test_logpath) html_file_name = os.path.join(test_logpath, self.logfile_name) - html_file = open(html_file_name, "w+", "utf-8") + html_file = open(html_file_name, mode="w+", encoding="utf-8") rendered_source = log_helper.get_html_source_with_base_href( test.driver, page_source ) diff --git a/seleniumbase/plugins/pytest_plugin.py b/seleniumbase/plugins/pytest_plugin.py index e905f88b2f1..e67d5dc4548 100644 --- a/seleniumbase/plugins/pytest_plugin.py +++ b/seleniumbase/plugins/pytest_plugin.py @@ -1910,24 +1910,24 @@ def _create_dashboard_assets_(): add_pytest_style_css = True if os.path.exists(pytest_style_css): existing_pytest_style = None - with open(pytest_style_css, "r") as f: + with open(pytest_style_css, mode="r") as f: existing_pytest_style = f.read() if existing_pytest_style == get_pytest_style(): add_pytest_style_css = False if add_pytest_style_css: - out_file = open(pytest_style_css, "w+", encoding="utf-8") + out_file = open(pytest_style_css, mode="w+", encoding="utf-8") out_file.writelines(get_pytest_style()) out_file.close() live_js_file = os.path.join(assets_folder, "live.js") add_live_js_file = True if os.path.exists(live_js_file): existing_live_js = None - with open(live_js_file, "r") as f: + with open(live_js_file, mode="r") as f: existing_live_js = f.read() if existing_live_js == live_js: add_live_js_file = False if add_live_js_file: - out_file = open(live_js_file, "w+", encoding="utf-8") + out_file = open(live_js_file, mode="w+", encoding="utf-8") out_file.writelines(live_js) out_file.close() @@ -2228,7 +2228,7 @@ def _perform_pytest_unconfigure_(config): and html_report_path and os.path.exists(html_report_path) ): - with open(html_report_path, "r", encoding="utf-8") as f: + with open(html_report_path, mode="r", encoding="utf-8") as f: the_html_r = f.read() assets_chunk = "if (assets.length === 1) {" remove_media = "container.classList.remove('media-container')" @@ -2274,18 +2274,18 @@ def _perform_pytest_unconfigure_(config): the_html_r = ( the_html_r[:rc_loc] + new_time + the_html_r[end_rc_loc:] ) - with open(html_report_path, "w", encoding="utf-8") as f: + with open(html_report_path, mode="w", encoding="utf-8") as f: f.write(the_html_r) # Finalize the HTML report with suppress(Exception): shared_utils.make_writable(html_report_path) - with open(html_report_path_copy, "w", encoding="utf-8") as f: + with open(html_report_path_copy, mode="w", encoding="utf-8") as f: f.write(the_html_r) # Finalize the HTML report copy with suppress(Exception): shared_utils.make_writable(html_report_path_copy) assets_style = "./assets/style.css" if os.path.exists(assets_style): html_style = None - with open(assets_style, "r", encoding="utf-8") as f: + with open(assets_style, mode="r", encoding="utf-8") as f: html_style = f.read() if html_style: html_style = html_style.replace("top: -50px;", "top: 2px;") @@ -2297,7 +2297,7 @@ def _perform_pytest_unconfigure_(config): html_style = html_style.replace(".collapsible", ".oldc") html_style = html_style.replace(" (hide details)", "") html_style = html_style.replace(" (show details)", "") - with open(assets_style, "w", encoding="utf-8") as f: + with open(assets_style, mode="w", encoding="utf-8") as f: f.write(html_style) with suppress(Exception): shared_utils.make_writable(assets_style) @@ -2332,7 +2332,7 @@ def _perform_pytest_unconfigure_(config): # Part 1: Finalizing the dashboard / integrating html report if os.path.exists(dashboard_path): the_html_d = None - with open(dashboard_path, "r", encoding="utf-8") as f: + with open(dashboard_path, mode="r", encoding="utf-8") as f: the_html_d = f.read() if sb_config._multithreaded and "-c" in sys_argv: # Threads have "-c" in sys.argv, except for the last @@ -2343,7 +2343,7 @@ def _perform_pytest_unconfigure_(config): if os.path.exists(pie_path): import json - with open(pie_path, "r") as f: + with open(pie_path, mode="r") as f: dash_pie = f.read().strip() sb_config._saved_dashboard_pie = json.loads(dash_pie) # If the test run doesn't complete by itself, stop refresh @@ -2374,20 +2374,20 @@ def _perform_pytest_unconfigure_(config): if sb_config._dash_final_summary: the_html_d += sb_config._dash_final_summary time.sleep(0.1) # Add time for "livejs" to detect changes - with open(dashboard_path, "w", encoding="utf-8") as f: + with open(dashboard_path, mode="w", encoding="utf-8") as f: f.write(the_html_d) # Finalize the dashboard time.sleep(0.1) # Add time for "livejs" to detect changes the_html_d = the_html_d.replace( "", "" ) - with open(dashboard_path, "w", encoding="utf-8") as f: + with open(dashboard_path, mode="w", encoding="utf-8") as f: f.write(the_html_d) # Finalize the dashboard with suppress(Exception): shared_utils.make_writable(dashboard_path) assets_style = "./assets/style.css" if os.path.exists(assets_style): html_style = None - with open(assets_style, "r", encoding="utf-8") as f: + with open(assets_style, mode="r", encoding="utf-8") as f: html_style = f.read() if html_style: html_style = html_style.replace("top: -50px;", "top: 2px;") @@ -2399,7 +2399,7 @@ def _perform_pytest_unconfigure_(config): html_style = html_style.replace(".collapsible", ".oldc") html_style = html_style.replace(" (hide details)", "") html_style = html_style.replace(" (show details)", "") - with open(assets_style, "w", encoding="utf-8") as f: + with open(assets_style, mode="w", encoding="utf-8") as f: f.write(html_style) with suppress(Exception): shared_utils.make_writable(assets_style) @@ -2421,7 +2421,7 @@ def _perform_pytest_unconfigure_(config): ): # Add the dashboard pie to the pytest html report the_html_r = None - with open(html_report_path, "r", encoding="utf-8") as f: + with open(html_report_path, mode="r", encoding="utf-8") as f: the_html_r = f.read() if sb_config._saved_dashboard_pie: h_r_name = sb_config._html_report_name @@ -2484,11 +2484,13 @@ def _perform_pytest_unconfigure_(config): the_html_r = ( the_html_r[:rc_loc] + new_time + the_html_r[end_rc_loc:] ) - with open(html_report_path, "w", encoding="utf-8") as f: + with open(html_report_path, mode="w", encoding="utf-8") as f: f.write(the_html_r) # Finalize the HTML report with suppress(Exception): shared_utils.make_writable(html_report_path) - with open(html_report_path_copy, "w", encoding="utf-8") as f: + with open( + html_report_path_copy, mode="w", encoding="utf-8" + ) as f: f.write(the_html_r) # Finalize the HTML report copy with suppress(Exception): shared_utils.make_writable(html_report_path_copy) @@ -2533,7 +2535,9 @@ def pytest_unconfigure(config): ): # Dash is HTML Report (Multithreaded) sb_config._dash_is_html_report = True - with open(dashboard_path, "w", encoding="utf-8") as f: + with open( + dashboard_path, mode="w", encoding="utf-8" + ) as f: f.write(sb_config._dash_html) # Dashboard Multithreaded _perform_pytest_unconfigure_(config) diff --git a/seleniumbase/translate/translator.py b/seleniumbase/translate/translator.py index 26242a5922f..f2c0bad2c02 100644 --- a/seleniumbase/translate/translator.py +++ b/seleniumbase/translate/translator.py @@ -484,7 +484,7 @@ def main(): print("") raise Exception(message) - with open(seleniumbase_file, "r", encoding="utf-8") as f: + with open(seleniumbase_file, mode="r", encoding="utf-8") as f: all_code = f.read() if "def test_" not in all_code and "from seleniumbase" not in all_code: print("") @@ -1042,7 +1042,7 @@ def main(): pass # Print-only run already done if new_file_name: - out_file = open(new_file_name, "w+", encoding="utf-8") + out_file = open(new_file_name, mode="w+", encoding="utf-8") out_file.writelines("\r\n".join(seleniumbase_lines)) out_file.close() results_saved = ( diff --git a/seleniumbase/undetected/cdp_driver/cdp_util.py b/seleniumbase/undetected/cdp_driver/cdp_util.py index 83ecd55eb79..a0e592a9cba 100644 --- a/seleniumbase/undetected/cdp_driver/cdp_util.py +++ b/seleniumbase/undetected/cdp_driver/cdp_util.py @@ -554,11 +554,45 @@ async def start( ad_block_dir = os.path.join(DOWNLOADS_FOLDER, "ad_block") __unzip_to_new_folder(ad_block_zip, ad_block_dir) extension_dir = __add_chrome_ext_dir(extension_dir, ad_block_dir) - if ( - "binary_location" in kwargs - and not browser_executable_path - ): + if "binary_location" in kwargs and not browser_executable_path: browser_executable_path = kwargs["binary_location"] + if not browser_executable_path: + browser = None + if "browser" in kwargs: + browser = kwargs["browser"] + if not browser and "--browser" in arg_join: + br_string = None + if "--browser=" in arg_join: + br_string = arg_join.split("--browser=")[1].split(" ")[0] + elif "--browser " in arg_join: + br_string = arg_join.split("--browser ")[1].split(" ")[0] + if br_string: + if br_string.startswith('"') and br_string.endswith('"'): + br_string = proxy_string[1:-1] + elif br_string.startswith("'") and br_string.endswith("'"): + br_string = proxy_string[1:-1] + browser = br_string + if not browser: + if "--edge" in sys_argv: + browser = "edge" + elif "--opera" in sys_argv: + browser = "opera" + elif "--brave" in sys_argv: + browser = "brave" + elif "--comet" in sys_argv: + browser = "comet" + elif "--atlas" in sys_argv: + browser = "atlas" + else: + browser = "chrome" + sb_config._cdp_browser = browser + if browser == "comet" or browser == "atlas": + incognito = False + guest = False + with suppress(Exception): + browser_binary = detect_b_ver.get_binary_location(browser) + if browser_binary and os.path.exists(browser_binary): + browser_executable_path = browser_binary if not config: config = Config( user_data_dir, @@ -622,23 +656,8 @@ async def start( async def start_async(*args, **kwargs) -> Browser: - headless = False - binary_location = None - if "browser_executable_path" in kwargs: - binary_location = kwargs["browser_executable_path"] - if binary_location and isinstance(binary_location, str): - binary_location = binary_location.strip() - else: - binary_location = detect_b_ver.get_binary_location("google-chrome") - if binary_location and isinstance(binary_location, str): - binary_location = binary_location.strip() - if not os.path.exists(binary_location): - binary_location = None - if ( - shared_utils.is_chrome_130_or_newer(binary_location) - and "user_data_dir" in kwargs - and kwargs["user_data_dir"] - ): + if "user_data_dir" in kwargs and kwargs["user_data_dir"]: + headless = False if "headless" in kwargs: headless = kwargs["headless"] decoy_args = kwargs @@ -662,23 +681,8 @@ def start_sync(*args, **kwargs) -> Browser: loop = kwargs["loop"] else: loop = asyncio.new_event_loop() - headless = False - binary_location = None - if "browser_executable_path" in kwargs: - binary_location = kwargs["browser_executable_path"] - if binary_location and isinstance(binary_location, str): - binary_location = binary_location.strip() - else: - binary_location = detect_b_ver.get_binary_location("google-chrome") - if binary_location and isinstance(binary_location, str): - binary_location = binary_location.strip() - if not os.path.exists(binary_location): - binary_location = None - if ( - shared_utils.is_chrome_130_or_newer(binary_location) - and "user_data_dir" in kwargs - and kwargs["user_data_dir"] - ): + if "user_data_dir" in kwargs and kwargs["user_data_dir"]: + headless = False if "headless" in kwargs: headless = kwargs["headless"] decoy_args = kwargs diff --git a/seleniumbase/undetected/cdp_driver/connection.py b/seleniumbase/undetected/cdp_driver/connection.py index 869c8bd768e..fc0aa1493d3 100644 --- a/seleniumbase/undetected/cdp_driver/connection.py +++ b/seleniumbase/undetected/cdp_driver/connection.py @@ -33,6 +33,7 @@ MAX_SIZE: int = 2**28 PING_TIMEOUT: int = 1800 # 30 minutes TargetType = Union[cdp.target.TargetInfo, cdp.target.TargetID] +logging.getLogger("asyncio").setLevel(logging.CRITICAL) logger = logging.getLogger("uc.connection") diff --git a/seleniumbase/utilities/selenium_grid/download_selenium_server.py b/seleniumbase/utilities/selenium_grid/download_selenium_server.py index b191105773b..36d857908ce 100644 --- a/seleniumbase/utilities/selenium_grid/download_selenium_server.py +++ b/seleniumbase/utilities/selenium_grid/download_selenium_server.py @@ -19,7 +19,7 @@ def download_selenium_server(): """Downloads the Selenium Server JAR file.""" try: - local_file = open(JAR_FILE, "wb") + local_file = open(JAR_FILE, mode="wb") remote_file = urlopen(SELENIUM_JAR) print("Downloading the Selenium Server JAR file...\n") local_file.write(remote_file.read()) diff --git a/seleniumbase/utilities/selenium_grid/grid_hub.py b/seleniumbase/utilities/selenium_grid/grid_hub.py index f8ee03dd4bd..b0d610d5d2f 100644 --- a/seleniumbase/utilities/selenium_grid/grid_hub.py +++ b/seleniumbase/utilities/selenium_grid/grid_hub.py @@ -77,7 +77,7 @@ def main(): data = [] data.append(verbose) file_path = os.path.join(dir_path, "verbose_hub_server.dat") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() diff --git a/seleniumbase/utilities/selenium_grid/grid_node.py b/seleniumbase/utilities/selenium_grid/grid_node.py index a3fc06e141c..f6feacbdb64 100644 --- a/seleniumbase/utilities/selenium_grid/grid_node.py +++ b/seleniumbase/utilities/selenium_grid/grid_node.py @@ -87,14 +87,14 @@ def main(): data = [] data.append(server_ip) file_path = os.path.join(dir_path, "ip_of_grid_hub.dat") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() data = [] data.append(verbose) file_path = os.path.join(dir_path, "verbose_node_server.dat") - file = open(file_path, "w+", "utf-8") + file = open(file_path, mode="w+", encoding="utf-8") file.writelines("\r\n".join(data)) file.close() diff --git a/seleniumbase/utilities/selenium_ide/convert_ide.py b/seleniumbase/utilities/selenium_ide/convert_ide.py index 4241a39540e..3b9189808da 100644 --- a/seleniumbase/utilities/selenium_ide/convert_ide.py +++ b/seleniumbase/utilities/selenium_ide/convert_ide.py @@ -59,7 +59,7 @@ def main(): uses_keys = False uses_select = False - with open(webdriver_python_file, "r", encoding="utf-8") as f: + with open(webdriver_python_file, mode="r", encoding="utf-8") as f: all_code = f.read() if "def test_" not in all_code: raise Exception( @@ -893,7 +893,7 @@ def main(): # Create SeleniumBase test file base_file_name = webdriver_python_file.split(".py")[0] converted_file_name = base_file_name + "_SB.py" - out_file = open(converted_file_name, "w+", encoding="utf-8") + out_file = open(converted_file_name, mode="w+", encoding="utf-8") out_file.writelines(seleniumbase_code) out_file.close() print( diff --git a/setup.py b/setup.py index 10361168738..5eeaacccb42 100755 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ long_description = None total_description = None try: - with open(os.path.join(this_dir, "README.md"), "rb") as f: + with open(os.path.join(this_dir, "README.md"), mode="rb") as f: total_description = f.read().decode("utf-8") description_lines = total_description.split("\n") long_description_lines = [] @@ -21,7 +21,9 @@ long_description = "A complete library for building end-to-end tests." about = {} # Get the package version from the seleniumbase/__version__.py file -with open(os.path.join(this_dir, "seleniumbase", "__version__.py"), "rb") as f: +with open( + os.path.join(this_dir, "seleniumbase", "__version__.py"), mode="rb" +) as f: exec(f.read().decode("utf-8"), about) if sys.argv[-1] == "publish": @@ -180,7 +182,7 @@ 'pygments>=2.19.2', 'pyreadline3>=3.5.4;platform_system=="Windows"', "tabcompleter>=1.4.0", - "pdbp>=1.7.1", + "pdbp>=1.8.0", "idna>=3.11", 'chardet==5.2.0', 'charset-normalizer>=3.4.4,<4',