diff --git a/examples/cdp_mode/ReadMe.md b/examples/cdp_mode/ReadMe.md
index 323c6ceda45..26aac55a0f4 100644
--- a/examples/cdp_mode/ReadMe.md
+++ b/examples/cdp_mode/ReadMe.md
@@ -140,7 +140,7 @@ from seleniumbase import SB
with SB(uc=True, test=True, locale="en", ad_block=True) as sb:
url = "https://www.pokemon.com/us"
sb.activate_cdp_mode(url)
- sb.sleep(3.5)
+ sb.sleep(1.5)
sb.click_if_visible("button#onetrust-accept-btn-handler")
sb.sleep(1.2)
sb.click("a span.icon_pokeball")
@@ -193,7 +193,7 @@ from seleniumbase import SB
with SB(uc=True, test=True, locale="en") as sb:
url = "https://www.hyatt.com/"
sb.activate_cdp_mode(url)
- sb.sleep(3.8)
+ sb.sleep(3.2)
sb.click_if_visible('button[aria-label="Close"]')
sb.sleep(0.1)
sb.click_if_visible("#onetrust-reject-all-handler")
@@ -282,7 +282,11 @@ from seleniumbase import SB
with SB(uc=True, test=True, ad_block=True) as sb:
url = "https://www.walmart.com/"
sb.activate_cdp_mode(url)
- sb.sleep(2.8)
+ sb.sleep(1.8)
+ continue_button = 'button:contains("Continue shopping")'
+ if sb.is_element_visible(continue_button):
+ sb.cdp.gui_click_element(continue_button)
+ sb.sleep(0.6)
sb.click('input[aria-label="Search"]')
sb.sleep(1.2)
search = "Settlers of Catan Board Game"
diff --git a/examples/cdp_mode/raw_cdp_hyatt.py b/examples/cdp_mode/raw_cdp_hyatt.py
index 072bf9e5452..6bf9fd27128 100644
--- a/examples/cdp_mode/raw_cdp_hyatt.py
+++ b/examples/cdp_mode/raw_cdp_hyatt.py
@@ -2,7 +2,7 @@
url = "https://www.hyatt.com/"
sb = sb_cdp.Chrome(url, locale="en", guest=True)
-sb.sleep(4.2)
+sb.sleep(3.6)
sb.click_if_visible('button[aria-label="Close"]')
sb.sleep(0.1)
sb.click_if_visible("#onetrust-reject-all-handler")
diff --git a/examples/cdp_mode/raw_hyatt.py b/examples/cdp_mode/raw_hyatt.py
index eca5cdfd970..9876c283c94 100644
--- a/examples/cdp_mode/raw_hyatt.py
+++ b/examples/cdp_mode/raw_hyatt.py
@@ -3,7 +3,7 @@
with SB(uc=True, test=True, locale="en") as sb:
url = "https://www.hyatt.com/"
sb.activate_cdp_mode(url)
- sb.sleep(3.8)
+ sb.sleep(3.2)
sb.click_if_visible('button[aria-label="Close"]')
sb.sleep(0.1)
sb.click_if_visible("#onetrust-reject-all-handler")
diff --git a/examples/cdp_mode/raw_pokemon.py b/examples/cdp_mode/raw_pokemon.py
index d5d0163c986..7b5f2f1badc 100644
--- a/examples/cdp_mode/raw_pokemon.py
+++ b/examples/cdp_mode/raw_pokemon.py
@@ -3,7 +3,7 @@
with SB(uc=True, test=True, locale="en", guest=True) as sb:
url = "https://www.pokemon.com/us"
sb.activate_cdp_mode(url)
- sb.sleep(3.5)
+ sb.sleep(1.5)
sb.click_if_visible("button#onetrust-accept-btn-handler")
sb.sleep(1.2)
sb.click("a span.icon_pokeball")
diff --git a/examples/cdp_mode/raw_walmart.py b/examples/cdp_mode/raw_walmart.py
index e5cfb029abe..daa6b0c317a 100644
--- a/examples/cdp_mode/raw_walmart.py
+++ b/examples/cdp_mode/raw_walmart.py
@@ -3,7 +3,11 @@
with SB(uc=True, test=True, ad_block=True) as sb:
url = "https://www.walmart.com/"
sb.activate_cdp_mode(url)
- sb.sleep(2.8)
+ sb.sleep(1.8)
+ continue_button = 'button:contains("Continue shopping")'
+ if sb.is_element_visible(continue_button):
+ sb.cdp.gui_click_element(continue_button)
+ sb.sleep(0.6)
sb.click('input[aria-label="Search"]')
sb.sleep(1.2)
search = "Settlers of Catan Board Game"
diff --git a/examples/cdp_mode/raw_xhr_async.py b/examples/cdp_mode/raw_xhr_async.py
index ee548503449..2ee00bb054e 100644
--- a/examples/cdp_mode/raw_xhr_async.py
+++ b/examples/cdp_mode/raw_xhr_async.py
@@ -64,9 +64,9 @@ async def crawl():
# Change url to something that makes ajax requests
tab = await driver.get("https://learn.microsoft.com/en-us/")
- time.sleep(2)
- for i in range(20):
- await tab.scroll_down(4)
+ time.sleep(1.5)
+ for i in range(18):
+ await tab.scroll_down(3)
time.sleep(0.02)
xhr_responses = await receiveXHR(tab, xhr_requests)
diff --git a/examples/cdp_mode/raw_xhr_sb.py b/examples/cdp_mode/raw_xhr_sb.py
index 81ff278235c..093d188978a 100644
--- a/examples/cdp_mode/raw_xhr_sb.py
+++ b/examples/cdp_mode/raw_xhr_sb.py
@@ -63,9 +63,9 @@ async def receiveXHR(page, requests):
# Change url to something that makes ajax requests
sb.cdp.open("https://learn.microsoft.com/en-us/")
- time.sleep(2)
- for i in range(10):
- sb.cdp.scroll_down(8)
+ time.sleep(1)
+ for i in range(9):
+ sb.cdp.scroll_down(6)
loop = sb.cdp.get_event_loop()
xhr_responses = loop.run_until_complete(receiveXHR(tab, xhr_requests))
diff --git a/examples/presenter/uc_presentation_4.py b/examples/presenter/uc_presentation_4.py
index 8b2103301f7..59b26be4e5b 100644
--- a/examples/presenter/uc_presentation_4.py
+++ b/examples/presenter/uc_presentation_4.py
@@ -463,7 +463,7 @@ def test_presentation_4(self):
with SB(uc=True, test=True, locale="en", ad_block=True) as sb:
url = "https://www.pokemon.com/us"
sb.activate_cdp_mode(url)
- sb.sleep(3.5)
+ sb.sleep(1.5)
sb.click_if_visible("button#onetrust-accept-btn-handler")
sb.sleep(1.2)
sb.click("a span.icon_pokeball")
@@ -515,7 +515,11 @@ def test_presentation_4(self):
with SB(uc=True, test=True, ad_block=True) as sb:
url = "https://www.walmart.com/"
sb.activate_cdp_mode(url)
- sb.sleep(2.8)
+ sb.sleep(1.8)
+ continue_button = 'button:contains("Continue shopping")'
+ if sb.is_element_visible(continue_button):
+ sb.cdp.gui_click_element(continue_button)
+ sb.sleep(0.6)
sb.click('input[aria-label="Search"]')
sb.sleep(1.2)
search = "Settlers of Catan Board Game"
@@ -679,7 +683,7 @@ def test_presentation_4(self):
with SB(uc=True, test=True, locale="en", ad_block=True) as sb:
url = "https://www.hyatt.com/"
sb.activate_cdp_mode(url)
- sb.sleep(3.5)
+ sb.sleep(3.2)
sb.click_if_visible('button[aria-label="Close"]')
sb.sleep(0.1)
sb.click_if_visible("#onetrust-reject-all-handler")
diff --git a/examples/raw_multi_sb.py b/examples/raw_multi_sb.py
new file mode 100644
index 00000000000..b32fbe04ba7
--- /dev/null
+++ b/examples/raw_multi_sb.py
@@ -0,0 +1,24 @@
+import sys
+import threading
+from concurrent.futures import ThreadPoolExecutor
+from random import randint, seed
+from seleniumbase import SB
+sys.argv.append("-n") # Tell SeleniumBase to do thread-locking as needed
+
+
+def launch_driver(url):
+ seed(len(threading.enumerate())) # Random seed for browser placement
+ with SB() as sb:
+ sb.set_window_rect(randint(4, 720), randint(8, 410), 700, 500)
+ sb.open(url=url)
+ if sb.is_element_visible("h1"):
+ sb.highlight("h1", loops=9)
+ else:
+ sb.sleep(2.2)
+
+
+if __name__ == "__main__":
+ urls = ['https://seleniumbase.io/demo_page' for i in range(4)]
+ with ThreadPoolExecutor(max_workers=len(urls)) as executor:
+ for url in urls:
+ executor.submit(launch_driver, url)
diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py
index f25699b531a..0287f511513 100755
--- a/seleniumbase/__version__.py
+++ b/seleniumbase/__version__.py
@@ -1,2 +1,2 @@
# seleniumbase package
-__version__ = "4.44.17"
+__version__ = "4.44.18"
diff --git a/seleniumbase/console_scripts/sb_install.py b/seleniumbase/console_scripts/sb_install.py
index 32aa536f991..4ee154e2411 100644
--- a/seleniumbase/console_scripts/sb_install.py
+++ b/seleniumbase/console_scripts/sb_install.py
@@ -177,7 +177,7 @@ def requests_get_with_retry(url):
def get_cft_known_good_versions():
- if hasattr(sb_config, "cft_kgv_json") and sb_config.cft_kgv_json:
+ if getattr(sb_config, "cft_kgv_json", None):
return sb_config.cft_kgv_json
cft_ngv_url = (
"https://googlechromelabs.github.io/"
@@ -188,7 +188,7 @@ def get_cft_known_good_versions():
def get_cft_latest_versions_per_milestone():
- if hasattr(sb_config, "cft_lvpm_json") and sb_config.cft_lvpm_json:
+ if getattr(sb_config, "cft_lvpm_json", None):
return sb_config.cft_lvpm_json
cft_lvpm_url = (
"https://googlechromelabs.github.io/"
@@ -205,7 +205,7 @@ def get_cft_latest_version_from_milestone(milestone):
def get_latest_chromedriver_version(channel="Stable"):
try:
- if hasattr(sb_config, "cft_lkgv_json") and sb_config.cft_lkgv_json:
+ if getattr(sb_config, "cft_lkgv_json", None):
return sb_config.cft_lkgv_json["channels"][channel]["version"]
req = requests_get(
"https://googlechromelabs.github.io/"
@@ -239,10 +239,7 @@ def get_latest_canary_chromedriver_version():
def log_d(message):
"""If setting sb_config.settings.HIDE_DRIVER_DOWNLOADS to True,
output from driver downloads are logged instead of printed."""
- if (
- hasattr(sb_config.settings, "HIDE_DRIVER_DOWNLOADS")
- and sb_config.settings.HIDE_DRIVER_DOWNLOADS
- ):
+ if getattr(sb_config.settings, "HIDE_DRIVER_DOWNLOADS", None):
logging.debug(message)
else:
print(message)
@@ -251,7 +248,7 @@ def log_d(message):
def main(override=None, intel_for_uc=None, force_uc=None):
if override:
found_proxy = None
- if hasattr(sb_config, "proxy_driver") and sb_config.proxy_driver:
+ if getattr(sb_config, "proxy_driver", None):
if " --proxy=" in " ".join(sys.argv):
for arg in sys.argv:
if arg.startswith("--proxy="):
@@ -311,8 +308,7 @@ def main(override=None, intel_for_uc=None, force_uc=None):
downloads_folder = DRIVER_DIR
if (
hasattr(sb_config, "settings")
- and hasattr(sb_config.settings, "NEW_DRIVER_DIR")
- and sb_config.settings.NEW_DRIVER_DIR
+ and getattr(sb_config.settings, "NEW_DRIVER_DIR", None)
and os.path.exists(sb_config.settings.NEW_DRIVER_DIR)
):
downloads_folder = sb_config.settings.NEW_DRIVER_DIR
diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py
index 978f21fe45d..9cb5047954f 100644
--- a/seleniumbase/core/browser_launcher.py
+++ b/seleniumbase/core/browser_launcher.py
@@ -104,10 +104,7 @@
def log_d(message):
"""If setting sb_config.settings.HIDE_DRIVER_DOWNLOADS to True,
output from driver downloads are logged instead of printed."""
- if (
- hasattr(settings, "HIDE_DRIVER_DOWNLOADS")
- and settings.HIDE_DRIVER_DOWNLOADS
- ):
+ if getattr(settings, "HIDE_DRIVER_DOWNLOADS", None):
logging.debug(message)
else:
print(message)
@@ -443,6 +440,7 @@ def has_captcha(text):
"
403 Forbidden" in text
or "Permission Denied" in text
or 'id="challenge-error-text"' in text
+ or "/challenge-platform/h/b/" in text
or "Just a moment..." in text
or 'action="/?__cf_chl_f_tk' in text
or 'id="challenge-widget-' in text
@@ -450,7 +448,6 @@ def has_captcha(text):
or 'class="g-recaptcha"' in text
or 'content="Pixelscan"' in text
or 'id="challenge-form"' in text
- or "/challenge-platform" in text
or "window._cf_chl_opt" in text
or "/recaptcha/api.js" in text
or "/turnstile/" in text
@@ -656,10 +653,8 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs):
safe_url = False
if (
- hasattr(driver, "_is_using_cdp")
- and driver._is_using_cdp
- and hasattr(driver, "cdp")
- and driver.cdp
+ getattr(driver, "_is_using_cdp", None)
+ and getattr(driver, "cdp", None)
and hasattr(driver.cdp, "loop")
):
# CDP Mode was already initialized
@@ -961,8 +956,7 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs):
driver.find_element_by_text = CDPM.find_element_by_text
driver._is_using_cdp = True
if (
- hasattr(sb_config, "_cdp_proxy")
- and sb_config._cdp_proxy
+ getattr(sb_config, "_cdp_proxy", None)
and "@" in sb_config._cdp_proxy
):
time.sleep(0.077)
@@ -1042,7 +1036,7 @@ def uc_click(
def verify_pyautogui_has_a_headed_browser(driver):
"""PyAutoGUI requires a headed browser so that it can
focus on the correct element when performing actions."""
- if hasattr(driver, "_is_hidden") and driver._is_hidden:
+ if getattr(driver, "_is_hidden", None):
raise Exception(
"PyAutoGUI can't be used in headless mode!"
)
@@ -1078,11 +1072,9 @@ def __install_pyautogui_if_missing():
xvfb_width = 1366
xvfb_height = 768
if (
- hasattr(sb_config, "_xvfb_width")
- and sb_config._xvfb_width
+ getattr(sb_config, "_xvfb_width", None)
and isinstance(sb_config._xvfb_width, int)
- and hasattr(sb_config, "_xvfb_height")
- and sb_config._xvfb_height
+ and getattr(sb_config, "_xvfb_height", None)
and isinstance(sb_config._xvfb_height, int)
):
xvfb_width = sb_config._xvfb_width
@@ -1109,8 +1101,7 @@ def __install_pyautogui_if_missing():
sb_config._virtual_display = _xvfb_display
sb_config.headless_active = True
if (
- hasattr(sb_config, "reuse_session")
- and sb_config.reuse_session
+ getattr(sb_config, "reuse_session", None)
and hasattr(sb_config, "_vd_list")
and isinstance(sb_config._vd_list, list)
):
@@ -1142,8 +1133,7 @@ def get_configured_pyautogui(pyautogui_copy):
and "DISPLAY" in os.environ.keys()
):
if (
- hasattr(sb_config, "_pyautogui_x11_display")
- and sb_config._pyautogui_x11_display
+ getattr(sb_config, "_pyautogui_x11_display", None)
and hasattr(pyautogui_copy._pyautogui_x11, "_display")
and (
sb_config._pyautogui_x11_display
@@ -1248,10 +1238,7 @@ def uc_gui_click_x_y(driver, x, y, timeframe=0.25):
connected = driver.is_connected()
if (
not connected
- and (
- not hasattr(sb_config, "_saved_width_ratio")
- or not sb_config._saved_width_ratio
- )
+ and not getattr(sb_config, "_saved_width_ratio", None)
and not __is_cdp_swap_needed(driver)
):
driver.reconnect(0.1)
@@ -1300,8 +1287,12 @@ def uc_gui_click_x_y(driver, x, y, timeframe=0.25):
def _on_a_cf_turnstile_page(driver):
source = driver.get_page_source()
if (
- 'data-callback="onCaptchaSuccess"' in source
- or "/challenge-platform/scripts/" in source
+ (
+ 'data-callback="onCaptchaSuccess"' in source
+ and 'title="reCAPTCHA"' not in source
+ and 'id="recaptcha-token"' not in source
+ )
+ or "/challenge-platform/h/b/" in source
or 'id="challenge-widget-' in source
or "challenges.cloudf" in source
or "cf-turnstile-" in source
@@ -1897,8 +1888,7 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
driver.is_element_present(".footer .clearfix .ray-id")
or driver.is_element_present("script[data-cf-beacon]")
)
- and hasattr(sb_config, "_saved_cf_tab_count")
- and sb_config._saved_cf_tab_count
+ and getattr(sb_config, "_saved_cf_tab_count", None)
and not __is_cdp_swap_needed(driver)
):
driver.uc_open_with_disconnect(driver.current_url, 3.8)
@@ -2534,8 +2524,7 @@ def _set_chrome_options(
chrome_options.page_load_strategy = page_load_strategy.lower()
elif (
not page_load_strategy
- and hasattr(settings, "PAGE_LOAD_STRATEGY")
- and settings.PAGE_LOAD_STRATEGY
+ and getattr(settings, "PAGE_LOAD_STRATEGY", None)
and settings.PAGE_LOAD_STRATEGY.lower() in ["eager", "none"]
):
# Only change it if not "normal", which is the default.
@@ -3043,15 +3032,9 @@ def get_driver(
):
sb_config._ext_dirs = []
driver_dir = DRIVER_DIR
- if (
- hasattr(sb_config, "binary_location")
- and sb_config.binary_location == "cft"
- ):
+ if getattr(sb_config, "binary_location", None) == "cft":
driver_dir = DRIVER_DIR_CFT
- if (
- hasattr(sb_config, "binary_location")
- and sb_config.binary_location == "chs"
- ):
+ if getattr(sb_config, "binary_location", None) == "chs":
driver_dir = DRIVER_DIR_CHS
if _special_binary_exists(binary_location, "opera"):
driver_dir = DRIVER_DIR_OPERA
@@ -3067,8 +3050,7 @@ def get_driver(
sb_config._cdp_browser = "atlas"
if (
hasattr(sb_config, "settings")
- and hasattr(sb_config.settings, "NEW_DRIVER_DIR")
- and sb_config.settings.NEW_DRIVER_DIR
+ and getattr(sb_config.settings, "NEW_DRIVER_DIR", None)
and os.path.exists(sb_config.settings.NEW_DRIVER_DIR)
):
driver_dir = sb_config.settings.NEW_DRIVER_DIR
@@ -4014,16 +3996,10 @@ def get_local_driver(
downloads_path = DOWNLOADS_FOLDER
driver_dir = DRIVER_DIR
special_chrome = False
- if (
- hasattr(sb_config, "binary_location")
- and sb_config.binary_location == "cft"
- ):
+ if getattr(sb_config, "binary_location", None) == "cft":
special_chrome = True
driver_dir = DRIVER_DIR_CFT
- if (
- hasattr(sb_config, "binary_location")
- and sb_config.binary_location == "chs"
- ):
+ if getattr(sb_config, "binary_location", None) == "chs":
special_chrome = True
driver_dir = DRIVER_DIR_CHS
if _special_binary_exists(binary_location, "opera"):
@@ -4040,8 +4016,7 @@ def get_local_driver(
driver_dir = DRIVER_DIR_ATLAS
if (
hasattr(sb_config, "settings")
- and hasattr(sb_config.settings, "NEW_DRIVER_DIR")
- and sb_config.settings.NEW_DRIVER_DIR
+ and getattr(sb_config.settings, "NEW_DRIVER_DIR", None)
and os.path.exists(sb_config.settings.NEW_DRIVER_DIR)
):
driver_dir = sb_config.settings.NEW_DRIVER_DIR
@@ -4651,8 +4626,7 @@ def get_local_driver(
edge_options.page_load_strategy = page_load_strategy.lower()
elif (
not page_load_strategy
- and hasattr(settings, "PAGE_LOAD_STRATEGY")
- and settings.PAGE_LOAD_STRATEGY
+ and getattr(settings, "PAGE_LOAD_STRATEGY", None)
and settings.PAGE_LOAD_STRATEGY.lower() in ["eager", "none"]
):
# Only change it if not "normal", which is the default.
@@ -4864,8 +4838,7 @@ def get_local_driver(
options.page_load_strategy = page_load_strategy.lower()
elif (
not page_load_strategy
- and hasattr(settings, "PAGE_LOAD_STRATEGY")
- and settings.PAGE_LOAD_STRATEGY
+ and getattr(settings, "PAGE_LOAD_STRATEGY", None)
and settings.PAGE_LOAD_STRATEGY.lower() in ["eager", "none"]
):
# Only change it if not "normal", which is the default.
diff --git a/seleniumbase/core/log_helper.py b/seleniumbase/core/log_helper.py
index ed380683c4c..ce537b6790c 100644
--- a/seleniumbase/core/log_helper.py
+++ b/seleniumbase/core/log_helper.py
@@ -25,7 +25,7 @@ def log_screenshot(test_logpath, driver, screenshot=None, get=False):
screenshot_skipped = constants.Warnings.SCREENSHOT_SKIPPED
screenshot_warning = constants.Warnings.SCREENSHOT_UNDEFINED
if (
- (hasattr(sb_config, "no_screenshot") and sb_config.no_screenshot)
+ getattr(sb_config, "no_screenshot", None)
or screenshot == screenshot_skipped
):
if get:
@@ -186,11 +186,7 @@ def log_test_failure_data(test, test_logpath, driver, browser, url=None):
data_to_save.append(
"--------------------------------------------------------------------"
)
- if (
- hasattr(test, "_outcome")
- and hasattr(test._outcome, "errors")
- and test._outcome.errors
- ):
+ if hasattr(test, "_outcome") and getattr(test._outcome, "errors", None):
try:
exc_message = test._outcome.errors[-1][1][1]
traceback_address = test._outcome.errors[-1][1][2]
@@ -225,12 +221,11 @@ def log_test_failure_data(test, test_logpath, driver, browser, url=None):
data_to_save.append("Exception: %s" % exc_message)
else:
traceback_message = None
- if hasattr(test, "is_behave") and test.is_behave:
+ if getattr(test, "is_behave", None):
if sb_config.behave_scenario.status.name == "failed":
if (
hasattr(sb_config, "behave_step")
- and hasattr(sb_config.behave_step, "error_message")
- and sb_config.behave_step.error_message
+ and getattr(sb_config.behave_step, "error_message", None)
):
traceback_message = sb_config.behave_step.error_message
else:
@@ -262,7 +257,7 @@ def log_test_failure_data(test, test_logpath, driver, browser, url=None):
)
else:
message = None
- if hasattr(test, "is_behave") and test.is_behave:
+ if getattr(test, "is_behave", None):
message = "Behave step was not implemented or skipped!"
else:
message = "Traceback not found!"
@@ -281,7 +276,7 @@ def log_test_failure_data(test, test_logpath, driver, browser, url=None):
data_to_save.append("Exception: %s" % sb_config._excinfo_value)
else:
data_to_save.append("Traceback:\n %s" % traceback_message)
- if hasattr(test, "is_nosetest") and test.is_nosetest:
+ if getattr(test, "is_nosetest", None):
# Also save the data for the report
sb_config._report_test_id = test_id
sb_config._report_fail_page = last_page
@@ -394,7 +389,7 @@ def log_page_source(test_logpath, driver, source=None):
def get_test_id(test):
- if hasattr(test, "is_behave") and test.is_behave:
+ if getattr(test, "is_behave", None):
file_name = sb_config.behave_scenario.filename
line_num = sb_config.behave_line_num
scenario_name = sb_config.behave_scenario.name
@@ -402,7 +397,7 @@ def get_test_id(test):
scenario_name = scenario_name.split(" -- @")[0]
test_id = "%s:%s => %s" % (file_name, line_num, scenario_name)
return test_id
- elif hasattr(test, "is_context_manager") and test.is_context_manager:
+ elif getattr(test, "is_context_manager", None):
filename = test.__class__.__module__.split(".")[-1] + ".py"
classname = test.__class__.__name__
methodname = test._testMethodName
@@ -412,7 +407,7 @@ def get_test_id(test):
stack_base = traceback.format_stack()[0].split(", in ")[0]
test_base = stack_base.split(", in ")[0].split(os.sep)[-1]
- if hasattr(test, "cm_filename") and test.cm_filename:
+ if getattr(test, "cm_filename", None):
filename = test.cm_filename
else:
filename = test_base.split('"')[0]
diff --git a/seleniumbase/core/mysql.py b/seleniumbase/core/mysql.py
index 88d91f65f0f..f51cf7a75fe 100644
--- a/seleniumbase/core/mysql.py
+++ b/seleniumbase/core/mysql.py
@@ -42,7 +42,7 @@ def __init__(self, database_env="test", conf_creds=None):
db_user = settings.DB_USERNAME
db_pass = settings.DB_PASSWORD
db_schema = settings.DB_SCHEMA
- if hasattr(sb_config, "settings_file") and sb_config.settings_file:
+ if getattr(sb_config, "settings_file", None):
override = settings_parser.set_settings(sb_config.settings_file)
if "DB_HOST" in override.keys():
db_server = override["DB_HOST"]
diff --git a/seleniumbase/core/report_helper.py b/seleniumbase/core/report_helper.py
index 51ddbf054b8..d408721a841 100644
--- a/seleniumbase/core/report_helper.py
+++ b/seleniumbase/core/report_helper.py
@@ -100,16 +100,12 @@ def process_failures(test, test_count, duration):
bad_page_image = "failure_%s.png" % test_count
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:
+ if getattr(test, "_last_page_screenshot", None):
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
- if (
- hasattr(test, "_outcome")
- and hasattr(test._outcome, "errors")
- and test._outcome.errors
- ):
+ if hasattr(test, "_outcome") and getattr(test._outcome, "errors", None):
try:
exc_message = test._outcome.errors[-1][1][1]
except Exception:
diff --git a/seleniumbase/core/sb_cdp.py b/seleniumbase/core/sb_cdp.py
index 4731559950d..66cedf1f29c 100644
--- a/seleniumbase/core/sb_cdp.py
+++ b/seleniumbase/core/sb_cdp.py
@@ -1149,7 +1149,42 @@ def open_new_tab(self, url=None, switch_to=True):
if not isinstance(url, str):
url = "about:blank"
if hasattr(driver, "cdp_base"):
- self.loop.run_until_complete(self.page.get(url, new_tab=True))
+ try:
+ self.loop.run_until_complete(self.page.get(url, new_tab=True))
+ except Exception:
+ original_targets = self.loop.run_until_complete(
+ self.page.send(mycdp.target.get_targets())
+ )
+ tab_url = driver.cdp_base.tabs[0].websocket_url
+ if not self.driver.is_connected():
+ self.driver.connect()
+ self.driver.open_new_tab()
+ targets = self.loop.run_until_complete(
+ self.page.send(mycdp.target.get_targets())
+ )
+ new_targets = []
+ for target in targets:
+ if target not in original_targets:
+ new_targets.append(target)
+ if new_targets:
+ found_target = new_targets[0]
+ t_str = str(new_targets[0])
+ target_id = (
+ t_str.split("target_id=TargetID('")[-1].split("')")[0]
+ )
+ pre_tab_url = tab_url.split("/page/")[0] + "/page/"
+ new_tab_url = pre_tab_url + target_id
+ new_tab = cdp_tab.Tab(
+ new_tab_url, found_target, driver.cdp_base
+ )
+ driver.cdp_base.targets.append(new_tab)
+ driver.cdp_base.tabs.append(new_tab)
+ self.driver.disconnect()
+ self.switch_to_newest_tab()
+ self.open(url)
+ return
+ elif getattr(sb_config, "guest_mode", None):
+ print(" open_new_tab() failed! (Known Guest Mode issue)")
if switch_to:
self.switch_to_newest_tab()
return
@@ -1157,14 +1192,17 @@ def open_new_tab(self, url=None, switch_to=True):
target_id = self.loop.run_until_complete(
self.page.send(mycdp.target.create_target(url))
)
+ if not target_id and getattr(sb_config, "guest_mode", None):
+ print(" open_new_tab() failed! (Known Guest Mode issue)")
found_target = None
targets = self.loop.run_until_complete(
self.page.send(mycdp.target.get_targets())
)
- for target in targets:
- if str(target_id) in str(target):
- found_target = target
- break
+ if target_id:
+ for target in targets:
+ if str(target_id) in str(target):
+ found_target = target
+ break
if found_target:
tab_url = driver.tabs[0].websocket_url
pre_tab_url = tab_url.split("/page/")[0] + "/page/"
@@ -1875,7 +1913,7 @@ def _on_a_cf_turnstile_page(self, source=None):
and 'title="reCAPTCHA"' not in source
and 'id="recaptcha-token"' not in source
)
- or "/challenge-platform/scripts/" in source
+ or "/challenge-platform/h/b/" in source
or 'id="challenge-widget-' in source
or "challenges.cloudf" in source
or "cf-turnstile-" in source
diff --git a/seleniumbase/core/session_helper.py b/seleniumbase/core/session_helper.py
index 886baa8c40a..3894beda18c 100644
--- a/seleniumbase/core/session_helper.py
+++ b/seleniumbase/core/session_helper.py
@@ -3,10 +3,8 @@
def end_reused_class_session_as_needed():
if (
- hasattr(sb_config, "reuse_class_session")
- and sb_config.reuse_class_session
- and hasattr(sb_config, "shared_driver")
- and sb_config.shared_driver
+ getattr(sb_config, "reuse_class_session", None)
+ and getattr(sb_config, "shared_driver", None)
):
if (
hasattr(sb_config.shared_driver, "service")
diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py
index 8e1a2852e54..30755c50a54 100644
--- a/seleniumbase/fixtures/base_case.py
+++ b/seleniumbase/fixtures/base_case.py
@@ -228,14 +228,9 @@ def open(self, url):
self.cdp.open(url)
return
elif (
- hasattr(self.driver, "_is_using_uc")
- and self.driver._is_using_uc
- # and hasattr(self.driver, "_is_using_auth")
- # and self.driver._is_using_auth
- and (
- not hasattr(self.driver, "_is_using_cdp")
- or not self.driver._is_using_cdp
- )
+ getattr(self.driver, "_is_using_uc", None)
+ # and getattr(self.driver, "_is_using_auth", None)
+ and not getattr(self.driver, "_is_using_cdp", None)
):
# Auth in UC Mode requires CDP Mode
# (and now we're always forcing it)
@@ -243,10 +238,8 @@ def open(self, url):
self.activate_cdp_mode(url)
return
elif (
- hasattr(self.driver, "_is_using_uc")
- and self.driver._is_using_uc
- and hasattr(self.driver, "_is_using_cdp")
- and self.driver._is_using_cdp
+ getattr(self.driver, "_is_using_uc", None)
+ and getattr(self.driver, "_is_using_cdp", None)
):
self.disconnect()
self.cdp.open(url)
@@ -1360,7 +1353,7 @@ def go_back(self):
if self.__is_cdp_swap_needed():
self.cdp.go_back()
return
- if hasattr(self, "recorder_mode") and self.recorder_mode:
+ if getattr(self, "recorder_mode", None):
self.save_recorded_actions()
pre_action_url = None
with suppress(Exception):
@@ -1388,7 +1381,7 @@ def go_forward(self):
if self.__is_cdp_swap_needed():
self.cdp.go_forward()
return
- if hasattr(self, "recorder_mode") and self.recorder_mode:
+ if getattr(self, "recorder_mode", None):
self.save_recorded_actions()
self.__last_page_load_url = None
self.driver.forward()
@@ -3979,10 +3972,8 @@ def open_new_window(self, switch_to=True):
self.cdp.open_new_tab(url=url, switch_to=switch_to)
return
elif (
- hasattr(self.driver, "_is_using_uc")
- and self.driver._is_using_uc
- and hasattr(self.driver, "_is_using_cdp")
- and self.driver._is_using_cdp
+ getattr(self.driver, "_is_using_uc", None)
+ and getattr(self.driver, "_is_using_cdp", None)
):
self.disconnect()
self.cdp.open_new_tab(url=url, switch_to=switch_to)
@@ -4895,7 +4886,7 @@ def add_cookies(self, cookies, expiry=False):
self.driver.add_cookie(cookie)
def __set_esc_skip(self):
- if hasattr(self, "esc_end") and self.esc_end:
+ if getattr(self, "esc_end", None):
script = (
"""document.onkeydown = function(evt) {
evt = evt || window.event;
@@ -4913,7 +4904,7 @@ def __set_esc_skip(self):
self.execute_script(script)
def __skip_if_esc(self):
- if hasattr(self, "esc_end") and self.esc_end:
+ if getattr(self, "esc_end", None):
if self.execute_script("return document.sb_esc_end;") == "yes":
self.skip()
@@ -4935,8 +4926,7 @@ def wait_for_ready_state_complete(self, timeout=None):
self.__disable_beforeunload_as_needed()
if (
self.page_load_strategy == "none"
- and hasattr(settings, "SKIP_JS_WAITS")
- and settings.SKIP_JS_WAITS
+ and getattr(settings, "SKIP_JS_WAITS", None)
):
time.sleep(0.01)
if self.undetectable:
@@ -4957,10 +4947,7 @@ def wait_for_angularjs(self, timeout=None, **kwargs):
def sleep(self, seconds):
self.__check_scope()
- if (
- not hasattr(sb_config, "time_limit")
- or (hasattr(sb_config, "time_limit") and not sb_config.time_limit)
- ):
+ if not getattr(sb_config, "time_limit", None):
time.sleep(seconds)
elif seconds < 0.4:
shared_utils.check_if_time_limit_exceeded()
@@ -4975,11 +4962,7 @@ def sleep(self, seconds):
if now_ms >= stop_ms:
break
time.sleep(0.2)
- if (
- self.recorder_mode
- and hasattr(sb_config, "record_sleep")
- and sb_config.record_sleep
- ):
+ if self.recorder_mode and getattr(sb_config, "record_sleep", None):
time_stamp = self.execute_script("return Date.now();")
origin = self.get_origin()
action = ["sleep", seconds, origin, time_stamp]
@@ -5037,7 +5020,7 @@ def deactivate_design_mode(self, url=None):
def activate_cdp_mode(self, url=None, **kwargs):
"""Activate CDP Mode with the URL and kwargs."""
- if hasattr(self.driver, "_is_using_uc") and self.driver._is_using_uc:
+ if getattr(self.driver, "_is_using_uc", None):
if self.__is_cdp_swap_needed():
return # CDP Mode is already active
if not self.is_connected():
@@ -5054,10 +5037,7 @@ def activate_cdp_mode(self, url=None, **kwargs):
self.solve_captcha = self.cdp.solve_captcha
if hasattr(self.cdp, "find_element_by_text"):
self.find_element_by_text = self.cdp.find_element_by_text
- if (
- hasattr(self.driver, "_is_using_auth")
- and self.driver._is_using_auth
- ):
+ if getattr(self.driver, "_is_using_auth", None):
with suppress(Exception):
self.cdp.loop.run_until_complete(self.cdp.page.wait(0.25))
self.undetectable = True
@@ -5709,14 +5689,13 @@ def __process_recorded_actions(self):
methodname = self._testMethodName
context_filename = None
if (
- hasattr(sb_config, "is_context_manager")
- and sb_config.is_context_manager
+ getattr(sb_config, "is_context_manager", None)
and (filename == "base_case.py" or methodname == "runTest")
):
import traceback
stack_base = traceback.format_stack()[0].split(os.sep)[-1]
test_base = stack_base.split(", in ")[0]
- if hasattr(self, "cm_filename") and self.cm_filename:
+ if getattr(self, "cm_filename", None):
filename = self.cm_filename
else:
filename = test_base.split('"')[0]
@@ -5733,7 +5712,7 @@ def __process_recorded_actions(self):
classname = "MyTestClass"
methodname = methodname.replace("[", "__").replace("]", "")
methodname = re.sub(r"[\W]", "_", methodname)
- if hasattr(self, "is_behave") and self.is_behave:
+ if getattr(self, "is_behave", None):
classname = sb_config.behave_feature.name
classname = classname.replace("/", " ").replace(" & ", " ")
classname = re.sub(r"[^\w" + r"_ " + r"]", "", classname)
@@ -5881,7 +5860,7 @@ def __process_recorded_actions(self):
test_id = sb_config._test_id
file_name = test_id.split("::")[0].split("/")[-1].split("\\")[-1]
file_name = file_name.split(".py")[0] + "_rec.py"
- if hasattr(self, "is_behave") and self.is_behave:
+ if getattr(self, "is_behave", None):
file_name = sb_config.behave_scenario.filename.replace(".", "_")
file_name = file_name.split("/")[-1].split("\\")[-1] + "_rec.py"
file_name = file_name
@@ -5900,7 +5879,7 @@ def __process_recorded_actions(self):
if terminal_size > 30 and star_len > terminal_size:
star_len = terminal_size
spc = "\n\n"
- if hasattr(self, "rec_print") and self.rec_print:
+ if getattr(self, "rec_print", None):
spc = ""
sys.stdout.write("\nCreated recordings%s%s" % (os.sep, file_name))
print()
@@ -5921,7 +5900,7 @@ def __process_recorded_actions(self):
rec_message = rec_message.replace(">>>", c2 + ">>>" + cr)
print("%s%s%s%s%s\n%s" % (spc, rec_message, c1, file_path, cr, stars))
- if hasattr(self, "rec_behave") and self.rec_behave:
+ if getattr(self, "rec_behave", None):
# Also generate necessary behave-gherkin files.
self.__process_recorded_behave_actions(srt_actions, colorama)
@@ -5932,7 +5911,7 @@ def __process_recorded_behave_actions(self, srt_actions, colorama):
filename = self.__get_filename()
feature_class = None
scenario_test = None
- if hasattr(self, "is_behave") and self.is_behave:
+ if getattr(self, "is_behave", None):
feature_class = sb_config.behave_feature.name
scenario_test = sb_config.behave_scenario.name
else:
@@ -5986,7 +5965,7 @@ def __process_recorded_behave_actions(self, srt_actions, colorama):
os.makedirs(steps_folder)
file_name = filename.split(".")[0]
- if hasattr(self, "is_behave") and self.is_behave:
+ if getattr(self, "is_behave", None):
file_name = sb_config.behave_scenario.filename.replace(".", "_")
file_name = file_name.split("/")[-1].split("\\")[-1] + "_rec.feature"
file_path = os.path.join(features_folder, file_name)
@@ -6003,7 +5982,7 @@ def __process_recorded_behave_actions(self, srt_actions, colorama):
if terminal_size > 30 and star_len > terminal_size:
star_len = terminal_size
spc = "\n"
- if hasattr(self, "rec_print") and self.rec_print:
+ if getattr(self, "rec_print", None):
spc = ""
print()
if " " not in file_path:
@@ -9021,7 +9000,7 @@ def skip(self, reason=""):
self.__passed_then_skipped = True
self.__will_be_skipped = True
sb_config._results[test_id] = "Skipped"
- if hasattr(self, "with_db_reporting") and self.with_db_reporting:
+ if getattr(self, "with_db_reporting", None):
if self.is_pytest:
self.__skip_reason = reason
else:
@@ -9718,7 +9697,7 @@ def _print(self, msg):
To force a print during multithreaded tests, use: "sys.stderr.write()".
To print without the new-line character end, use: "sys.stdout.write()".
"""
- if hasattr(sb_config, "_multithreaded") and sb_config._multithreaded:
+ if getattr(sb_config, "_multithreaded", None):
if not isinstance(msg, str):
with suppress(Exception):
msg = str(msg)
@@ -13940,7 +13919,7 @@ def __js_click(self, selector, by="css selector"):
simulateClick(someLink);"""
% css_selector
)
- if hasattr(self, "recorder_mode") and self.recorder_mode:
+ if getattr(self, "recorder_mode", None):
self.save_recorded_actions()
try:
self.execute_script(script)
@@ -13988,7 +13967,7 @@ def __js_click_element(self, element):
var someLink = arguments[0];
simulateClick(someLink);"""
)
- if hasattr(self, "recorder_mode") and self.recorder_mode:
+ if getattr(self, "recorder_mode", None):
self.save_recorded_actions()
try:
self.execute_script(script, element)
@@ -14195,7 +14174,7 @@ def __jquery_click(self, selector, by="css selector"):
selector = self.convert_to_css_selector(selector, by=by)
selector = self.__make_css_match_first_element_only(selector)
click_script = """jQuery('%s')[0].click();""" % selector
- if hasattr(self, "recorder_mode") and self.recorder_mode:
+ if getattr(self, "recorder_mode", None):
self.save_recorded_actions()
self.safe_execute_script(click_script)
@@ -14351,8 +14330,7 @@ def __switch_to_newest_window_if_not_blank(self):
def __needs_minimum_wait(self):
if (
self.page_load_strategy == "none"
- and hasattr(settings, "SKIP_JS_WAITS")
- and settings.SKIP_JS_WAITS
+ and getattr(settings, "SKIP_JS_WAITS", None)
):
return True
else:
@@ -14684,10 +14662,7 @@ def __ad_block_as_needed(self):
def __disable_beforeunload_as_needed(self):
"""Disables beforeunload as needed. Also resets frame_switch state."""
- if (
- hasattr(self, "_disable_beforeunload")
- and self._disable_beforeunload
- ):
+ if getattr(self, "_disable_beforeunload", None):
self.disable_beforeunload()
if self.recorder_mode:
try:
@@ -15488,9 +15463,9 @@ def setUp(self, masterqa_mode=False):
self.__skip_reason = None
self.testcase_manager.insert_testcase_data(data_payload)
self.case_start_time = int(time.time() * 1000.0)
- elif hasattr(self, "is_behave") and self.is_behave:
+ elif getattr(self, "is_behave", None):
self.__initialize_variables()
- elif hasattr(self, "is_nosetest") and self.is_nosetest:
+ elif getattr(self, "is_nosetest", None):
pass # Setup performed in plugins for pynose
else:
# Pure Python run. (Eg. SB() and Driver() Managers)
@@ -15682,7 +15657,7 @@ def setUp(self, masterqa_mode=False):
)
raise Exception(message)
- if not hasattr(self, "is_nosetest") or not self.is_nosetest:
+ if not getattr(self, "is_nosetest", None):
# Xvfb Virtual Display activation for Linux
self.__activate_virtual_display_as_needed()
@@ -15858,10 +15833,7 @@ def __set_last_page_screenshot(self):
self.__last_page_screenshot_png is for all screenshot log files."""
SCREENSHOT_SKIPPED = constants.Warnings.SCREENSHOT_SKIPPED
SCREENSHOT_UNDEFINED = constants.Warnings.SCREENSHOT_UNDEFINED
- if (
- hasattr(self, "no_screenshot_after_test")
- and self.no_screenshot_after_test
- ):
+ if getattr(self, "no_screenshot_after_test", None):
from seleniumbase.core import encoded_images
NO_SCREENSHOT = encoded_images.get_no_screenshot_png()
@@ -15892,10 +15864,7 @@ def __set_last_page_screenshot(self):
ignore_test_time_limit=True,
)
try:
- if (
- hasattr(settings, "SCREENSHOT_WITH_BACKGROUND")
- and settings.SCREENSHOT_WITH_BACKGROUND
- ):
+ if getattr(settings, "SCREENSHOT_WITH_BACKGROUND", None):
self.__last_page_screenshot = (
self.driver.get_screenshot_as_base64()
)
@@ -15966,8 +15935,7 @@ def __get_exception_info(self):
exc_message = None
if (
hasattr(self, "_outcome")
- and hasattr(self._outcome, "errors")
- and self._outcome.errors
+ and getattr(self._outcome, "errors", None)
):
try:
exc_message = self._outcome.errors[-1][1][1]
@@ -16055,8 +16023,7 @@ def __add_pytest_html_extra(self):
def __delay_driver_quit(self):
delay_driver_quit = False
if (
- hasattr(self, "_using_sb_fixture")
- and self._using_sb_fixture
+ getattr(self, "_using_sb_fixture", None)
and "--pdb" in sys.argv
and self.__has_exception()
and len(self._drivers_list) == 1
@@ -16112,7 +16079,7 @@ def __has_exception(self):
has_exception = False
if hasattr(sys, "last_traceback") and sys.last_traceback is not None:
has_exception = True
- elif hasattr(self, "is_context_manager") and self.is_context_manager:
+ elif getattr(self, "is_context_manager", None):
if self.with_testing_base and self._has_failure:
return True
else:
@@ -16136,7 +16103,7 @@ def __has_exception(self):
def __get_test_id(self):
"""The id used in various places such as the test log path."""
- if hasattr(self, "is_behave") and self.is_behave:
+ if getattr(self, "is_behave", None):
file_name = sb_config.behave_scenario.filename
file_name = file_name.replace("/", ".").replace("\\", ".")
scenario_name = sb_config.behave_scenario.name
@@ -16146,7 +16113,7 @@ def __get_test_id(self):
scenario_name = scenario_name.replace(" ", "_")
test_id = "%s.%s" % (file_name, scenario_name)
return test_id
- elif hasattr(self, "is_context_manager") and self.is_context_manager:
+ elif getattr(self, "is_context_manager", None):
if hasattr(self, "_manager_saved_id"):
self.__saved_id = self._manager_saved_id
if self.__saved_id:
@@ -16158,7 +16125,7 @@ def __get_test_id(self):
import traceback
stack_base = traceback.format_stack()[0].split(os.sep)[-1]
test_base = stack_base.split(", in ")[0]
- if hasattr(self, "cm_filename") and self.cm_filename:
+ if getattr(self, "cm_filename", None):
filename = self.cm_filename
else:
filename = test_base.split('"')[0]
@@ -16173,7 +16140,7 @@ def __get_test_id(self):
)
if self._sb_test_identifier and len(str(self._sb_test_identifier)) > 6:
test_id = self._sb_test_identifier
- elif hasattr(self, "_using_sb_fixture") and self._using_sb_fixture:
+ elif getattr(self, "_using_sb_fixture", None):
test_id = sb_config._latest_display_id
test_id = test_id.replace(".py::", ".").replace("::", ".")
test_id = test_id.replace("/", ".").replace("\\", ".")
@@ -16195,7 +16162,7 @@ def __get_test_id_2(self):
return full_name.split("] ")[0] + "]"
else:
return full_name.split(" ")[0]
- if hasattr(self, "is_behave") and self.is_behave:
+ if getattr(self, "is_behave", None):
return self.__get_test_id()
test_id = "%s.%s.%s" % (
self.__class__.__module__.split(".")[-1],
@@ -16216,7 +16183,7 @@ def __get_display_id(self):
return full_name.split("] ")[0] + "]"
else:
return full_name.split(" ")[0]
- if hasattr(self, "is_behave") and self.is_behave:
+ if getattr(self, "is_behave", None):
file_name = sb_config.behave_scenario.filename
line_num = sb_config.behave_line_num
scenario_name = sb_config.behave_scenario.name
@@ -16249,7 +16216,7 @@ def __get_filename(self):
if "PYTEST_CURRENT_TEST" in os.environ:
test_id = os.environ["PYTEST_CURRENT_TEST"].split(" ")[0]
filename = test_id.split("::")[0].split("/")[-1]
- elif hasattr(self, "is_behave") and self.is_behave:
+ elif getattr(self, "is_behave", None):
filename = sb_config.behave_scenario.filename
filename = filename.split("/")[-1].split("\\")[-1]
else:
@@ -16285,8 +16252,7 @@ def __process_dashboard(self, has_exception, init=False):
sb_config._pdb_failure = True
elif (
self.is_pytest
- and hasattr(sb_config, "_pdb_failure")
- and sb_config._pdb_failure
+ and getattr(sb_config, "_pdb_failure", None)
and not has_exception
):
return # Handle case where "pytest --pdb" marks failures as Passed
@@ -16680,7 +16646,7 @@ def save_teardown_screenshot(self):
self.__check_scope()
except Exception:
return
- if hasattr(self, "recorder_mode") and self.recorder_mode:
+ if getattr(self, "recorder_mode", None):
# In case tearDown() leaves the origin, save actions first.
self.save_recorded_actions()
if (
@@ -16875,7 +16841,7 @@ def tearDown(self):
if not hasattr(self, "_using_sb_fixture") and self.__called_teardown:
# This test already called tearDown()
return
- if hasattr(self, "recorder_mode") and self.recorder_mode:
+ if getattr(self, "recorder_mode", None):
page_actions._reconnect_if_disconnected(self.driver)
try:
self.__process_recorded_actions()
@@ -17110,7 +17076,7 @@ def tearDown(self):
self.testcase_manager.update_testcase_log_url(data_payload)
else:
# (Pynose / Behave / Pure Python)
- if hasattr(self, "is_behave") and self.is_behave:
+ if getattr(self, "is_behave", None):
if sb_config.behave_scenario.status.name == "failed":
has_exception = True
sb_config._has_exception = True
@@ -17170,8 +17136,8 @@ def tearDown(self):
self._last_page_url = self.get_current_url()
except Exception:
self._last_page_url = "(Error: Unknown URL)"
- if hasattr(self, "is_behave") and self.is_behave and has_exception:
- if hasattr(sb_config, "pdb_option") and sb_config.pdb_option:
+ if getattr(self, "is_behave", None) and has_exception:
+ if getattr(sb_config, "pdb_option", None):
if (
hasattr(sb_config, "behave_step")
and hasattr(sb_config.behave_step, "exc_traceback")
@@ -17179,24 +17145,14 @@ def tearDown(self):
self.__activate_behave_post_mortem_debug_mode()
if self._final_debug:
self.__activate_debug_mode_in_teardown()
- elif (
- hasattr(sb_config, "_do_sb_post_mortem")
- and sb_config._do_sb_post_mortem
- ):
+ elif getattr(sb_config, "_do_sb_post_mortem", None):
self.__activate_sb_mgr_post_mortem_debug_mode()
- elif (
- hasattr(sb_config, "_do_sb_final_trace")
- and sb_config._do_sb_final_trace
- ):
+ elif getattr(sb_config, "_do_sb_final_trace", None):
self.__activate_debug_mode_in_teardown()
# (Pynose / Behave / Pure Python) Close all open browser windows
self.__quit_all_drivers()
# Resume tearDown() for all test runners, (Pytest / Pynose / Behave)
- if (
- hasattr(self, "_xvfb_display")
- and self._xvfb_display
- and not self._reuse_session
- ):
+ if getattr(self, "_xvfb_display", None) and not self._reuse_session:
# Stop the Xvfb virtual display launched from BaseCase
try:
if hasattr(self._xvfb_display, "stop"):
@@ -17208,16 +17164,9 @@ def tearDown(self):
except Exception:
pass
if (
- hasattr(sb_config, "_virtual_display")
- and sb_config._virtual_display
+ getattr(sb_config, "_virtual_display", None)
and hasattr(sb_config._virtual_display, "stop")
- and (
- not hasattr(sb_config, "reuse_session")
- or (
- hasattr(sb_config, "reuse_session")
- and not sb_config.reuse_session
- )
- )
+ and not getattr(sb_config, "reuse_session", None)
):
# CDP Mode may launch a 2nd Xvfb virtual display
try:
diff --git a/seleniumbase/fixtures/js_utils.py b/seleniumbase/fixtures/js_utils.py
index aa11c40a2c3..0728f2dbd91 100644
--- a/seleniumbase/fixtures/js_utils.py
+++ b/seleniumbase/fixtures/js_utils.py
@@ -31,7 +31,7 @@ def wait_for_ready_state_complete(driver, timeout=settings.LARGE_TIMEOUT):
(Previously, tests would fail immediately if exceeding the timeout.)"""
if hasattr(driver, "_swap_driver"):
return
- if hasattr(settings, "SKIP_JS_WAITS") and settings.SKIP_JS_WAITS:
+ if getattr(settings, "SKIP_JS_WAITS", None):
return
start_ms = time.time() * 1000.0
stop_ms = start_ms + (timeout * 1000.0)
@@ -65,13 +65,13 @@ def execute_async_script(driver, script, timeout=settings.LARGE_TIMEOUT):
def wait_for_angularjs(driver, timeout=settings.LARGE_TIMEOUT, **kwargs):
- if hasattr(settings, "SKIP_JS_WAITS") and settings.SKIP_JS_WAITS:
+ if getattr(settings, "SKIP_JS_WAITS", None):
return
with suppress(Exception):
# This closes pop-up alerts
execute_script(driver, "")
if (
- (hasattr(driver, "_is_using_uc") and driver._is_using_uc)
+ getattr(driver, "_is_using_uc", None)
or not settings.WAIT_FOR_ANGULARJS
):
wait_for_ready_state_complete(driver)
@@ -874,7 +874,7 @@ def set_messenger_theme(
theme = "future"
if location == "default":
location = "bottom_right"
- if hasattr(sb_config, "mobile_emulator") and sb_config.mobile_emulator:
+ if getattr(sb_config, "mobile_emulator", None):
location = "top_center"
if max_messages == "default":
max_messages = "8"
@@ -978,7 +978,7 @@ def post_messenger_success_message(driver, message, msg_dur=None):
with suppress(Exception):
theme = "future"
location = "bottom_right"
- if hasattr(sb_config, "mobile_emulator") and sb_config.mobile_emulator:
+ if getattr(sb_config, "mobile_emulator", None):
location = "top_right"
set_messenger_theme(driver, theme=theme, location=location)
post_message(driver, message, msg_dur, style="success")
diff --git a/seleniumbase/fixtures/page_actions.py b/seleniumbase/fixtures/page_actions.py
index dd3606d8d50..25632c1732b 100644
--- a/seleniumbase/fixtures/page_actions.py
+++ b/seleniumbase/fixtures/page_actions.py
@@ -1646,11 +1646,7 @@ def switch_to_frame(
def __switch_to_window(driver, window_handle, uc_lock=True):
- if (
- hasattr(driver, "_is_using_uc")
- and driver._is_using_uc
- and uc_lock
- ):
+ if getattr(driver, "_is_using_uc", None) and uc_lock:
gui_lock = FileLock(constants.MultiBrowser.PYAUTOGUILOCK)
with gui_lock:
driver.switch_to.window(window_handle)
@@ -1734,8 +1730,7 @@ def switch_to_window(
def _reconnect_if_disconnected(driver):
if (
- hasattr(driver, "_is_using_uc")
- and driver._is_using_uc
+ getattr(driver, "_is_using_uc", None)
and hasattr(driver, "is_connected")
and not driver.is_connected()
):
@@ -1757,24 +1752,17 @@ def open_url(driver, url):
driver.cdp.open(url)
return
elif (
- hasattr(driver, "_is_using_uc")
- and driver._is_using_uc
- # and hasattr(driver, "_is_using_auth")
- # and driver._is_using_auth
- and (
- not hasattr(driver, "_is_using_cdp")
- or not driver._is_using_cdp
- )
+ getattr(driver, "_is_using_uc", None)
+ # and getattr(driver, "_is_using_auth", None)
+ and not getattr(driver, "_is_using_cdp", None)
):
# Auth in UC Mode requires CDP Mode
# (and now we're always forcing it)
driver.uc_activate_cdp_mode(url)
return
elif (
- hasattr(driver, "_is_using_uc")
- and driver._is_using_uc
- and hasattr(driver, "_is_using_cdp")
- and driver._is_using_cdp
+ getattr(driver, "_is_using_uc", None)
+ and getattr(driver, "_is_using_cdp", None)
):
driver.disconnect()
driver.cdp.open(url)
diff --git a/seleniumbase/fixtures/shared_utils.py b/seleniumbase/fixtures/shared_utils.py
index 908c226688c..9cf42887338 100644
--- a/seleniumbase/fixtures/shared_utils.py
+++ b/seleniumbase/fixtures/shared_utils.py
@@ -147,8 +147,7 @@ def fix_url_as_needed(url):
def reconnect_if_disconnected(driver):
if (
- hasattr(driver, "_is_using_uc")
- and driver._is_using_uc
+ getattr(driver, "_is_using_uc", None)
and hasattr(driver, "is_connected")
and not driver.is_connected()
):
@@ -298,8 +297,7 @@ def __time_limit_exceeded(message):
def check_if_time_limit_exceeded():
if (
- hasattr(sb_config, "time_limit")
- and sb_config.time_limit
+ getattr(sb_config, "time_limit", None)
and not sb_config.recorder_mode
):
time_limit = sb_config.time_limit
diff --git a/seleniumbase/plugins/pytest_plugin.py b/seleniumbase/plugins/pytest_plugin.py
index e120ea951a4..e3721b7f511 100644
--- a/seleniumbase/plugins/pytest_plugin.py
+++ b/seleniumbase/plugins/pytest_plugin.py
@@ -1729,7 +1729,7 @@ def pytest_configure(config):
sb_config.extension_dir = config.getoption("extension_dir")
sb_config.disable_features = config.getoption("disable_features")
sb_config.binary_location = config.getoption("binary_location")
- if hasattr(sb_config, "_cdp_bin_loc") and sb_config._cdp_bin_loc:
+ if getattr(sb_config, "_cdp_bin_loc", None):
sb_config.binary_location = sb_config._cdp_bin_loc
elif not sb_config.binary_location:
if (
@@ -2187,16 +2187,12 @@ def pytest_runtest_teardown(item):
self = item._testcase
with suppress(Exception):
if (
- hasattr(self, "driver")
- and self.driver
+ getattr(self, "driver", None)
and "--pdb" not in sys_argv
):
if not (is_windows or self.driver.service.process):
self.driver.quit()
- elif (
- hasattr(sb_config, "_sb_pdb_driver")
- and sb_config._sb_pdb_driver
- ):
+ elif getattr(sb_config, "_sb_pdb_driver", None):
with suppress(Exception):
if (
not is_windows
@@ -2206,32 +2202,18 @@ def pytest_runtest_teardown(item):
sb_config._sb_pdb_driver = None
with suppress(Exception):
if (
- hasattr(self, "_xvfb_display")
- and self._xvfb_display
+ getattr(self, "_xvfb_display", None)
and hasattr(self._xvfb_display, "stop")
- and (
- not hasattr(sb_config, "reuse_session")
- or (
- hasattr(sb_config, "reuse_session")
- and not sb_config.reuse_session
- )
- )
+ and not getattr(sb_config, "reuse_session", None)
):
self.headless_active = False
sb_config.headless_active = False
self._xvfb_display.stop()
self._xvfb_display = None
if (
- hasattr(sb_config, "_virtual_display")
- and sb_config._virtual_display
+ getattr(sb_config, "_virtual_display", None)
and hasattr(sb_config._virtual_display, "stop")
- and (
- not hasattr(sb_config, "reuse_session")
- or (
- hasattr(sb_config, "reuse_session")
- and not sb_config.reuse_session
- )
- )
+ and not getattr(sb_config, "reuse_session", None)
):
sb_config._virtual_display.stop()
sb_config._virtual_display = None
@@ -2330,12 +2312,9 @@ def _perform_pytest_unconfigure_(config):
else:
start_time = reporter._session_start.time # (pytest >= 8.4.0)
duration = time.time() - start_time
- if (
- (hasattr(sb_config, "multi_proxy") and not sb_config.multi_proxy)
- or not hasattr(sb_config, "multi_proxy")
- ):
+ if not getattr(sb_config, "multi_proxy", None):
proxy_helper.remove_proxy_zip_if_present()
- if hasattr(sb_config, "reuse_session") and sb_config.reuse_session:
+ if getattr(sb_config, "reuse_session", None):
# Close the shared browser session
if sb_config.shared_driver:
try:
@@ -2352,14 +2331,13 @@ def _perform_pytest_unconfigure_(config):
sb_config.shared_driver = None
with suppress(Exception):
if (
- hasattr(sb_config, "_virtual_display")
- and sb_config._virtual_display
+ getattr(sb_config, "_virtual_display", None)
and hasattr(sb_config._virtual_display, "stop")
):
sb_config._virtual_display.stop()
sb_config._virtual_display = None
sb_config.headless_active = False
- if hasattr(sb_config, "_vd_list") and sb_config._vd_list:
+ if getattr(sb_config, "_vd_list", None):
if isinstance(sb_config._vd_list, list):
for display in sb_config._vd_list:
if display:
@@ -2374,7 +2352,7 @@ def _perform_pytest_unconfigure_(config):
shared_utils.make_dir_files_writable("./assets/")
log_helper.clear_empty_logs()
# Dashboard post-processing: Disable time-based refresh and stamp complete
- if not hasattr(sb_config, "dashboard") or not sb_config.dashboard:
+ if not getattr(sb_config, "dashboard", None):
html_report_path = None
the_html_r = None
abs_path = os.path.abspath(".")
@@ -2679,11 +2657,11 @@ def pytest_unconfigure(config):
)
):
return
- if hasattr(sb_config, "_multithreaded") and sb_config._multithreaded:
+ if getattr(sb_config, "_multithreaded", None):
import fasteners
dash_lock = fasteners.InterProcessLock(constants.Dashboard.LOCKFILE)
- if hasattr(sb_config, "dashboard") and sb_config.dashboard:
+ if getattr(sb_config, "dashboard", None):
# Multi-threaded tests with the Dashboard
abs_path = os.path.abspath(".")
dash_lock_file = constants.Dashboard.LOCKFILE
diff --git a/seleniumbase/plugins/selenium_plugin.py b/seleniumbase/plugins/selenium_plugin.py
index 0c6a48b4825..42733e1aa56 100644
--- a/seleniumbase/plugins/selenium_plugin.py
+++ b/seleniumbase/plugins/selenium_plugin.py
@@ -1338,7 +1338,7 @@ def beforeTest(self, test):
test.test.extension_dir = self.options.extension_dir
test.test.disable_features = self.options.disable_features
test.test.binary_location = self.options.binary_location
- if hasattr(sb_config, "_cdp_bin_loc") and sb_config._cdp_bin_loc:
+ if getattr(sb_config, "_cdp_bin_loc", None):
test.test.binary_location = sb_config._cdp_bin_loc
if self.options.use_cft and not test.test.binary_location:
test.test.binary_location = "cft"
@@ -1515,10 +1515,7 @@ def beforeTest(self, test):
def finalize(self, result):
"""This runs after all tests have completed with nosetests."""
- if (
- (hasattr(sb_config, "multi_proxy") and not sb_config.multi_proxy)
- or not hasattr(sb_config, "multi_proxy")
- ):
+ if not getattr(sb_config, "multi_proxy", None):
proxy_helper.remove_proxy_zip_if_present()
def afterTest(self, test):
@@ -1536,8 +1533,7 @@ def afterTest(self, test):
pass
with suppress(Exception):
if (
- hasattr(self, "_xvfb_display")
- and self._xvfb_display
+ getattr(self, "_xvfb_display", None)
and hasattr(self._xvfb_display, "stop")
):
self.headless_active = False
@@ -1545,8 +1541,7 @@ def afterTest(self, test):
self._xvfb_display.stop()
self._xvfb_display = None
if (
- hasattr(sb_config, "_virtual_display")
- and sb_config._virtual_display
+ getattr(sb_config, "_virtual_display", None)
and hasattr(sb_config._virtual_display, "stop")
):
sb_config._virtual_display.stop()
diff --git a/seleniumbase/undetected/__init__.py b/seleniumbase/undetected/__init__.py
index faaea62c5dc..6945bb846d7 100644
--- a/seleniumbase/undetected/__init__.py
+++ b/seleniumbase/undetected/__init__.py
@@ -163,7 +163,7 @@ def __init__(
from seleniumbase import config as sb_config
if (
(("-n" in sys.argv) or (" -n=" in arg_join) or ("-c" in sys.argv))
- or (hasattr(sb_config, "multi_proxy") and sb_config.multi_proxy)
+ or getattr(sb_config, "multi_proxy", None)
or not special_port_free
):
debug_port = selenium.webdriver.common.service.utils.free_port()
@@ -197,9 +197,7 @@ def __init__(
except IndexError:
pass
if not user_data_dir:
- if hasattr(options, "user_data_dir") and getattr(
- options, "user_data_dir", None
- ):
+ if getattr(options, "user_data_dir", None):
options.add_argument(
"--user-data-dir=%s" % options.user_data_dir
)
@@ -405,9 +403,7 @@ def get(self, url):
def add_cdp_listener(self, event_name, callback):
if (
- hasattr(self, "reactor")
- and self.reactor
- and self.reactor is not None
+ getattr(self, "reactor", None)
and isinstance(self.reactor, Reactor)
):
self.reactor.add_event_handler(event_name, callback)
@@ -416,8 +412,7 @@ def add_cdp_listener(self, event_name, callback):
def clear_cdp_listeners(self):
if (
- hasattr(self, "reactor")
- and self.reactor
+ getattr(self, "reactor", None)
and isinstance(self.reactor, Reactor)
):
self.reactor.handlers.clear()
@@ -526,7 +521,13 @@ def connect(self):
with suppress(Exception):
for window_handle in self.window_handles:
self.switch_to.window(window_handle)
- if self.current_url.startswith("chrome-extension://"):
+ current_url = None
+ if hasattr(self, "cdp") and hasattr(self.cdp, "driver"):
+ with suppress(Exception):
+ current_url = self.cdp.get_current_url()
+ if not current_url:
+ current_url = self.current_url
+ if current_url.startswith("chrome-extension://"):
# https://issues.chromium.org/issues/396611138
# (Remove the Linux conditional when resolved)
# (So that close() is always called)
diff --git a/seleniumbase/undetected/cdp_driver/browser.py b/seleniumbase/undetected/cdp_driver/browser.py
index bb4d49e161f..03768228bc6 100644
--- a/seleniumbase/undetected/cdp_driver/browser.py
+++ b/seleniumbase/undetected/cdp_driver/browser.py
@@ -329,28 +329,17 @@ async def get(
_cdp_geolocation = None
_cdp_recorder = None
_cdp_ad_block = None
- if (
- hasattr(sb_config, "_cdp_timezone") and sb_config._cdp_timezone
- ):
+ if getattr(sb_config, "_cdp_timezone", None):
_cdp_timezone = sb_config._cdp_timezone
- if (
- hasattr(sb_config, "_cdp_user_agent")
- and sb_config._cdp_user_agent
- ):
+ if getattr(sb_config, "_cdp_user_agent", None):
_cdp_user_agent = sb_config._cdp_user_agent
- if hasattr(sb_config, "_cdp_locale") and sb_config._cdp_locale:
+ if getattr(sb_config, "_cdp_locale", None):
_cdp_locale = sb_config._cdp_locale
- if hasattr(sb_config, "_cdp_platform") and sb_config._cdp_platform:
+ if getattr(sb_config, "_cdp_platform", None):
_cdp_platform = sb_config._cdp_platform
- if (
- hasattr(sb_config, "_cdp_geolocation")
- and sb_config._cdp_geolocation
- ):
+ if getattr(sb_config, "_cdp_geolocation", None):
_cdp_geolocation = sb_config._cdp_geolocation
- if (
- hasattr(sb_config, "ad_block_on")
- and sb_config.ad_block_on
- ):
+ if getattr(sb_config, "ad_block_on", None):
_cdp_ad_block = sb_config.ad_block_on
if "timezone" in kwargs:
_cdp_timezone = kwargs["timezone"]
@@ -435,8 +424,7 @@ async def get(
await connection.send(cdp.page.set_bypass_csp(enabled=True))
# (The code below is for the Chrome 142 extension fix)
if (
- hasattr(sb_config, "_cdp_proxy")
- and sb_config._cdp_proxy
+ getattr(sb_config, "_cdp_proxy", None)
and "@" in sb_config._cdp_proxy
and "auth" not in kwargs
):
@@ -592,7 +580,7 @@ async def start(self=None) -> Browser:
break
if not self.info:
chromium = "Chromium"
- if hasattr(sb_config, "_cdp_browser") and sb_config._cdp_browser:
+ if getattr(sb_config, "_cdp_browser", None):
chromium = sb_config._cdp_browser
chromium = chromium[0].upper() + chromium[1:]
message = "Failed to connect to the browser"
@@ -910,7 +898,7 @@ async def get_all(
"""
connection = None
for _tab in self._browser.tabs:
- if hasattr(_tab, "closed") and _tab.closed:
+ if getattr(_tab, "closed", None):
continue
connection = _tab
break
@@ -940,7 +928,7 @@ async def set_all(self, cookies: List[cdp.network.CookieParam]):
"""
connection = None
for _tab in self._browser.tabs:
- if hasattr(_tab, "closed") and _tab.closed:
+ if getattr(_tab, "closed", None):
continue
connection = _tab
break
@@ -967,7 +955,7 @@ async def save(self, file: PathLike = ".session.dat", pattern: str = ".*"):
save_path = pathlib.Path(file).resolve()
connection = None
for _tab in self._browser.tabs:
- if hasattr(_tab, "closed") and _tab.closed:
+ if getattr(_tab, "closed", None):
continue
connection = _tab
break
@@ -1013,7 +1001,7 @@ async def load(self, file: PathLike = ".session.dat", pattern: str = ".*"):
included_cookies = []
connection = None
for _tab in self._browser.tabs:
- if hasattr(_tab, "closed") and _tab.closed:
+ if getattr(_tab, "closed", None):
continue
connection = _tab
break
@@ -1036,7 +1024,7 @@ async def clear(self):
"""
connection = None
for _tab in self._browser.tabs:
- if hasattr(_tab, "closed") and _tab.closed:
+ if getattr(_tab, "closed", None):
continue
connection = _tab
break
diff --git a/seleniumbase/undetected/cdp_driver/cdp_util.py b/seleniumbase/undetected/cdp_driver/cdp_util.py
index b7acafc19d6..73a0393562f 100644
--- a/seleniumbase/undetected/cdp_driver/cdp_util.py
+++ b/seleniumbase/undetected/cdp_driver/cdp_util.py
@@ -617,6 +617,8 @@ async def start(
sb_config._cdp_browser = "atlas"
else:
sb_config._cdp_browser = "chrome"
+ sb_config.incognito = incognito
+ sb_config.guest_mode = guest
if not config:
config = Config(
user_data_dir,
diff --git a/seleniumbase/undetected/cdp_driver/tab.py b/seleniumbase/undetected/cdp_driver/tab.py
index d53ac36ee55..b24e7dcc48c 100644
--- a/seleniumbase/undetected/cdp_driver/tab.py
+++ b/seleniumbase/undetected/cdp_driver/tab.py
@@ -342,13 +342,19 @@ async def get(
if new_window and not new_tab:
new_tab = True
if new_tab:
- if hasattr(sb_config, "incognito") and sb_config.incognito:
+ if (
+ getattr(sb_config, "incognito", None)
+ or (
+ getattr(sb_config, "_cdp_browser", None)
+ in ["comet", "atlas"]
+ )
+ ):
return await self.browser.get(
url, new_tab=False, new_window=True, **kwargs
)
else:
return await self.browser.get(
- url, new_tab, new_window, **kwargs
+ url, new_tab=True, new_window=False, **kwargs
)
else:
if not kwargs: