Add support for the "selenium-wire" library

This commit is contained in:
Michael Mintz 2022-10-29 20:42:25 -04:00
parent 4bb3a0a082
commit d4df607822
13 changed files with 139 additions and 8 deletions

View File

@ -565,7 +565,8 @@ pytest my_first_test.py --pdb
--maximize # (Start tests with the browser window maximized.)
--screenshot # (Save a screenshot at the end of each test.)
--visual-baseline # (Set the visual baseline for Visual/Layout tests.)
--external-pdf # (Set Chrome "plugins.always_open_pdf_externally": True.)
--wire # (Use selenium-wire's webdriver for replacing selenium webdriver.)
--external-pdf # (Set Chromium "plugins.always_open_pdf_externally":True.)
--timeout-multiplier=MULTIPLIER # (Multiplies the default timeout values.)
--list-fail-page # (After each failing test, list the URL of the failure.)
```

View File

@ -74,6 +74,7 @@ if pure_python:
sb._reuse_session = False
sb._crumbs = False
sb._final_debug = False
sb.use_wire = False
sb.visual_baseline = False
sb.window_size = None
sb.maximize_option = False

View File

@ -179,7 +179,8 @@ pytest my_first_test.py --settings-file=custom_settings.py
--maximize # (Start tests with the browser window maximized.)
--screenshot # (Save a screenshot at the end of each test.)
--visual-baseline # (Set the visual baseline for Visual/Layout tests.)
--external-pdf # (Set Chrome "plugins.always_open_pdf_externally": True.)
--wire # (Use selenium-wire's webdriver for replacing selenium webdriver.)
--external-pdf # (Set Chromium "plugins.always_open_pdf_externally":True.)
--timeout-multiplier=MULTIPLIER # (Multiplies the default timeout values.)
--list-fail-page # (After each failing test, list the URL of the failure.)
```

View File

@ -24,6 +24,7 @@
* Can run tests with a customized browser user agent. (``--agent=USER_AGENT_STRING``)
* Can set a Chromium User Data Directory/Profile to load. (``--user-data-dir=DIR``)
* Can avoid detection by sites that try to block Selenium. (``--undetected``/``--uc``)
* Can integrate with [selenium-wire](https://github.com/wkeeling/selenium-wire) for inspecting browser requests. (``--wire``)
* Can load Chrome Extension ZIP files. (``--extension-zip=ZIP``)
* Can load Chrome Extension folders. (``--extension-dir=DIR``)
* Powerful [console scripts](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/console_scripts/ReadMe.md). (Type **``seleniumbase``** or **``sbase``** to use.)

View File

@ -536,6 +536,10 @@ self.get_session_storage_items()
############
self.set_wire_proxy(string) # Requires "--wire"!
############
self.add_css_link(css_link)
self.add_js_link(js_link)

View File

@ -73,7 +73,7 @@ class BaseTestCase(BaseCase):
# <<< Run custom setUp() code for tests AFTER the super().setUp() >>>
def tearDown(self):
self.save_teardown_screenshot() # If test fails, or if "--screenshot"
self.save_teardown_screenshot() # On failure or "--screenshot"
if self.has_exception():
# <<< Run custom code if the test failed. >>>
pass
@ -255,7 +255,7 @@ class OverrideDriverTest(BaseCase):
(From <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/test_override_driver.py">examples/test_override_driver.py</a>)
The above format can let you use [selenium-wire](https://github.com/wkeeling/selenium-wire) to intercept & inspect requests and responses during SeleniumBase tests. Here's how the ``selenium-wire`` integration may look:
The above format lets you customize [selenium-wire](https://github.com/wkeeling/selenium-wire) for intercepting and inspecting requests and responses during SeleniumBase tests. Here's how a ``selenium-wire`` integration may look:
```python
from seleniumbase import BaseCase
@ -277,6 +277,8 @@ class WireTestCase(BaseCase):
print(request.url)
```
(NOTE: The ``selenium-wire`` integration is now included with ``seleniumbase``: Add ``--wire`` as a ``pytest`` command-line option to activate. If you need both ``--wire`` with ``--undetected`` together, you'll still need to override ``get_new_driver()``.)
<a id="sb_sf_10"></a>
<h3><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> 10. Overriding the driver via "sb" fixture</h3>
@ -297,7 +299,7 @@ def sb(request):
super(BaseClass, self).setUp()
def tearDown(self):
self.save_teardown_screenshot()
self.save_teardown_screenshot() # On failure or "--screenshot"
super(BaseClass, self).tearDown()
def base_method(self):
@ -352,7 +354,7 @@ def sb(request):
super(BaseClass, self).setUp()
def tearDown(self):
self.save_teardown_screenshot()
self.save_teardown_screenshot() # On failure or "--screenshot"
super(BaseClass, self).tearDown()
def base_method(self):
@ -390,6 +392,8 @@ class TestWire:
print(request.url)
```
(NOTE: The ``selenium-wire`` integration is now included with ``seleniumbase``: Add ``--wire`` as a ``pytest`` command-line option to activate. If you need both ``--wire`` with ``--undetected`` together, you'll still need to override ``get_new_driver()``.)
<a id="sb_sf_11"></a>
<h3><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> 11. BaseCase with Chinese translations</h3>

View File

@ -89,6 +89,7 @@ behave -D agent="User Agent String" -D demo
-D maximize (Start tests with the browser window maximized.)
-D screenshot (Save a screenshot at the end of each test.)
-D visual-baseline (Set the visual baseline for Visual/Layout tests.)
-D wire (Use selenium-wire's webdriver for replacing selenium webdriver.)
-D external-pdf (Set Chromium "plugins.always_open_pdf_externally": True.)
-D timeout-multiplier=MULTIPLIER (Multiplies the default timeout values.)
"""
@ -179,6 +180,7 @@ def get_configured_sb(context):
sb._crumbs = False
sb._disable_beforeunload = False
sb.visual_baseline = False
sb.use_wire = False
sb.window_size = None
sb.maximize_option = False
sb.is_context_manager = False
@ -540,6 +542,10 @@ def get_configured_sb(context):
if low_key in ["visual-baseline", "visual_baseline"]:
sb.visual_baseline = True
continue
# Handle: -D wire
if low_key == "wire":
sb.use_wire = True
continue
# Handle: -D window-size=Width,Height / window_size=Width,Height
if low_key in ["window-size", "window_size"]:
window_size = userdata[key]

View File

@ -16,6 +16,7 @@ from seleniumbase.config import settings
from seleniumbase.core import download_helper
from seleniumbase.core import proxy_helper
from seleniumbase.fixtures import constants
from seleniumbase.fixtures import shared_utils
from seleniumbase import drivers # webdriver storage folder for SeleniumBase
from seleniumbase import extensions # browser extensions storage folder
@ -372,6 +373,7 @@ def _set_chrome_options(
extension_zip,
extension_dir,
page_load_strategy,
use_wire,
external_pdf,
servername,
mobile_emulator,
@ -918,6 +920,7 @@ def get_driver(
extension_zip=None,
extension_dir=None,
page_load_strategy=None,
use_wire=False,
external_pdf=False,
test_id=None,
mobile_emulator=False,
@ -1083,6 +1086,7 @@ def get_driver(
extension_zip,
extension_dir,
page_load_strategy,
use_wire,
external_pdf,
test_id,
mobile_emulator,
@ -1130,6 +1134,7 @@ def get_driver(
extension_zip,
extension_dir,
page_load_strategy,
use_wire,
external_pdf,
mobile_emulator,
device_width,
@ -1181,6 +1186,7 @@ def get_remote_driver(
extension_zip,
extension_dir,
page_load_strategy,
use_wire,
external_pdf,
test_id,
mobile_emulator,
@ -1188,6 +1194,21 @@ def get_remote_driver(
device_height,
device_pixel_ratio,
):
if use_wire and selenium4_or_newer:
driver_fixing_lock = fasteners.InterProcessLock(
constants.MultiBrowser.DRIVER_FIXING_LOCK
)
with driver_fixing_lock: # Prevent multi-processes mode issues
try:
from seleniumwire import webdriver
except Exception:
shared_utils.pip_install(
"selenium-wire", version=constants.SeleniumWire.VER
)
from seleniumwire import webdriver
else:
from selenium import webdriver
# Construct the address for connecting to a Selenium Grid
if servername.startswith("https://"):
protocol = "https"
@ -1280,6 +1301,7 @@ def get_remote_driver(
extension_zip,
extension_dir,
page_load_strategy,
use_wire,
external_pdf,
servername,
mobile_emulator,
@ -1510,6 +1532,7 @@ def get_remote_driver(
extension_zip,
extension_dir,
page_load_strategy,
use_wire,
external_pdf,
servername,
mobile_emulator,
@ -1708,6 +1731,7 @@ def get_local_driver(
extension_zip,
extension_dir,
page_load_strategy,
use_wire,
external_pdf,
mobile_emulator,
device_width,
@ -1719,6 +1743,20 @@ def get_local_driver(
Can also be used to spin up additional browsers for the same test.
"""
downloads_path = DOWNLOADS_FOLDER
if use_wire and selenium4_or_newer:
driver_fixing_lock = fasteners.InterProcessLock(
constants.MultiBrowser.DRIVER_FIXING_LOCK
)
with driver_fixing_lock: # Prevent multi-processes mode issues
try:
from seleniumwire import webdriver
except Exception:
shared_utils.pip_install(
"selenium-wire", version=constants.SeleniumWire.VER
)
from seleniumwire import webdriver
else:
from selenium import webdriver
if browser_name == constants.Browser.FIREFOX:
firefox_options = _set_firefox_options(
@ -2308,6 +2346,7 @@ def get_local_driver(
extension_zip,
extension_dir,
page_load_strategy,
use_wire,
external_pdf,
servername,
mobile_emulator,
@ -2372,6 +2411,7 @@ def get_local_driver(
extension_zip,
extension_dir,
page_load_strategy,
use_wire,
external_pdf,
servername,
mobile_emulator,
@ -2754,6 +2794,7 @@ def get_local_driver(
extension_zip,
extension_dir,
page_load_strategy,
use_wire,
external_pdf,
servername,
mobile_emulator,

View File

@ -3201,6 +3201,7 @@ class BaseCase(unittest.TestCase):
extension_zip=None,
extension_dir=None,
page_load_strategy=None,
use_wire=None,
external_pdf=None,
is_mobile=None,
d_width=None,
@ -3251,6 +3252,7 @@ class BaseCase(unittest.TestCase):
extension_zip - A Chrome Extension ZIP file to use (Chrome-only)
extension_dir - A Chrome Extension folder to use (Chrome-only)
page_load_strategy - the option to change pageLoadStrategy (Chrome)
use_wire - Use selenium-wire webdriver instead of the selenium one
external_pdf - "plugins.always_open_pdf_externally": True. (Chrome)
is_mobile - the option to use the mobile emulator (Chrome-only)
d_width - the device width of the mobile emulator (Chrome-only)
@ -3367,6 +3369,8 @@ class BaseCase(unittest.TestCase):
extension_dir = self.extension_dir
if page_load_strategy is None:
page_load_strategy = self.page_load_strategy
if use_wire is None:
use_wire = self.use_wire
if external_pdf is None:
external_pdf = self.external_pdf
test_id = self.__get_test_id()
@ -3432,6 +3436,7 @@ class BaseCase(unittest.TestCase):
extension_zip=extension_zip,
extension_dir=extension_dir,
page_load_strategy=page_load_strategy,
use_wire=use_wire,
external_pdf=external_pdf,
test_id=test_id,
mobile_emulator=is_mobile,
@ -7773,6 +7778,36 @@ class BaseCase(unittest.TestCase):
############
# Methods ONLY for the selenium-wire integration ("--wire")
def set_wire_proxy(self, string):
"""Set a proxy server for selenium-wire mode ("--wire")
NOTE: This method ONLY works while using "--wire" mode!
Examples:
self.set_wire_proxy("SERVER:PORT")
self.set_wire_proxy("socks5://SERVER:PORT")
self.set_wire_proxy("USERNAME:PASSWORD@SERVER:PORT")
"""
if not string:
self.driver.proxy = {}
return
the_http = "http"
the_https = "https"
if string.startswith("socks4://"):
the_http = "socks4"
the_https = "socks4"
elif string.startswith("socks5://"):
the_http = "socks5"
the_https = "socks5"
string = string.split("//")[-1]
self.driver.proxy = {
"http": "%s://%s" % (the_http, string),
"https": "%s://%s" % (the_https, string),
"no_proxy": "localhost,127.0.0.1",
}
############
# Duplicates (Avoids name confusion when migrating from other frameworks.)
def open_url(self, url):
@ -12804,6 +12839,7 @@ class BaseCase(unittest.TestCase):
self.extension_zip = sb_config.extension_zip
self.extension_dir = sb_config.extension_dir
self.page_load_strategy = sb_config.page_load_strategy
self.use_wire = sb_config.use_wire
self.external_pdf = sb_config.external_pdf
self._final_debug = sb_config.final_debug
self.window_size = sb_config.window_size
@ -13091,6 +13127,7 @@ class BaseCase(unittest.TestCase):
extension_zip=self.extension_zip,
extension_dir=self.extension_dir,
page_load_strategy=self.page_load_strategy,
use_wire=self.use_wire,
external_pdf=self.external_pdf,
is_mobile=self.mobile_emulator,
d_width=self.__device_width,

View File

@ -293,6 +293,11 @@ class Tether:
)
class SeleniumWire:
# The version installed if selenium-wire is not installed
VER = "5.1.0"
class ValidBrowsers:
valid_browsers = [
"chrome",

View File

@ -108,7 +108,8 @@ def pytest_addoption(parser):
--maximize (Start tests with the browser window maximized.)
--screenshot (Save a screenshot at the end of each test.)
--visual-baseline (Set the visual baseline for Visual/Layout tests.)
--external-pdf (Set Chromium "plugins.always_open_pdf_externally": True.)
--wire (Use selenium-wire's webdriver for replacing selenium webdriver.)
--external-pdf (Set Chromium "plugins.always_open_pdf_externally":True.)
--timeout-multiplier=MULTIPLIER (Multiplies the default timeout values.)
--list-fail-page (After each failing test, list the URL of the failure.)
"""
@ -1097,6 +1098,13 @@ def pytest_addoption(parser):
When a test calls self.check_window(), it will
rebuild its files in the visual_baseline folder.""",
)
parser.addoption(
"--wire",
action="store_true",
dest="use_wire",
default=False,
help="""Use selenium-wire's webdriver for selenium webdriver.""",
)
parser.addoption(
"--external_pdf",
"--external-pdf",
@ -1415,6 +1423,7 @@ def pytest_configure(config):
sb_config.maximize_option = config.getoption("maximize_option")
sb_config.save_screenshot = config.getoption("save_screenshot")
sb_config.visual_baseline = config.getoption("visual_baseline")
sb_config.use_wire = config.getoption("use_wire")
sb_config.external_pdf = config.getoption("external_pdf")
sb_config.timeout_multiplier = config.getoption("timeout_multiplier")
sb_config.list_fp = config.getoption("fail_page")

View File

@ -82,6 +82,7 @@ class SeleniumBrowser(Plugin):
--maximize (Start tests with the browser window maximized.)
--screenshot (Save a screenshot at the end of each test.)
--visual-baseline (Set the visual baseline for Visual/Layout tests.)
--wire (Use selenium-wire's webdriver for replacing selenium webdriver.)
--external-pdf (Set Chromium "plugins.always_open_pdf_externally": True.)
--timeout-multiplier=MULTIPLIER (Multiplies the default timeout values.)
"""
@ -783,6 +784,13 @@ class SeleniumBrowser(Plugin):
When a test calls self.check_window(), it will
rebuild its files in the visual_baseline folder.""",
)
parser.add_option(
"--wire",
action="store_true",
dest="use_wire",
default=False,
help="""Use selenium-wire's webdriver for selenium webdriver.""",
)
parser.add_option(
"--external_pdf",
"--external-pdf",
@ -942,6 +950,7 @@ class SeleniumBrowser(Plugin):
test.test.maximize_option = self.options.maximize_option
test.test.save_screenshot_after_test = self.options.save_screenshot
test.test.visual_baseline = self.options.visual_baseline
test.test.use_wire = self.options.use_wire
test.test.external_pdf = self.options.external_pdf
test.test.timeout_multiplier = self.options.timeout_multiplier
test.test.dashboard = False

View File

@ -281,7 +281,19 @@ setup(
"pillow": [
'Pillow==6.2.2;python_version<"3.6"',
'Pillow==8.4.0;python_version>="3.6" and python_version<"3.7"',
'Pillow==9.2.0;python_version>="3.7"',
'Pillow==9.3.0;python_version>="3.7"',
],
# pip install -e .[selenium-wire]
"selenium-wire": [
'selenium-wire==5.1.0;python_version>="3.7"',
'Brotli==1.0.9;python_version>="3.7"',
'blinker==1.5;python_version>="3.7"',
'h2==4.1.0;python_version>="3.7"',
'hpack==4.0.0;python_version>="3.7"',
'hyperframe==6.0.1;python_version>="3.7"',
'kaitaistruct==0.10;python_version>="3.7"',
'pyasn1==0.4.8;python_version>="3.7"',
'zstandard==0.18.0;python_version>="3.7"',
],
},
packages=[