seleniumbase 4.44.1__tar.gz → 4.44.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {seleniumbase-4.44.1/seleniumbase.egg-info → seleniumbase-4.44.3}/PKG-INFO +1 -1
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/__version__.py +1 -1
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/browser_launcher.py +52 -24
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/sb_cdp.py +99 -27
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/fixtures/base_case.py +29 -22
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/undetected/cdp.py +1 -12
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/undetected/cdp_driver/browser.py +4 -6
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/undetected/cdp_driver/config.py +12 -4
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/undetected/cdp_driver/connection.py +2 -3
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/undetected/cdp_driver/element.py +75 -18
- {seleniumbase-4.44.1 → seleniumbase-4.44.3/seleniumbase.egg-info}/PKG-INFO +1 -1
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/.gitignore +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/LICENSE +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/MANIFEST.in +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/README.md +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/install.sh +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/pyproject.toml +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/pytest.ini +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/requirements.txt +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/sbase/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/sbase/__main__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/sbase/steps.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/__main__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/behave/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/behave/behave_helper.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/behave/behave_sb.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/behave/steps.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/common/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/common/decorators.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/common/encryption.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/common/exceptions.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/common/obfuscate.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/common/unobfuscate.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/config/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/config/ad_block_list.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/config/proxy_list.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/config/settings.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/console_scripts/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/console_scripts/logo_helper.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/console_scripts/rich_helper.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/console_scripts/run.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/console_scripts/sb_behave_gui.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/console_scripts/sb_caseplans.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/console_scripts/sb_commander.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/console_scripts/sb_install.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/console_scripts/sb_mkchart.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/console_scripts/sb_mkdir.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/console_scripts/sb_mkfile.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/console_scripts/sb_mkpres.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/console_scripts/sb_mkrec.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/console_scripts/sb_objectify.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/console_scripts/sb_print.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/console_scripts/sb_recorder.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/application_manager.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/capabilities_parser.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/colored_traceback.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/create_db_tables.sql +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/detect_b_ver.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/download_helper.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/encoded_images.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/jqc_helper.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/log_helper.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/mysql.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/proxy_helper.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/recorder_helper.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/report_helper.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/s3_manager.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/sb_driver.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/session_helper.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/settings_parser.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/style_sheet.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/testcase_manager.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/tour_helper.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/core/visual_helper.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/drivers/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/drivers/atlas_drivers/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/drivers/brave_drivers/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/drivers/cft_drivers/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/drivers/chs_drivers/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/drivers/comet_drivers/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/drivers/opera_drivers/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/extensions/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/extensions/ad_block.zip +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/extensions/disable_csp.zip +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/extensions/recorder.zip +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/extensions/sbase_ext.zip +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/fixtures/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/fixtures/constants.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/fixtures/css_to_xpath.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/fixtures/errors.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/fixtures/js_utils.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/fixtures/page_actions.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/fixtures/page_utils.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/fixtures/shared_utils.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/fixtures/unittest_helper.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/fixtures/words.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/fixtures/xpath_to_css.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/js_code/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/js_code/active_css_js.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/js_code/live_js.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/js_code/recorder_js.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/masterqa/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/masterqa/master_qa.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/plugins/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/plugins/base_plugin.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/plugins/basic_test_info.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/plugins/db_reporting_plugin.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/plugins/driver_manager.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/plugins/page_source.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/plugins/pytest_plugin.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/plugins/s3_logging_plugin.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/plugins/sb_manager.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/plugins/screen_shots.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/plugins/selenium_plugin.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/resources/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/translate/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/translate/chinese.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/translate/dutch.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/translate/french.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/translate/italian.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/translate/japanese.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/translate/korean.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/translate/master_dict.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/translate/portuguese.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/translate/russian.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/translate/spanish.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/translate/translator.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/undetected/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/undetected/cdp_driver/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/undetected/cdp_driver/_contradict.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/undetected/cdp_driver/cdp_util.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/undetected/cdp_driver/tab.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/undetected/dprocess.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/undetected/options.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/undetected/patcher.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/undetected/reactor.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/undetected/webelement.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/utilities/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/utilities/selenium_grid/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/utilities/selenium_grid/download_selenium_server.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/utilities/selenium_grid/font_color +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/utilities/selenium_grid/grid-hub +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/utilities/selenium_grid/grid-node +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/utilities/selenium_grid/grid_hub.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/utilities/selenium_grid/grid_node.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/utilities/selenium_grid/register-grid-node.bat +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/utilities/selenium_grid/register-grid-node.sh +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/utilities/selenium_grid/start-grid-hub.bat +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/utilities/selenium_grid/start-grid-hub.sh +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/utilities/selenium_ide/__init__.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase/utilities/selenium_ide/convert_ide.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase.egg-info/SOURCES.txt +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase.egg-info/dependency_links.txt +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase.egg-info/entry_points.txt +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase.egg-info/requires.txt +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/seleniumbase.egg-info/top_level.txt +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/setup.cfg +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/setup.py +0 -0
- {seleniumbase-4.44.1 → seleniumbase-4.44.3}/virtualenv_install.sh +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# seleniumbase package
|
|
2
|
-
__version__ = "4.44.
|
|
2
|
+
__version__ = "4.44.3"
|
|
@@ -293,7 +293,17 @@ def extend_driver(
|
|
|
293
293
|
)
|
|
294
294
|
if hasattr(driver, "proxy"):
|
|
295
295
|
driver.set_wire_proxy = DM.set_wire_proxy
|
|
296
|
+
completed_loads = []
|
|
297
|
+
for ext_dir in sb_config._ext_dirs:
|
|
298
|
+
with suppress(Exception):
|
|
299
|
+
if ext_dir not in completed_loads:
|
|
300
|
+
completed_loads.append(ext_dir)
|
|
301
|
+
if not use_uc and os.path.exists(os.path.abspath(ext_dir)):
|
|
302
|
+
driver.webextension.install(os.path.abspath(ext_dir))
|
|
296
303
|
if proxy_auth:
|
|
304
|
+
with suppress(Exception):
|
|
305
|
+
if not use_uc and os.path.exists(proxy_helper.PROXY_DIR_PATH):
|
|
306
|
+
driver.webextension.install(proxy_helper.PROXY_DIR_PATH)
|
|
297
307
|
# Proxy needs a moment to load in Manifest V3
|
|
298
308
|
if use_uc:
|
|
299
309
|
time.sleep(0.14)
|
|
@@ -764,6 +774,7 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs):
|
|
|
764
774
|
cdp.click_active_element = CDPM.click_active_element
|
|
765
775
|
cdp.click_if_visible = CDPM.click_if_visible
|
|
766
776
|
cdp.click_visible_elements = CDPM.click_visible_elements
|
|
777
|
+
cdp.click_with_offset = CDPM.click_with_offset
|
|
767
778
|
cdp.mouse_click = CDPM.mouse_click
|
|
768
779
|
cdp.get_parent = CDPM.get_parent
|
|
769
780
|
cdp.remove_element = CDPM.remove_element
|
|
@@ -793,11 +804,13 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs):
|
|
|
793
804
|
cdp.set_attributes = CDPM.set_attributes
|
|
794
805
|
cdp.is_attribute_present = CDPM.is_attribute_present
|
|
795
806
|
cdp.is_online = CDPM.is_online
|
|
807
|
+
cdp.solve_captcha = CDPM.solve_captcha
|
|
796
808
|
cdp.gui_press_key = CDPM.gui_press_key
|
|
797
809
|
cdp.gui_press_keys = CDPM.gui_press_keys
|
|
798
810
|
cdp.gui_write = CDPM.gui_write
|
|
799
811
|
cdp.gui_click_x_y = CDPM.gui_click_x_y
|
|
800
812
|
cdp.gui_click_element = CDPM.gui_click_element
|
|
813
|
+
cdp.gui_click_with_offset = CDPM.gui_click_with_offset
|
|
801
814
|
cdp.gui_click_captcha = CDPM.gui_click_captcha
|
|
802
815
|
cdp.gui_drag_drop_points = CDPM.gui_drag_drop_points
|
|
803
816
|
cdp.gui_drag_and_drop = CDPM.gui_drag_and_drop
|
|
@@ -2084,6 +2097,7 @@ def _add_chrome_proxy_extension(
|
|
|
2084
2097
|
"""Implementation of https://stackoverflow.com/a/35293284/7058266
|
|
2085
2098
|
for https://stackoverflow.com/q/12848327/7058266
|
|
2086
2099
|
(Run Selenium on a proxy server that requires authentication.)"""
|
|
2100
|
+
zip_it = False
|
|
2087
2101
|
args = " ".join(sys.argv)
|
|
2088
2102
|
bypass_list = proxy_bypass_list
|
|
2089
2103
|
if (
|
|
@@ -2464,13 +2478,27 @@ def _set_chrome_options(
|
|
|
2464
2478
|
extension_zip_list = extension_zip.split(",")
|
|
2465
2479
|
for extension_zip_item in extension_zip_list:
|
|
2466
2480
|
abs_path = os.path.abspath(extension_zip_item)
|
|
2467
|
-
|
|
2481
|
+
if os.path.exists(abs_path):
|
|
2482
|
+
try:
|
|
2483
|
+
abs_path_dir = os.path.join(
|
|
2484
|
+
DOWNLOADS_FOLDER, abs_path.split(".")[0]
|
|
2485
|
+
)
|
|
2486
|
+
_unzip_to_new_folder(abs_path, abs_path_dir)
|
|
2487
|
+
chrome_options = add_chrome_ext_dir(
|
|
2488
|
+
chrome_options, abs_path_dir
|
|
2489
|
+
)
|
|
2490
|
+
sb_config._ext_dirs.append(abs_path_dir)
|
|
2491
|
+
except Exception:
|
|
2492
|
+
with suppress(Exception):
|
|
2493
|
+
chrome_options.add_extension(abs_path)
|
|
2468
2494
|
if extension_dir:
|
|
2469
2495
|
# load-extension input can be a comma-separated list
|
|
2470
2496
|
abs_path = (
|
|
2471
2497
|
",".join(os.path.abspath(p) for p in extension_dir.split(","))
|
|
2472
2498
|
)
|
|
2473
2499
|
chrome_options = add_chrome_ext_dir(chrome_options, abs_path)
|
|
2500
|
+
for p in extension_dir.split(","):
|
|
2501
|
+
sb_config._ext_dirs.append(os.path.abspath(p))
|
|
2474
2502
|
if (
|
|
2475
2503
|
page_load_strategy
|
|
2476
2504
|
and page_load_strategy.lower() in ["eager", "none"]
|
|
@@ -2505,37 +2533,32 @@ def _set_chrome_options(
|
|
|
2505
2533
|
if (settings.DISABLE_CSP_ON_CHROME or disable_csp) and not headless:
|
|
2506
2534
|
# Headless Chrome does not support extensions, which are required
|
|
2507
2535
|
# for disabling the Content Security Policy on Chrome.
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
chrome_options
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
else:
|
|
2516
|
-
chrome_options = _add_chrome_disable_csp_extension(chrome_options)
|
|
2536
|
+
disable_csp_zip = DISABLE_CSP_ZIP_PATH
|
|
2537
|
+
disable_csp_dir = os.path.join(DOWNLOADS_FOLDER, "disable_csp")
|
|
2538
|
+
_unzip_to_new_folder(disable_csp_zip, disable_csp_dir)
|
|
2539
|
+
chrome_options = add_chrome_ext_dir(
|
|
2540
|
+
chrome_options, disable_csp_dir
|
|
2541
|
+
)
|
|
2542
|
+
sb_config._ext_dirs.append(disable_csp_dir)
|
|
2517
2543
|
if ad_block_on and not headless:
|
|
2518
2544
|
# Headless Chrome does not support extensions.
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
else:
|
|
2525
|
-
chrome_options = _add_chrome_ad_block_extension(chrome_options)
|
|
2545
|
+
ad_block_zip = AD_BLOCK_ZIP_PATH
|
|
2546
|
+
ad_block_dir = os.path.join(DOWNLOADS_FOLDER, "ad_block")
|
|
2547
|
+
_unzip_to_new_folder(ad_block_zip, ad_block_dir)
|
|
2548
|
+
chrome_options = add_chrome_ext_dir(chrome_options, ad_block_dir)
|
|
2549
|
+
sb_config._ext_dirs.append(ad_block_dir)
|
|
2526
2550
|
if recorder_ext and not headless:
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
else:
|
|
2533
|
-
chrome_options = _add_chrome_recorder_extension(chrome_options)
|
|
2551
|
+
recorder_zip = RECORDER_ZIP_PATH
|
|
2552
|
+
recorder_dir = os.path.join(DOWNLOADS_FOLDER, "recorder")
|
|
2553
|
+
_unzip_to_new_folder(recorder_zip, recorder_dir)
|
|
2554
|
+
chrome_options = add_chrome_ext_dir(chrome_options, recorder_dir)
|
|
2555
|
+
sb_config._ext_dirs.append(recorder_dir)
|
|
2534
2556
|
if chromium_arg and "sbase" in chromium_arg:
|
|
2535
2557
|
sbase_ext_zip = SBASE_EXT_ZIP_PATH
|
|
2536
2558
|
sbase_ext_dir = os.path.join(DOWNLOADS_FOLDER, "sbase_ext")
|
|
2537
2559
|
_unzip_to_new_folder(sbase_ext_zip, sbase_ext_dir)
|
|
2538
2560
|
chrome_options = add_chrome_ext_dir(chrome_options, sbase_ext_dir)
|
|
2561
|
+
sb_config._ext_dirs.append(sbase_ext_dir)
|
|
2539
2562
|
if proxy_string:
|
|
2540
2563
|
if proxy_auth:
|
|
2541
2564
|
zip_it = True
|
|
@@ -2721,6 +2744,10 @@ def _set_chrome_options(
|
|
|
2721
2744
|
chrome_options.add_argument("--disable-features=%s" % d_f_string)
|
|
2722
2745
|
if proxy_auth:
|
|
2723
2746
|
chrome_options.add_argument("--test-type")
|
|
2747
|
+
if proxy_auth or sb_config._ext_dirs:
|
|
2748
|
+
if not is_using_uc(undetectable, browser_name):
|
|
2749
|
+
chrome_options.enable_webextensions = True
|
|
2750
|
+
chrome_options.enable_bidi = True
|
|
2724
2751
|
if (
|
|
2725
2752
|
is_using_uc(undetectable, browser_name)
|
|
2726
2753
|
and (
|
|
@@ -2985,6 +3012,7 @@ def get_driver(
|
|
|
2985
3012
|
device_pixel_ratio=None,
|
|
2986
3013
|
browser=None, # A duplicate of browser_name to avoid confusion
|
|
2987
3014
|
):
|
|
3015
|
+
sb_config._ext_dirs = []
|
|
2988
3016
|
driver_dir = DRIVER_DIR
|
|
2989
3017
|
if (
|
|
2990
3018
|
hasattr(sb_config, "binary_location")
|
|
@@ -64,6 +64,11 @@ class CDPMethods():
|
|
|
64
64
|
)
|
|
65
65
|
element.highlight_overlay = lambda: self.__highlight_overlay(element)
|
|
66
66
|
element.mouse_click = lambda: self.__mouse_click(element)
|
|
67
|
+
element.click_with_offset = (
|
|
68
|
+
lambda *args, **kwargs: self.__mouse_click_with_offset_async(
|
|
69
|
+
element, *args, **kwargs
|
|
70
|
+
)
|
|
71
|
+
)
|
|
67
72
|
element.mouse_drag = (
|
|
68
73
|
lambda destination: self.__mouse_drag(element, destination)
|
|
69
74
|
)
|
|
@@ -447,6 +452,15 @@ class CDPMethods():
|
|
|
447
452
|
self.loop.run_until_complete(self.page.wait())
|
|
448
453
|
return result
|
|
449
454
|
|
|
455
|
+
def __mouse_click_with_offset_async(self, element, *args, **kwargs):
|
|
456
|
+
result = (
|
|
457
|
+
self.loop.run_until_complete(
|
|
458
|
+
element.mouse_click_with_offset_async(*args, **kwargs)
|
|
459
|
+
)
|
|
460
|
+
)
|
|
461
|
+
self.loop.run_until_complete(self.page.wait())
|
|
462
|
+
return result
|
|
463
|
+
|
|
450
464
|
def __mouse_drag(self, element, destination):
|
|
451
465
|
return (
|
|
452
466
|
self.loop.run_until_complete(element.mouse_drag_async(destination))
|
|
@@ -689,10 +703,16 @@ class CDPMethods():
|
|
|
689
703
|
self.__slow_mode_pause_if_set()
|
|
690
704
|
element = self.find_element(selector, timeout=timeout)
|
|
691
705
|
element.scroll_into_view()
|
|
692
|
-
|
|
693
|
-
|
|
706
|
+
tag_name = element.tag_name
|
|
707
|
+
if tag_name:
|
|
708
|
+
tag_name = tag_name.lower().strip()
|
|
709
|
+
if (
|
|
710
|
+
tag_name in ["a", "button", "canvas", "div", "input", "li", "span"]
|
|
711
|
+
and "contains(" not in selector
|
|
712
|
+
):
|
|
713
|
+
element.mouse_click() # Simulated click (NOT PyAutoGUI)
|
|
694
714
|
else:
|
|
695
|
-
element.click()
|
|
715
|
+
element.click() # Standard CDP click
|
|
696
716
|
self.__slow_mode_pause_if_set()
|
|
697
717
|
self.loop.run_until_complete(self.page.wait())
|
|
698
718
|
|
|
@@ -738,7 +758,7 @@ class CDPMethods():
|
|
|
738
758
|
element.scroll_into_view()
|
|
739
759
|
element.click()
|
|
740
760
|
click_count += 1
|
|
741
|
-
time.sleep(0.
|
|
761
|
+
time.sleep(0.044)
|
|
742
762
|
self.__slow_mode_pause_if_set()
|
|
743
763
|
self.loop.run_until_complete(self.page.wait())
|
|
744
764
|
except Exception:
|
|
@@ -1757,11 +1777,32 @@ class CDPMethods():
|
|
|
1757
1777
|
self.__slow_mode_pause_if_set()
|
|
1758
1778
|
self.loop.run_until_complete(self.page.wait())
|
|
1759
1779
|
|
|
1760
|
-
def
|
|
1761
|
-
|
|
1762
|
-
|
|
1780
|
+
def gui_click_with_offset(
|
|
1781
|
+
self, selector, x, y, timeframe=0.25, center=False
|
|
1782
|
+
):
|
|
1783
|
+
"""Click an element at an {X,Y}-offset location.
|
|
1784
|
+
{0,0} is the top-left corner of the element.
|
|
1785
|
+
If center==True, {0,0} becomes the center of the element.
|
|
1786
|
+
The timeframe is the time spent moving the mouse."""
|
|
1787
|
+
if center:
|
|
1788
|
+
px, py = self.get_gui_element_center(selector)
|
|
1789
|
+
self.gui_click_x_y(px + x, py + y, timeframe=timeframe)
|
|
1790
|
+
else:
|
|
1791
|
+
element_rect = self.get_gui_element_rect(selector)
|
|
1792
|
+
px = element_rect["x"]
|
|
1793
|
+
py = element_rect["y"]
|
|
1794
|
+
self.gui_click_x_y(px + x, py + y, timeframe=timeframe)
|
|
1795
|
+
|
|
1796
|
+
def click_with_offset(self, selector, x, y, center=False):
|
|
1797
|
+
element = self.find_element(selector)
|
|
1798
|
+
element.scroll_into_view()
|
|
1799
|
+
element.click_with_offset(x=x, y=y, center=center)
|
|
1800
|
+
self.__slow_mode_pause_if_set()
|
|
1801
|
+
self.loop.run_until_complete(self.page.wait())
|
|
1802
|
+
|
|
1803
|
+
def _on_a_cf_turnstile_page(self, source=None):
|
|
1763
1804
|
if not source or len(source) < 400:
|
|
1764
|
-
time.sleep(0.
|
|
1805
|
+
time.sleep(0.2)
|
|
1765
1806
|
source = self.get_page_source()
|
|
1766
1807
|
if (
|
|
1767
1808
|
'data-callback="onCaptchaSuccess"' in source
|
|
@@ -1773,20 +1814,21 @@ class CDPMethods():
|
|
|
1773
1814
|
return True
|
|
1774
1815
|
return False
|
|
1775
1816
|
|
|
1776
|
-
def _on_a_g_recaptcha_page(self):
|
|
1777
|
-
time.sleep(0.042)
|
|
1778
|
-
source = self.get_page_source()
|
|
1817
|
+
def _on_a_g_recaptcha_page(self, source=None):
|
|
1779
1818
|
if not source or len(source) < 400:
|
|
1780
|
-
time.sleep(0.
|
|
1819
|
+
time.sleep(0.2)
|
|
1781
1820
|
source = self.get_page_source()
|
|
1782
1821
|
if (
|
|
1783
1822
|
'id="recaptcha-token"' in source
|
|
1784
1823
|
or 'title="reCAPTCHA"' in source
|
|
1785
1824
|
):
|
|
1786
1825
|
return True
|
|
1826
|
+
elif "/recaptcha/api.js" in source:
|
|
1827
|
+
time.sleep(1.6) # Still loading
|
|
1828
|
+
return True
|
|
1787
1829
|
return False
|
|
1788
1830
|
|
|
1789
|
-
def __gui_click_recaptcha(self):
|
|
1831
|
+
def __gui_click_recaptcha(self, use_cdp=False):
|
|
1790
1832
|
selector = None
|
|
1791
1833
|
if self.is_element_visible('iframe[title="reCAPTCHA"]'):
|
|
1792
1834
|
selector = 'iframe[title="reCAPTCHA"]'
|
|
@@ -1797,19 +1839,39 @@ class CDPMethods():
|
|
|
1797
1839
|
element_rect = self.get_gui_element_rect(selector, timeout=1)
|
|
1798
1840
|
e_x = element_rect["x"]
|
|
1799
1841
|
e_y = element_rect["y"]
|
|
1800
|
-
|
|
1801
|
-
|
|
1842
|
+
x_offset = 26
|
|
1843
|
+
y_offset = 35
|
|
1844
|
+
if shared_utils.is_windows():
|
|
1845
|
+
x_offset = 29
|
|
1846
|
+
x = e_x + x_offset
|
|
1847
|
+
y = e_y + y_offset
|
|
1802
1848
|
sb_config._saved_cf_x_y = (x, y)
|
|
1803
1849
|
time.sleep(0.08)
|
|
1804
|
-
|
|
1850
|
+
if use_cdp:
|
|
1851
|
+
self.sleep(0.03)
|
|
1852
|
+
gui_lock = FileLock(constants.MultiBrowser.PYAUTOGUILOCK)
|
|
1853
|
+
with gui_lock: # Prevent issues with multiple processes
|
|
1854
|
+
self.bring_active_window_to_front()
|
|
1855
|
+
time.sleep(0.056)
|
|
1856
|
+
self.click_with_offset(selector, x_offset, y_offset)
|
|
1857
|
+
time.sleep(0.056)
|
|
1858
|
+
else:
|
|
1859
|
+
self.gui_click_x_y(x, y)
|
|
1860
|
+
|
|
1861
|
+
def solve_captcha(self):
|
|
1862
|
+
self.__click_captcha(use_cdp=True)
|
|
1805
1863
|
|
|
1806
1864
|
def gui_click_captcha(self):
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1865
|
+
self.__click_captcha(use_cdp=False)
|
|
1866
|
+
|
|
1867
|
+
def __click_captcha(self, use_cdp=False):
|
|
1868
|
+
"""Uses PyAutoGUI unless use_cdp == True"""
|
|
1869
|
+
self.sleep(0.056)
|
|
1870
|
+
source = self.get_page_source()
|
|
1871
|
+
if self._on_a_g_recaptcha_page(source):
|
|
1872
|
+
self.__gui_click_recaptcha(use_cdp)
|
|
1811
1873
|
return
|
|
1812
|
-
|
|
1874
|
+
elif not self._on_a_cf_turnstile_page(source):
|
|
1813
1875
|
return
|
|
1814
1876
|
selector = None
|
|
1815
1877
|
if (
|
|
@@ -1970,14 +2032,24 @@ class CDPMethods():
|
|
|
1970
2032
|
element_rect = self.get_gui_element_rect(selector, timeout=1)
|
|
1971
2033
|
e_x = element_rect["x"]
|
|
1972
2034
|
e_y = element_rect["y"]
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
2035
|
+
x_offset = 32
|
|
2036
|
+
y_offset = 32
|
|
2037
|
+
if shared_utils.is_windows():
|
|
2038
|
+
y_offset = 28
|
|
2039
|
+
x = e_x + x_offset
|
|
2040
|
+
y = e_y + y_offset
|
|
1978
2041
|
sb_config._saved_cf_x_y = (x, y)
|
|
1979
2042
|
time.sleep(0.08)
|
|
1980
|
-
|
|
2043
|
+
if use_cdp:
|
|
2044
|
+
self.sleep(0.03)
|
|
2045
|
+
gui_lock = FileLock(constants.MultiBrowser.PYAUTOGUILOCK)
|
|
2046
|
+
with gui_lock: # Prevent issues with multiple processes
|
|
2047
|
+
self.bring_active_window_to_front()
|
|
2048
|
+
time.sleep(0.056)
|
|
2049
|
+
self.click_with_offset(selector, x_offset, y_offset)
|
|
2050
|
+
time.sleep(0.056)
|
|
2051
|
+
else:
|
|
2052
|
+
self.gui_click_x_y(x, y)
|
|
1981
2053
|
|
|
1982
2054
|
def __gui_drag_drop(self, x1, y1, x2, y2, timeframe=0.25, uc_lock=False):
|
|
1983
2055
|
self.__install_pyautogui_if_missing()
|
|
@@ -4694,7 +4694,7 @@ class BaseCase(unittest.TestCase):
|
|
|
4694
4694
|
if not os.path.exists(file_path):
|
|
4695
4695
|
os.makedirs(file_path)
|
|
4696
4696
|
cookies_file_path = os.path.join(file_path, name)
|
|
4697
|
-
cookies_file = open(cookies_file_path, "w+", encoding="utf-8")
|
|
4697
|
+
cookies_file = open(cookies_file_path, mode="w+", encoding="utf-8")
|
|
4698
4698
|
cookies_file.writelines(json_cookies)
|
|
4699
4699
|
cookies_file.close()
|
|
4700
4700
|
|
|
@@ -5008,6 +5008,9 @@ class BaseCase(unittest.TestCase):
|
|
|
5008
5008
|
self.get_new_driver(undetectable=True)
|
|
5009
5009
|
self.driver.uc_open_with_cdp_mode(url, **kwargs)
|
|
5010
5010
|
self.cdp = self.driver.cdp
|
|
5011
|
+
if hasattr(self.cdp, "solve_captcha"):
|
|
5012
|
+
self.solve_captcha = self.cdp.solve_captcha
|
|
5013
|
+
self.undetectable = True
|
|
5011
5014
|
|
|
5012
5015
|
def activate_recorder(self):
|
|
5013
5016
|
"""Activate Recorder Mode on the current tab/window.
|
|
@@ -5748,7 +5751,7 @@ class BaseCase(unittest.TestCase):
|
|
|
5748
5751
|
extra_file_name = "__init__.py"
|
|
5749
5752
|
extra_file_path = os.path.join(recordings_folder, extra_file_name)
|
|
5750
5753
|
if not os.path.exists(extra_file_path):
|
|
5751
|
-
out_file = open(extra_file_path, "w+", "utf-8")
|
|
5754
|
+
out_file = open(extra_file_path, mode="w+", encoding="utf-8")
|
|
5752
5755
|
out_file.writelines("\r\n".join(data))
|
|
5753
5756
|
out_file.close()
|
|
5754
5757
|
sys.stdout.write("\nCreated recordings%s__init__.py" % os.sep)
|
|
@@ -5796,7 +5799,7 @@ class BaseCase(unittest.TestCase):
|
|
|
5796
5799
|
extra_file_name = "pytest.ini"
|
|
5797
5800
|
extra_file_path = os.path.join(recordings_folder, extra_file_name)
|
|
5798
5801
|
if not os.path.exists(extra_file_path):
|
|
5799
|
-
out_file = open(extra_file_path, "w+", "utf-8")
|
|
5802
|
+
out_file = open(extra_file_path, mode="w+", encoding="utf-8")
|
|
5800
5803
|
out_file.writelines("\r\n".join(data))
|
|
5801
5804
|
out_file.close()
|
|
5802
5805
|
sys.stdout.write("\nCreated recordings%spytest.ini" % os.sep)
|
|
@@ -5817,7 +5820,7 @@ class BaseCase(unittest.TestCase):
|
|
|
5817
5820
|
extra_file_name = "setup.cfg"
|
|
5818
5821
|
extra_file_path = os.path.join(recordings_folder, extra_file_name)
|
|
5819
5822
|
if not os.path.exists(extra_file_path):
|
|
5820
|
-
out_file = open(extra_file_path, "w+", "utf-8")
|
|
5823
|
+
out_file = open(extra_file_path, mode="w+", encoding="utf-8")
|
|
5821
5824
|
out_file.writelines("\r\n".join(data))
|
|
5822
5825
|
out_file.close()
|
|
5823
5826
|
sys.stdout.write("\nCreated recordings%ssetup.cfg" % os.sep)
|
|
@@ -5835,7 +5838,7 @@ class BaseCase(unittest.TestCase):
|
|
|
5835
5838
|
elif context_filename:
|
|
5836
5839
|
file_name = context_filename
|
|
5837
5840
|
file_path = os.path.join(recordings_folder, file_name)
|
|
5838
|
-
out_file = open(file_path, "w+", "utf-8")
|
|
5841
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
5839
5842
|
out_file.writelines("\r\n".join(data))
|
|
5840
5843
|
out_file.close()
|
|
5841
5844
|
rec_message = ">>> RECORDING SAVED as: "
|
|
@@ -5937,7 +5940,7 @@ class BaseCase(unittest.TestCase):
|
|
|
5937
5940
|
file_name = sb_config.behave_scenario.filename.replace(".", "_")
|
|
5938
5941
|
file_name = file_name.split("/")[-1].split("\\")[-1] + "_rec.feature"
|
|
5939
5942
|
file_path = os.path.join(features_folder, file_name)
|
|
5940
|
-
out_file = open(file_path, "w+", "utf-8")
|
|
5943
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
5941
5944
|
out_file.writelines("\r\n".join(data))
|
|
5942
5945
|
out_file.close()
|
|
5943
5946
|
|
|
@@ -5975,7 +5978,7 @@ class BaseCase(unittest.TestCase):
|
|
|
5975
5978
|
file_name = "__init__.py"
|
|
5976
5979
|
file_path = os.path.join(features_folder, file_name)
|
|
5977
5980
|
if not os.path.exists(file_path):
|
|
5978
|
-
out_file = open(file_path, "w+", "utf-8")
|
|
5981
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
5979
5982
|
out_file.writelines("\r\n".join(data))
|
|
5980
5983
|
out_file.close()
|
|
5981
5984
|
print("Created recordings/features/__init__.py")
|
|
@@ -5988,7 +5991,7 @@ class BaseCase(unittest.TestCase):
|
|
|
5988
5991
|
file_name = "behave.ini"
|
|
5989
5992
|
file_path = os.path.join(features_folder, file_name)
|
|
5990
5993
|
if not os.path.exists(file_path):
|
|
5991
|
-
out_file = open(file_path, "w+", "utf-8")
|
|
5994
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
5992
5995
|
out_file.writelines("\r\n".join(data))
|
|
5993
5996
|
out_file.close()
|
|
5994
5997
|
print("Created recordings/features/behave.ini")
|
|
@@ -6027,7 +6030,7 @@ class BaseCase(unittest.TestCase):
|
|
|
6027
6030
|
file_name = "environment.py"
|
|
6028
6031
|
file_path = os.path.join(features_folder, file_name)
|
|
6029
6032
|
if not os.path.exists(file_path):
|
|
6030
|
-
out_file = open(file_path, "w+", "utf-8")
|
|
6033
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
6031
6034
|
out_file.writelines("\r\n".join(data))
|
|
6032
6035
|
out_file.close()
|
|
6033
6036
|
print("Created recordings/features/environment.py")
|
|
@@ -6037,7 +6040,7 @@ class BaseCase(unittest.TestCase):
|
|
|
6037
6040
|
file_name = "__init__.py"
|
|
6038
6041
|
file_path = os.path.join(steps_folder, file_name)
|
|
6039
6042
|
if not os.path.exists(file_path):
|
|
6040
|
-
out_file = open(file_path, "w+", "utf-8")
|
|
6043
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
6041
6044
|
out_file.writelines("\r\n".join(data))
|
|
6042
6045
|
out_file.close()
|
|
6043
6046
|
print("Created recordings/features/steps/__init__.py")
|
|
@@ -6048,7 +6051,7 @@ class BaseCase(unittest.TestCase):
|
|
|
6048
6051
|
file_name = "imported.py"
|
|
6049
6052
|
file_path = os.path.join(steps_folder, file_name)
|
|
6050
6053
|
if not os.path.exists(file_path):
|
|
6051
|
-
out_file = open(file_path, "w+", "utf-8")
|
|
6054
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
6052
6055
|
out_file.writelines("\r\n".join(data))
|
|
6053
6056
|
out_file.close()
|
|
6054
6057
|
print("Created recordings/features/steps/imported.py")
|
|
@@ -11117,7 +11120,7 @@ class BaseCase(unittest.TestCase):
|
|
|
11117
11120
|
return # Skip the rest when deferred visual asserts are used
|
|
11118
11121
|
the_html = visual_helper.get_sbs_html()
|
|
11119
11122
|
file_path = os.path.join(test_logpath, constants.SideBySide.HTML_FILE)
|
|
11120
|
-
out_file = open(file_path, "w+", encoding="utf-8")
|
|
11123
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
11121
11124
|
out_file.writelines(the_html)
|
|
11122
11125
|
out_file.close()
|
|
11123
11126
|
|
|
@@ -11277,16 +11280,16 @@ class BaseCase(unittest.TestCase):
|
|
|
11277
11280
|
self.save_screenshot(
|
|
11278
11281
|
baseline_png, visual_baseline_path, selector="body"
|
|
11279
11282
|
)
|
|
11280
|
-
out_file = open(page_url_file, "w+", encoding="utf-8")
|
|
11283
|
+
out_file = open(page_url_file, mode="w+", encoding="utf-8")
|
|
11281
11284
|
out_file.writelines(page_url)
|
|
11282
11285
|
out_file.close()
|
|
11283
|
-
out_file = open(level_1_file, "w+", encoding="utf-8")
|
|
11286
|
+
out_file = open(level_1_file, mode="w+", encoding="utf-8")
|
|
11284
11287
|
out_file.writelines(json.dumps(level_1))
|
|
11285
11288
|
out_file.close()
|
|
11286
|
-
out_file = open(level_2_file, "w+", encoding="utf-8")
|
|
11289
|
+
out_file = open(level_2_file, mode="w+", encoding="utf-8")
|
|
11287
11290
|
out_file.writelines(json.dumps(level_2))
|
|
11288
11291
|
out_file.close()
|
|
11289
|
-
out_file = open(level_3_file, "w+", encoding="utf-8")
|
|
11292
|
+
out_file = open(level_3_file, mode="w+", encoding="utf-8")
|
|
11290
11293
|
out_file.writelines(json.dumps(level_3))
|
|
11291
11294
|
out_file.close()
|
|
11292
11295
|
|
|
@@ -11425,7 +11428,7 @@ class BaseCase(unittest.TestCase):
|
|
|
11425
11428
|
alpha_n_d_name = "".join([x if x.isalnum() else "_" for x in name])
|
|
11426
11429
|
side_by_side_name = "side_by_side_%s.html" % alpha_n_d_name
|
|
11427
11430
|
file_path = os.path.join(test_logpath, side_by_side_name)
|
|
11428
|
-
out_file = open(file_path, "w+", encoding="utf-8")
|
|
11431
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
11429
11432
|
out_file.writelines(the_html)
|
|
11430
11433
|
out_file.close()
|
|
11431
11434
|
|
|
@@ -11452,6 +11455,7 @@ class BaseCase(unittest.TestCase):
|
|
|
11452
11455
|
if cdp_swap_needed:
|
|
11453
11456
|
if not self.cdp:
|
|
11454
11457
|
self.cdp = self.driver.cdp
|
|
11458
|
+
self.undetectable = True
|
|
11455
11459
|
return True
|
|
11456
11460
|
else:
|
|
11457
11461
|
return False
|
|
@@ -12116,7 +12120,7 @@ class BaseCase(unittest.TestCase):
|
|
|
12116
12120
|
with suppress(Exception):
|
|
12117
12121
|
os.makedirs(saved_presentations_folder)
|
|
12118
12122
|
file_path = os.path.join(saved_presentations_folder, filename)
|
|
12119
|
-
out_file = open(file_path, "w+", encoding="utf-8")
|
|
12123
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
12120
12124
|
out_file.writelines(the_html)
|
|
12121
12125
|
out_file.close()
|
|
12122
12126
|
if self._output_file_saves:
|
|
@@ -12811,7 +12815,7 @@ class BaseCase(unittest.TestCase):
|
|
|
12811
12815
|
with suppress(Exception):
|
|
12812
12816
|
os.makedirs(saved_charts_folder)
|
|
12813
12817
|
file_path = os.path.join(saved_charts_folder, filename)
|
|
12814
|
-
out_file = open(file_path, "w+", encoding="utf-8")
|
|
12818
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
12815
12819
|
out_file.writelines(the_html)
|
|
12816
12820
|
out_file.close()
|
|
12817
12821
|
if self._output_file_saves:
|
|
@@ -13970,6 +13974,9 @@ class BaseCase(unittest.TestCase):
|
|
|
13970
13974
|
timeout=None,
|
|
13971
13975
|
center=None,
|
|
13972
13976
|
):
|
|
13977
|
+
if self.__is_cdp_swap_needed():
|
|
13978
|
+
self.cdp.click_with_offset(selector, x, y, center=center)
|
|
13979
|
+
return
|
|
13973
13980
|
self.wait_for_ready_state_complete()
|
|
13974
13981
|
if self.__needs_minimum_wait():
|
|
13975
13982
|
time.sleep(0.14)
|
|
@@ -16371,7 +16378,7 @@ class BaseCase(unittest.TestCase):
|
|
|
16371
16378
|
dash_pie = json.dumps(sb_config._saved_dashboard_pie)
|
|
16372
16379
|
dash_pie_loc = constants.Dashboard.DASH_PIE
|
|
16373
16380
|
pie_path = os.path.join(abs_path, dash_pie_loc)
|
|
16374
|
-
pie_file = open(pie_path, "w+", encoding="utf-8")
|
|
16381
|
+
pie_file = open(pie_path, mode="w+", encoding="utf-8")
|
|
16375
16382
|
pie_file.writelines(dash_pie)
|
|
16376
16383
|
pie_file.close()
|
|
16377
16384
|
DASH_PIE_PNG_1 = constants.Dashboard.get_dash_pie_1()
|
|
@@ -16531,7 +16538,7 @@ class BaseCase(unittest.TestCase):
|
|
|
16531
16538
|
)
|
|
16532
16539
|
abs_path = os.path.abspath(".")
|
|
16533
16540
|
file_path = os.path.join(abs_path, "dashboard.html")
|
|
16534
|
-
out_file = open(file_path, "w+", encoding="utf-8")
|
|
16541
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
16535
16542
|
out_file.writelines(the_html)
|
|
16536
16543
|
out_file.close()
|
|
16537
16544
|
sb_config._dash_html = the_html
|
|
@@ -16544,7 +16551,7 @@ class BaseCase(unittest.TestCase):
|
|
|
16544
16551
|
dash_json = json.dumps((_results, _display_id, _rt, _tlp, d_stats))
|
|
16545
16552
|
dash_json_loc = constants.Dashboard.DASH_JSON
|
|
16546
16553
|
dash_jsonpath = os.path.join(abs_path, dash_json_loc)
|
|
16547
|
-
dash_json_file = open(dash_jsonpath, "w+", encoding="utf-8")
|
|
16554
|
+
dash_json_file = open(dash_jsonpath, mode="w+", encoding="utf-8")
|
|
16548
16555
|
dash_json_file.writelines(dash_json)
|
|
16549
16556
|
dash_json_file.close()
|
|
16550
16557
|
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import fasteners
|
|
2
1
|
import json
|
|
3
2
|
import logging
|
|
4
3
|
import requests
|
|
5
|
-
|
|
6
|
-
from seleniumbase.fixtures import shared_utils
|
|
4
|
+
import websockets
|
|
7
5
|
|
|
8
6
|
log = logging.getLogger(__name__)
|
|
9
7
|
|
|
@@ -107,15 +105,6 @@ class CDP:
|
|
|
107
105
|
return resp.json()
|
|
108
106
|
|
|
109
107
|
async def send(self, method, params):
|
|
110
|
-
pip_find_lock = fasteners.InterProcessLock(
|
|
111
|
-
constants.PipInstall.FINDLOCK
|
|
112
|
-
)
|
|
113
|
-
with pip_find_lock:
|
|
114
|
-
try:
|
|
115
|
-
import websockets
|
|
116
|
-
except Exception:
|
|
117
|
-
shared_utils.pip_install("websockets")
|
|
118
|
-
import websockets
|
|
119
108
|
self._reqid += 1
|
|
120
109
|
async with websockets.connect(self.wsurl) as ws:
|
|
121
110
|
await ws.send(
|
|
@@ -350,8 +350,7 @@ class Browser:
|
|
|
350
350
|
if _cdp_geolocation:
|
|
351
351
|
await connection.send(cdp.page.navigate("about:blank"))
|
|
352
352
|
await connection.set_geolocation(_cdp_geolocation)
|
|
353
|
-
#
|
|
354
|
-
"""
|
|
353
|
+
# (The code below is for the Chrome 142 extension fix)
|
|
355
354
|
if (
|
|
356
355
|
hasattr(sb_config, "_cdp_proxy")
|
|
357
356
|
and "@" in sb_config._cdp_proxy
|
|
@@ -363,7 +362,6 @@ class Browser:
|
|
|
363
362
|
proxy_pass = username_and_password.split(":")[1]
|
|
364
363
|
await connection.set_auth(proxy_user, proxy_pass, self.tabs[0])
|
|
365
364
|
time.sleep(0.25)
|
|
366
|
-
"""
|
|
367
365
|
if "auth" in kwargs and kwargs["auth"] and ":" in kwargs["auth"]:
|
|
368
366
|
username_and_password = kwargs["auth"]
|
|
369
367
|
proxy_user = username_and_password.split(":")[0]
|
|
@@ -375,12 +373,12 @@ class Browser:
|
|
|
375
373
|
cdp.page.navigate(url)
|
|
376
374
|
)
|
|
377
375
|
if _cdp_recorder:
|
|
378
|
-
|
|
379
|
-
|
|
376
|
+
# (The code below is for the Chrome 142 extension fix)
|
|
377
|
+
from seleniumbase.js_code.recorder_js import recorder_js
|
|
380
378
|
recorder_code = (
|
|
381
379
|
"""window.onload = function() { %s };""" % recorder_js
|
|
382
380
|
)
|
|
383
|
-
await connection.send(cdp.runtime.evaluate(recorder_code))
|
|
381
|
+
await connection.send(cdp.runtime.evaluate(recorder_code))
|
|
384
382
|
# Update the frame_id on the tab
|
|
385
383
|
connection.frame_id = frame_id
|
|
386
384
|
connection.browser = self
|
|
@@ -79,7 +79,8 @@ class Config:
|
|
|
79
79
|
if not browser_args:
|
|
80
80
|
browser_args = []
|
|
81
81
|
if not user_data_dir:
|
|
82
|
-
self.
|
|
82
|
+
self.user_data_dir = temp_profile_dir()
|
|
83
|
+
self._user_data_dir = self.user_data_dir
|
|
83
84
|
self._custom_data_dir = False
|
|
84
85
|
else:
|
|
85
86
|
self.user_data_dir = user_data_dir
|
|
@@ -315,10 +316,13 @@ def find_chrome_executable(return_all=False):
|
|
|
315
316
|
for item in os.environ.get("PATH").split(os.pathsep):
|
|
316
317
|
for subitem in (
|
|
317
318
|
"google-chrome",
|
|
319
|
+
"google-chrome-stable",
|
|
320
|
+
"google-chrome-beta",
|
|
321
|
+
"google-chrome-dev",
|
|
322
|
+
"google-chrome-unstable",
|
|
323
|
+
"chrome",
|
|
318
324
|
"chromium",
|
|
319
325
|
"chromium-browser",
|
|
320
|
-
"chrome",
|
|
321
|
-
"google-chrome-stable",
|
|
322
326
|
):
|
|
323
327
|
candidates.append(os.sep.join((item, subitem)))
|
|
324
328
|
if "darwin" in sys.platform:
|
|
@@ -347,7 +351,11 @@ def find_chrome_executable(return_all=False):
|
|
|
347
351
|
)
|
|
348
352
|
rv = []
|
|
349
353
|
for candidate in candidates:
|
|
350
|
-
if
|
|
354
|
+
if (
|
|
355
|
+
os.path.exists(candidate)
|
|
356
|
+
and os.access(candidate, os.R_OK)
|
|
357
|
+
and os.access(candidate, os.X_OK)
|
|
358
|
+
):
|
|
351
359
|
logger.debug("%s is a valid candidate... " % candidate)
|
|
352
360
|
rv.append(candidate)
|
|
353
361
|
else:
|