diff --git a/README.md b/README.md
index 6099d39148c..470cc141ae2 100755
--- a/README.md
+++ b/README.md
@@ -679,6 +679,7 @@ pytest test_coffee_cart.py --trace
--message-duration=SECONDS # (The time length for Messenger alerts.)
--check-js # (Check for JavaScript errors after page loads.)
--ad-block # (Block some types of display ads from loading.)
+--host-resolver-rules=RULES # (Set host-resolver-rules, comma-separated.)
--block-images # (Block images from loading during tests.)
--do-not-track # (Indicate to websites that you don't want to be tracked.)
--verify-delay=SECONDS # (The delay before MasterQA verification checks.)
diff --git a/examples/presenter/edge_presentation.py b/examples/presenter/edge_presentation.py
index 80df3ff1ee3..3ca53e8a8d0 100644
--- a/examples/presenter/edge_presentation.py
+++ b/examples/presenter/edge_presentation.py
@@ -42,7 +42,7 @@ def test_presentation(self):
self.play_tour()
self.sleep(0.25)
self.open("data:,")
- self.create_presentation(theme="sky", transition="fade")
+ self.create_presentation(theme="beige", transition="fade")
self.add_slide(
"
About the presenter:
\n"
"\n"
@@ -153,24 +153,40 @@ def test_presentation(self):
self.play_tour()
self.highlight('[href*="microsoft-edge/tools/webdriver"]')
- self.get_new_driver(browser="edge")
+ self.get_new_driver(browser="edge", disable_csp=True)
self.maximize_window()
self.open(
"https://developer.microsoft.com/en-us/"
"microsoft-edge/tools/webdriver/"
)
- self.wait_for_element("#page-heading")
- self.scroll_to("#page-heading")
- zoom_in = '#page-heading{zoom: 1.2;-moz-transform: scale(1.2);}'
+ self.wait_for_element("div.common-heading")
+ self.scroll_to("div.common-heading")
+ zoom_in = 'div.h1{zoom: 1.02;-moz-transform: scale(1.02);}'
self.add_css_style(zoom_in)
- self.highlight("#page-heading", loops=8)
- self.sleep(1.2)
- self.highlight("#downloads-channel", loops=8)
- self.sleep(1.2)
- self.highlight("#downloads", loops=12)
- self.sleep(1.8)
- self.highlight("#installation", loops=12)
- self.sleep(1.8)
+ self.highlight("div.common-heading", loops=8)
+ self.create_tour(theme="driverjs")
+ self.add_tour_step(
+ "", "div.common-heading", alignment="left"
+ )
+ self.play_tour()
+ self.highlight('div[data-fetch-key="block-web-driver:0"]', loops=12)
+ self.create_tour(theme="driverjs")
+ self.add_tour_step(
+ "", 'div[data-fetch-key="block-web-driver:0"]', alignment="top"
+ )
+ self.play_tour()
+ self.highlight('div[data-fetch-key="block-web-driver:1"]', loops=12)
+ self.create_tour(theme="driverjs")
+ self.add_tour_step(
+ "", 'div[data-fetch-key="block-web-driver:1"]', alignment="top"
+ )
+ self.play_tour()
+ self.highlight('section[data-section-id="installation"]', loops=12)
+ self.create_tour(theme="driverjs")
+ self.add_tour_step(
+ "", "div.block-heading--sixtyforty", alignment="left"
+ )
+ self.play_tour()
self.quit_extra_driver()
self.switch_to_default_driver()
diff --git a/examples/presenter/multi_uc.py b/examples/presenter/multi_uc.py
index d1107cec3ab..37f621dacf4 100644
--- a/examples/presenter/multi_uc.py
+++ b/examples/presenter/multi_uc.py
@@ -7,14 +7,14 @@
@pytest.mark.parametrize("", [[]] * 3)
def test_multi_threaded(sb):
- sb.driver.get("https://nowsecure.nl/#relax")
+ sb.driver.uc_open_with_tab("https://nowsecure.nl/#relax")
sb.set_window_rect(randint(0, 755), randint(38, 403), 700, 500)
try:
sb.assert_text("OH YEAH, you passed!", "h1", timeout=4)
sb.post_message("Selenium wasn't detected!", duration=4)
sb._print("\n Success! Website did not detect Selenium! ")
except Exception:
- sb.driver.get("https://nowsecure.nl/#relax")
+ sb.driver.uc_open_with_tab("https://nowsecure.nl/#relax")
try:
sb.assert_text("OH YEAH, you passed!", "h1", timeout=4)
sb.post_message("Selenium wasn't detected!", duration=4)
diff --git a/examples/presenter/uc_presentation.py b/examples/presenter/uc_presentation.py
index a94aee7a76e..fd98fb46bed 100644
--- a/examples/presenter/uc_presentation.py
+++ b/examples/presenter/uc_presentation.py
@@ -29,13 +29,13 @@ def test_presentation(self):
self.get_new_driver(undetectable=True)
try:
- self.driver.get("https://nowsecure.nl/#relax")
+ self.driver.uc_open_with_tab("https://nowsecure.nl/#relax")
try:
self.assert_text("OH YEAH, you passed!", "h1", timeout=4)
self.post_message("Selenium wasn't detected!", duration=4)
except Exception:
self.clear_all_cookies()
- self.driver.get("https://nowsecure.nl/#relax")
+ self.driver.uc_open_with_tab("https://nowsecure.nl/#relax")
self.assert_text("OH YEAH, you passed!", "h1", timeout=4)
self.post_message("Selenium wasn't detected!", duration=4)
finally:
@@ -355,10 +355,10 @@ def test_presentation(self):
try:
with SB(uc=True) as sb:
- sb.driver.get("https://nowsecure.nl/#relax")
+ sb.driver.uc_open_with_tab("https://nowsecure.nl/#relax")
sb.sleep(1)
if not sb.is_text_visible("OH YEAH, you passed", "h1"):
- sb.driver.get("https://nowsecure.nl/#relax")
+ sb.driver.uc_open_with_tab("https://nowsecure.nl/#relax")
sb.sleep(1)
sb.activate_demo_mode()
sb.assert_text("OH YEAH, you passed!", "h1", timeout=3)
diff --git a/examples/raw_form_turnstile.py b/examples/raw_form_turnstile.py
index 84df796ecfa..3c169b03f44 100644
--- a/examples/raw_form_turnstile.py
+++ b/examples/raw_form_turnstile.py
@@ -8,9 +8,7 @@ def open_the_form_turnstile_page(sb):
def click_turnstile_and_verify(sb):
- iframe = sb.driver.find_element("iframe")
- sb.driver.reconnect(0.1) # Another way to reconnect
- sb.driver.switch_to.frame(iframe)
+ sb.driver.uc_switch_to_frame("iframe")
sb.driver.uc_click("span.mark")
sb.highlight("img#captcha-success", timeout=3.33)
diff --git a/examples/raw_parameter_script.py b/examples/raw_parameter_script.py
index ee7db91f9b4..d1436fa5bf1 100644
--- a/examples/raw_parameter_script.py
+++ b/examples/raw_parameter_script.py
@@ -84,6 +84,7 @@
sb._disable_beforeunload = False
sb.save_screenshot_after_test = False
sb.no_screenshot_after_test = False
+ sb.host_resolver_rules = None
sb.page_load_strategy = None
sb.timeout_multiplier = None
sb.pytest_html_report = None
diff --git a/examples/raw_turnstile.py b/examples/raw_turnstile.py
index 15d747e4bc9..4cc46144648 100644
--- a/examples/raw_turnstile.py
+++ b/examples/raw_turnstile.py
@@ -8,9 +8,7 @@ def open_the_turnstile_page(sb):
def click_turnstile_and_verify(sb):
- iframe = sb.driver.find_element("iframe")
- sb.driver.reconnect(0.1) # Another way to reconnect
- sb.driver.switch_to.frame(iframe)
+ sb.driver.uc_switch_to_frame("iframe")
sb.driver.uc_click("span.mark")
sb.assert_element("img#captcha-success", timeout=3.33)
diff --git a/examples/test_chromedriver.py b/examples/test_chromedriver.py
index 6056d72cbd9..4ce8d444d3a 100644
--- a/examples/test_chromedriver.py
+++ b/examples/test_chromedriver.py
@@ -9,6 +9,7 @@
class ChromedriverTests(BaseCase):
def test_chromedriver_matches_chrome(self):
if self.browser != "chrome":
+ self.open_if_not_url("data:,")
print("\n This test is only for Chrome!")
print(' (Run with: "--browser=chrome")')
self.skip("This test is only for Chrome!")
diff --git a/examples/test_verify_chromedriver.py b/examples/test_verify_chromedriver.py
index f73d6493282..81a5851579d 100644
--- a/examples/test_verify_chromedriver.py
+++ b/examples/test_verify_chromedriver.py
@@ -28,3 +28,8 @@ def test_fail_if_versions_dont_match(self):
print("\nWarning -> " + message)
elif int(major_chromedriver_version) != int(major_chrome_version):
raise Exception(message)
+ else:
+ print(
+ "\n* Chrome version: {%s}\n* Driver version: {%s}"
+ % (chromedriver_version, chrome_version)
+ )
diff --git a/help_docs/customizing_test_runs.md b/help_docs/customizing_test_runs.md
index ae375223981..2a8ed61498d 100644
--- a/help_docs/customizing_test_runs.md
+++ b/help_docs/customizing_test_runs.md
@@ -159,6 +159,7 @@ pytest my_first_test.py --settings-file=custom_settings.py
--message-duration=SECONDS # (The time length for Messenger alerts.)
--check-js # (Check for JavaScript errors after page loads.)
--ad-block # (Block some types of display ads from loading.)
+--host-resolver-rules=RULES # (Set host-resolver-rules, comma-separated.)
--block-images # (Block images from loading during tests.)
--do-not-track # (Indicate to websites that you don't want to be tracked.)
--verify-delay=SECONDS # (The delay before MasterQA verification checks.)
diff --git a/help_docs/method_summary.md b/help_docs/method_summary.md
index 7dca4ce53eb..7c1965da721 100644
--- a/help_docs/method_summary.md
+++ b/help_docs/method_summary.md
@@ -993,10 +993,16 @@ driver.highlight_click(selector)
driver.sleep(seconds)
+driver.locator(selector)
+
+driver.get_attribute(selector, attribute)
+
driver.get_page_source()
driver.get_title()
+driver.switch_to_frame(frame)
+
############
# "driver"-specific methods added by SeleniumBase for UC Mode: "--uc" / uc=True
@@ -1007,7 +1013,13 @@ driver.uc_open_with_tab(url)
driver.uc_open_with_reconnect(url, reconnect_time=None)
-driver.uc_click(selector)
+driver.reconnect(timeout)
+
+driver.uc_click(
+ selector, by="css selector",
+ timeout=settings.SMALL_TIMEOUT, reconnect_time=None)
+
+driver.uc_switch_to_frame(frame)
```
--------
diff --git a/mkdocs.yml b/mkdocs.yml
index 580dc7c7611..76f615cd6ed 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -157,6 +157,7 @@ nav:
- 🔑 CF Turnstile on Form: https://seleniumbase.io/apps/form_turnstile
- 🔐 reCAPTCHA v2 Test: https://seleniumbase.io/apps/recaptcha
- 🔐 reCAPTCHA v2 on Form: https://seleniumbase.io/apps/form_recaptcha
+ - 🔐 reCAPTCHA, invisible: https://seleniumbase.io/apps/invisible_recaptcha
- Additional Help Docs:
- 📑 Table of Contents: help_docs/ReadMe.md
- 🖼️ How to handle iframes: help_docs/handling_iframes.md
diff --git a/mkdocs_build/requirements.txt b/mkdocs_build/requirements.txt
index e23a4f5e6cf..8fb01cf898b 100644
--- a/mkdocs_build/requirements.txt
+++ b/mkdocs_build/requirements.txt
@@ -3,7 +3,7 @@
regex>=2023.10.3
PyYAML>=6.0.1
-pymdown-extensions>=10.3.1
+pymdown-extensions>=10.4
pipdeptree>=2.13.1
python-dateutil>=2.8.2
Markdown==3.5.1
diff --git a/requirements.txt b/requirements.txt
index fa668b9f899..c137f4f664b 100755
--- a/requirements.txt
+++ b/requirements.txt
@@ -7,7 +7,7 @@ attrs>=23.1.0
certifi>=2023.7.22
filelock>=3.12.2;python_version<"3.8"
filelock>=3.13.1;python_version>="3.8"
-platformdirs>=3.11.0
+platformdirs>=4.0.0
parse>=1.19.1
parse-type>=0.6.2
six==1.16.0
@@ -15,7 +15,7 @@ idna==3.4
chardet==5.2.0
charset-normalizer==3.3.2
urllib3>=1.26.18,<2;python_version<"3.10"
-urllib3>=1.26.18,<2.1.0;python_version>="3.10"
+urllib3>=1.26.18,<2.2.0;python_version>="3.10"
requests==2.31.0
pynose==1.4.8
sniffio==1.3.0
@@ -40,7 +40,7 @@ pytest-html==2.0.1
pytest-metadata==3.0.0
pytest-ordering==0.6
pytest-rerunfailures==12.0
-pytest-xdist==3.3.1
+pytest-xdist==3.4.0
parameterized==0.9.0
sbvirtualdisplay==1.3.0
behave==1.2.6
diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py
index f738015ba0e..7cd5ef0f256 100755
--- a/seleniumbase/__version__.py
+++ b/seleniumbase/__version__.py
@@ -1,2 +1,2 @@
# seleniumbase package
-__version__ = "4.21.1"
+__version__ = "4.21.2"
diff --git a/seleniumbase/behave/behave_sb.py b/seleniumbase/behave/behave_sb.py
index e2830757a93..9dc2a4741e1 100644
--- a/seleniumbase/behave/behave_sb.py
+++ b/seleniumbase/behave/behave_sb.py
@@ -230,6 +230,7 @@ def get_configured_sb(context):
sb.proxy_bypass_list = None
sb.proxy_pac_url = None
sb.multi_proxy = False
+ sb.host_resolver_rules = None
sb.enable_3d_apis = False
sb.swiftshader = False
sb.ad_block_on = False
@@ -772,6 +773,13 @@ def get_configured_sb(context):
if low_key in ["multi-proxy", "multi_proxy"]:
sb.multi_proxy = True
continue
+ # Handle: -D host-resolver-rules=RULES / host_resolver_rules=RULES
+ if low_key in ["host-resolver-rules", "host_resolver_rules"]:
+ host_resolver_rules = userdata[key]
+ if host_resolver_rules == "true":
+ host_resolver_rules = sb.host_resolver_rules
+ sb.host_resolver_rules = host_resolver_rules
+ continue
# Handle: -D enable-3d-apis / enable_3d_apis
if low_key in ["enable-3d-apis", "enable_3d_apis"]:
sb.enable_3d_apis = True
diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py
index 6081ddf6371..d354dff5d72 100644
--- a/seleniumbase/core/browser_launcher.py
+++ b/seleniumbase/core/browser_launcher.py
@@ -187,8 +187,10 @@ def extend_driver(driver):
driver.highlight = DM.highlight
driver.highlight_click = DM.highlight_click
driver.sleep = time.sleep
+ driver.get_attribute = DM.get_attribute
driver.get_page_source = DM.get_page_source
driver.get_title = DM.get_title
+ driver.switch_to_frame = DM.switch_to_frame
if hasattr(driver, "proxy"):
driver.set_wire_proxy = DM.set_wire_proxy
return driver
@@ -453,6 +455,17 @@ def uc_click(
driver.js_click(selector, by=by, timeout=timeout)
+def uc_switch_to_frame(driver, frame):
+ from selenium.webdriver.remote.webelement import WebElement
+ if isinstance(frame, WebElement):
+ driver.reconnect(0.15)
+ driver.switch_to.frame(frame)
+ else:
+ iframe = driver.locator(frame)
+ driver.reconnect(0.15)
+ driver.switch_to.frame(iframe)
+
+
def edgedriver_on_path():
return os.path.exists(LOCAL_EDGEDRIVER)
@@ -743,6 +756,7 @@ def _set_chrome_options(
enable_3d_apis,
swiftshader,
ad_block_on,
+ host_resolver_rules,
block_images,
do_not_track,
chromium_arg,
@@ -824,6 +838,10 @@ def _set_chrome_options(
chrome_options.set_capability(
"goog:loggingPrefs", {"performance": "ALL", "browser": "ALL"}
)
+ if host_resolver_rules:
+ chrome_options.add_argument(
+ "--host-resolver-rules=%s" % host_resolver_rules
+ )
if mobile_emulator and not is_using_uc(undetectable, browser_name):
emulator_settings = {}
device_metrics = {}
@@ -1307,6 +1325,7 @@ def get_driver(
enable_3d_apis=False,
swiftshader=False,
ad_block_on=False,
+ host_resolver_rules=None,
block_images=False,
do_not_track=False,
chromium_arg=None,
@@ -1518,6 +1537,7 @@ def get_driver(
enable_3d_apis,
swiftshader,
ad_block_on,
+ host_resolver_rules,
block_images,
do_not_track,
chromium_arg,
@@ -1572,6 +1592,7 @@ def get_driver(
enable_3d_apis,
swiftshader,
ad_block_on,
+ host_resolver_rules,
block_images,
do_not_track,
chromium_arg,
@@ -1630,6 +1651,7 @@ def get_remote_driver(
enable_3d_apis,
swiftshader,
ad_block_on,
+ host_resolver_rules,
block_images,
do_not_track,
chromium_arg,
@@ -1751,6 +1773,7 @@ def get_remote_driver(
enable_3d_apis,
swiftshader,
ad_block_on,
+ host_resolver_rules,
block_images,
do_not_track,
chromium_arg,
@@ -1915,6 +1938,7 @@ def get_remote_driver(
enable_3d_apis,
swiftshader,
ad_block_on,
+ host_resolver_rules,
block_images,
do_not_track,
chromium_arg,
@@ -2029,6 +2053,7 @@ def get_local_driver(
enable_3d_apis,
swiftshader,
ad_block_on,
+ host_resolver_rules,
block_images,
do_not_track,
chromium_arg,
@@ -2440,6 +2465,10 @@ def get_local_driver(
edge_options.set_capability(
"ms:loggingPrefs", {"performance": "ALL", "browser": "ALL"}
)
+ if host_resolver_rules:
+ edge_options.add_argument(
+ "--host-resolver-rules=%s" % host_resolver_rules
+ )
if not enable_sync:
edge_options.add_argument("--disable-sync")
if (
@@ -2782,6 +2811,7 @@ def get_local_driver(
enable_3d_apis,
swiftshader,
ad_block_on,
+ host_resolver_rules,
block_images,
do_not_track,
chromium_arg,
@@ -3282,6 +3312,7 @@ def get_local_driver(
enable_3d_apis,
swiftshader,
None, # ad_block_on
+ None, # host_resolver_rules
block_images,
do_not_track,
None, # chromium_arg
@@ -3498,6 +3529,7 @@ def get_local_driver(
enable_3d_apis,
swiftshader,
None, # ad_block_on
+ None, # host_resolver_rules
block_images,
do_not_track,
None, # chromium_arg
@@ -3574,6 +3606,11 @@ def get_local_driver(
driver.uc_click = lambda *args, **kwargs: uc_click(
driver, *args, **kwargs
)
+ driver.uc_switch_to_frame = (
+ lambda *args, **kwargs: uc_switch_to_frame(
+ driver, *args, **kwargs
+ )
+ )
if mobile_emulator:
uc_metrics = {}
if (
diff --git a/seleniumbase/core/sb_driver.py b/seleniumbase/core/sb_driver.py
index 4e8b8e1e359..265f7d70e2c 100644
--- a/seleniumbase/core/sb_driver.py
+++ b/seleniumbase/core/sb_driver.py
@@ -1,4 +1,5 @@
"""Add new methods to extend the driver"""
+from selenium.webdriver.remote.webelement import WebElement
from seleniumbase.fixtures import js_utils
from seleniumbase.fixtures import page_actions
from seleniumbase.fixtures import page_utils
@@ -41,6 +42,10 @@ def locator(self, selector, by=None):
pass
raise Exception('No such Element: {%s} (by="%s")!' % (selector, by))
+ def get_attribute(self, selector, attribute, by="css selector"):
+ element = self.locator(selector, by=by)
+ return element.get_attribute(attribute)
+
def get_page_source(self):
return self.driver.page_source
@@ -158,6 +163,13 @@ def highlight_click(self, *args, **kwargs):
kwargs.pop("loops")
page_actions.click(self.driver, *args, **kwargs)
+ def switch_to_frame(self, frame):
+ if isinstance(frame, WebElement):
+ self.driver.switch_to.frame(frame)
+ else:
+ iframe = self.locator(frame)
+ self.driver.switch_to.frame(iframe)
+
def set_wire_proxy(self, string):
"""Set a proxy server for selenium-wire mode ("--wire")
Examples: (ONLY avilable if using selenium-wire mode!)
diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py
index fbad650b0ff..afcbe0038b9 100644
--- a/seleniumbase/fixtures/base_case.py
+++ b/seleniumbase/fixtures/base_case.py
@@ -3765,6 +3765,7 @@ def get_new_driver(
enable_3d_apis=None,
swiftshader=None,
ad_block_on=None,
+ host_resolver_rules=None,
block_images=None,
do_not_track=None,
chromium_arg=None,
@@ -3822,6 +3823,7 @@ def get_new_driver(
enable_3d_apis - the option to enable WebGL and 3D APIs (Chrome)
swiftshader - the option to use Chrome's swiftshader (Chrome-only)
ad_block_on - the option to block ads from loading (Chromium-only)
+ host_resolver_rules - Configure host-resolver-rules (Chromium-only)
block_images - the option to block images from loading (Chrome)
do_not_track - indicate that websites should not track you (Chrome)
chromium_arg - the option to add a Chromium arg to Chrome/Edge
@@ -3937,6 +3939,8 @@ def get_new_driver(
swiftshader = self._swiftshader
if ad_block_on is None:
ad_block_on = self.ad_block_on
+ if host_resolver_rules is None:
+ host_resolver_rules = self.host_resolver_rules
if block_images is None:
block_images = self.block_images
if do_not_track is None:
@@ -4024,6 +4028,7 @@ def get_new_driver(
enable_3d_apis=enable_3d_apis,
swiftshader=swiftshader,
ad_block_on=ad_block_on,
+ host_resolver_rules=host_resolver_rules,
block_images=block_images,
do_not_track=do_not_track,
chromium_arg=chromium_arg,
@@ -14266,6 +14271,7 @@ def setUp(self, masterqa_mode=False):
self.message_duration = sb_config.message_duration
self.js_checking_on = sb_config.js_checking_on
self.ad_block_on = sb_config.ad_block_on
+ self.host_resolver_rules = sb_config.host_resolver_rules
self.block_images = sb_config.block_images
self.do_not_track = sb_config.do_not_track
self.chromium_arg = sb_config.chromium_arg
@@ -14633,6 +14639,7 @@ def setUp(self, masterqa_mode=False):
enable_3d_apis=self.enable_3d_apis,
swiftshader=self._swiftshader,
ad_block_on=self.ad_block_on,
+ host_resolver_rules=self.host_resolver_rules,
block_images=self.block_images,
do_not_track=self.do_not_track,
chromium_arg=self.chromium_arg,
@@ -14651,8 +14658,14 @@ def setUp(self, masterqa_mode=False):
d_height=self.__device_height,
d_p_r=self.__device_pixel_ratio,
)
- if self.driver.timeouts.implicit_wait > 0:
- self.driver.implicitly_wait(0)
+ try:
+ if self.driver.timeouts.implicit_wait > 0:
+ self.driver.implicitly_wait(0)
+ except Exception:
+ try:
+ self.driver.implicitly_wait(0)
+ except Exception:
+ pass
self._default_driver = self.driver
if self._reuse_session:
sb_config.shared_driver = self.driver
@@ -14671,10 +14684,13 @@ def setUp(self, masterqa_mode=False):
self.set_time_limit(self.time_limit)
# Configure the page load timeout
- if hasattr(settings, "PAGE_LOAD_TIMEOUT"):
- self.driver.set_page_load_timeout(settings.PAGE_LOAD_TIMEOUT)
- else:
- self.driver.set_page_load_timeout(120) # Selenium uses 300
+ try:
+ if hasattr(settings, "PAGE_LOAD_TIMEOUT"):
+ self.driver.set_page_load_timeout(settings.PAGE_LOAD_TIMEOUT)
+ else:
+ self.driver.set_page_load_timeout(120) # Selenium uses 300
+ except Exception:
+ pass
# Set the start time for the test (in ms).
# Although the pytest clock starts before setUp() begins,
diff --git a/seleniumbase/plugins/driver_manager.py b/seleniumbase/plugins/driver_manager.py
index c4921c38cea..122e463de95 100644
--- a/seleniumbase/plugins/driver_manager.py
+++ b/seleniumbase/plugins/driver_manager.py
@@ -99,6 +99,7 @@ def Driver(
enable_3d_apis=None, # Enable WebGL and 3D APIs.
swiftshader=None, # Chrome: --use-gl=angle / --use-angle=swiftshader-webgl
ad_block_on=None, # Block some types of display ads from loading.
+ host_resolver_rules=None, # Set host-resolver-rules, comma-separated.
block_images=None, # Block images from loading during tests.
do_not_track=None, # Tell websites that you don't want to be tracked.
chromium_arg=None, # "ARG=N,ARG2" (Set Chromium args, ","-separated.)
@@ -436,6 +437,15 @@ def Driver(
ad_block_on = True
else:
ad_block_on = False
+ if host_resolver_rules is None:
+ if '--host-resolver-rules="' in arg_join:
+ host_resolver_rules = (
+ arg_join.split('--host-resolver-rules="')[1].split('"')[0]
+ )
+ elif '--host_resolver_rules="' in arg_join:
+ host_resolver_rules = (
+ arg_join.split("--host_resolver_rules=")[1].split('"')[0]
+ )
if driver_version is None:
if "--driver-version=" in arg_join:
driver_version = (
@@ -486,6 +496,7 @@ def Driver(
enable_3d_apis=enable_3d_apis,
swiftshader=swiftshader,
ad_block_on=ad_block_on,
+ host_resolver_rules=host_resolver_rules,
block_images=block_images,
do_not_track=do_not_track,
chromium_arg=chromium_arg,
diff --git a/seleniumbase/plugins/pytest_plugin.py b/seleniumbase/plugins/pytest_plugin.py
index 3e3c8703351..ca0686e89eb 100644
--- a/seleniumbase/plugins/pytest_plugin.py
+++ b/seleniumbase/plugins/pytest_plugin.py
@@ -76,6 +76,7 @@ def pytest_addoption(parser):
--message-duration=SECONDS (The time length for Messenger alerts.)
--check-js (Check for JavaScript errors after page loads.)
--ad-block (Block some types of display ads from loading.)
+ --host-resolver-rules=RULES (Set host-resolver-rules, comma-separated.)
--block-images (Block images from loading during tests.)
--do-not-track (Indicate to websites that you don't want to be tracked.)
--verify-delay=SECONDS (The delay before MasterQA verification checks.)
@@ -798,8 +799,8 @@ def pytest_addoption(parser):
dest="message_duration",
default=None,
help="""Setting this overrides the default time that
- messenger notifications remain visible when reaching
- assert statements during Demo Mode.""",
+ messenger notifications remain visible when
+ reaching assert statements during Demo Mode.""",
)
parser.addoption(
"--check_js",
@@ -822,6 +823,25 @@ def pytest_addoption(parser):
help="""Using this makes WebDriver block display ads
that are defined in ad_block_list.AD_BLOCK_LIST.""",
)
+ parser.addoption(
+ "--host_resolver_rules",
+ "--host-resolver-rules",
+ action="store",
+ dest="host_resolver_rules",
+ default=None,
+ help="""Use this option to set "host-resolver-rules".
+ This lets you re-map traffic from any domain.
+ Eg. "MAP www.google-analytics.com 0.0.0.0".
+ Eg. "MAP * ~NOTFOUND , EXCLUDE myproxy".
+ Eg. "MAP * 0.0.0.0 , EXCLUDE 127.0.0.1".
+ Eg. "MAP *.google.com myproxy".
+ Find more examples on these pages:
+ (https://www.electronjs.org/docs/
+ latest/api/command-line-switches)
+ (https://www.chromium.org/developers/
+ design-documents/network-stack/socks-proxy/)
+ Use comma-separation for multiple host rules.""",
+ )
parser.addoption(
"--block_images",
"--block-images",
@@ -1499,6 +1519,7 @@ def pytest_configure(config):
sb_config.message_duration = config.getoption("message_duration")
sb_config.js_checking_on = config.getoption("js_checking_on")
sb_config.ad_block_on = config.getoption("ad_block_on")
+ sb_config.host_resolver_rules = config.getoption("host_resolver_rules")
sb_config.block_images = config.getoption("block_images")
sb_config.do_not_track = config.getoption("do_not_track")
sb_config.verify_delay = config.getoption("verify_delay")
diff --git a/seleniumbase/plugins/sb_manager.py b/seleniumbase/plugins/sb_manager.py
index 5ab3ba5f93c..e0b1336857e 100644
--- a/seleniumbase/plugins/sb_manager.py
+++ b/seleniumbase/plugins/sb_manager.py
@@ -63,6 +63,7 @@ def SB(
enable_3d_apis=None, # Enable WebGL and 3D APIs.
swiftshader=None, # Chrome: --use-gl=angle / --use-angle=swiftshader-webgl
ad_block_on=None, # Block some types of display ads from loading.
+ host_resolver_rules=None, # Set host-resolver-rules, comma-separated.
block_images=None, # Block images from loading during tests.
do_not_track=None, # Tell websites that you don't want to be tracked.
chromium_arg=None, # "ARG=N,ARG2" (Set Chromium args, ","-separated.)
@@ -604,6 +605,15 @@ def SB(
ad_block_on = True
else:
ad_block_on = False
+ if host_resolver_rules is None:
+ if '--host-resolver-rules="' in arg_join:
+ host_resolver_rules = (
+ arg_join.split('--host-resolver-rules="')[1].split('"')[0]
+ )
+ elif '--host_resolver_rules="' in arg_join:
+ host_resolver_rules = (
+ arg_join.split("--host_resolver_rules=")[1].split('"')[0]
+ )
if driver_version is None:
if "--driver-version=" in arg_join:
driver_version = (
@@ -710,6 +720,7 @@ def SB(
sb_config.dashboard = False
sb_config._dashboard_initialized = False
sb_config.message_duration = message_duration
+ sb_config.host_resolver_rules = host_resolver_rules
sb_config.block_images = block_images
sb_config.do_not_track = do_not_track
sb_config.use_wire = use_wire
@@ -811,6 +822,7 @@ def SB(
sb.dashboard = sb_config.dashboard
sb._dash_initialized = sb_config._dashboard_initialized
sb.message_duration = sb_config.message_duration
+ sb.host_resolver_rules = sb_config.host_resolver_rules
sb.block_images = sb_config.block_images
sb.do_not_track = sb_config.do_not_track
sb.use_wire = sb_config.use_wire
diff --git a/seleniumbase/plugins/selenium_plugin.py b/seleniumbase/plugins/selenium_plugin.py
index f8c45536ae9..3e9af8bc0ff 100644
--- a/seleniumbase/plugins/selenium_plugin.py
+++ b/seleniumbase/plugins/selenium_plugin.py
@@ -55,6 +55,7 @@ class SeleniumBrowser(Plugin):
--message-duration=SECONDS (The time length for Messenger alerts.)
--check-js (Check for JavaScript errors after page loads.)
--ad-block (Block some types of display ads from loading.)
+ --host-resolver-rules=RULES (Set host-resolver-rules, comma-separated.)
--block-images (Block images from loading during tests.)
--do-not-track (Indicate to websites that you don't want to be tracked.)
--verify-delay=SECONDS (The delay before MasterQA verification checks.)
@@ -529,8 +530,8 @@ def options(self, parser, env):
dest="message_duration",
default=None,
help="""Setting this overrides the default time that
- messenger notifications remain visible when reaching
- assert statements during Demo Mode.""",
+ messenger notifications remain visible when
+ reaching assert statements during Demo Mode.""",
)
parser.addoption(
"--check_js",
@@ -553,6 +554,25 @@ def options(self, parser, env):
help="""Using this makes WebDriver block display ads
that are defined in ad_block_list.AD_BLOCK_LIST.""",
)
+ parser.addoption(
+ "--host_resolver_rules",
+ "--host-resolver-rules",
+ action="store",
+ dest="host_resolver_rules",
+ default=None,
+ help="""Use this option to set "host-resolver-rules".
+ This lets you re-map traffic from any domain.
+ Eg. "MAP www.google-analytics.com 0.0.0.0".
+ Eg. "MAP * ~NOTFOUND , EXCLUDE myproxy".
+ Eg. "MAP * 0.0.0.0 , EXCLUDE 127.0.0.1".
+ Eg. "MAP *.google.com myproxy".
+ Find more examples on these pages:
+ (https://www.electronjs.org/docs/
+ latest/api/command-line-switches)
+ (https://www.chromium.org/developers/
+ design-documents/network-stack/socks-proxy/)
+ Use comma-separation for multiple host rules.""",
+ )
parser.addoption(
"--block_images",
"--block-images",
@@ -1090,6 +1110,7 @@ def beforeTest(self, test):
test.test.message_duration = self.options.message_duration
test.test.js_checking_on = self.options.js_checking_on
test.test.ad_block_on = self.options.ad_block_on
+ test.test.host_resolver_rules = self.options.host_resolver_rules
test.test.block_images = self.options.block_images
test.test.do_not_track = self.options.do_not_track
test.test.verify_delay = self.options.verify_delay # MasterQA
diff --git a/seleniumbase/undetected/__init__.py b/seleniumbase/undetected/__init__.py
index 3fbb1a57239..da76cb768bf 100644
--- a/seleniumbase/undetected/__init__.py
+++ b/seleniumbase/undetected/__init__.py
@@ -367,6 +367,7 @@ def remove_cdc_props_as_needed(self):
cdc_props = self._get_cdc_props()
if len(cdc_props) > 0:
self._hook_remove_cdc_props(cdc_props)
+ time.sleep(0.05)
def get(self, url):
self.remove_cdc_props_as_needed()
@@ -438,6 +439,10 @@ def quit(self):
try:
logger.debug("Terminating the UC browser")
os.kill(self.browser_pid, 15)
+ # Not sure if this is really needed:
+ os.waitpid(self.browser_pid, 0)
+ except (AttributeError, ChildProcessError, RuntimeError, OSError):
+ pass
except TimeoutError as e:
logger.debug(e, exc_info=True)
except Exception:
diff --git a/setup.py b/setup.py
index a3b3bc8ba64..a54fc2a089d 100755
--- a/setup.py
+++ b/setup.py
@@ -140,7 +140,7 @@
"certifi>=2023.7.22",
'filelock>=3.12.2;python_version<"3.8"',
'filelock>=3.13.1;python_version>="3.8"',
- 'platformdirs>=3.11.0',
+ 'platformdirs>=4.0.0',
'parse>=1.19.1',
'parse-type>=0.6.2',
"six==1.16.0",
@@ -148,7 +148,7 @@
'chardet==5.2.0',
'charset-normalizer==3.3.2',
'urllib3>=1.26.18,<2;python_version<"3.10"',
- 'urllib3>=1.26.18,<2.1.0;python_version>="3.10"',
+ 'urllib3>=1.26.18,<2.2.0;python_version>="3.10"',
'requests==2.31.0',
"pynose==1.4.8",
'sniffio==1.3.0',
@@ -173,7 +173,7 @@
'pytest-metadata==3.0.0',
"pytest-ordering==0.6",
'pytest-rerunfailures==12.0',
- 'pytest-xdist==3.3.1',
+ 'pytest-xdist==3.4.0',
'parameterized==0.9.0',
"sbvirtualdisplay==1.3.0",
"behave==1.2.6",