Skip to content

Commit 4361e22

Browse files
committed
Add a command line option to set a proxy server for tests to use.
1 parent 45f6731 commit 4361e22

File tree

5 files changed

+104
-16
lines changed

5 files changed

+104
-16
lines changed

seleniumbase/config/proxy_list.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""
2+
Proxy Server "Phone Book".
3+
4+
Simplify running browser tests through a proxy server
5+
by adding your frequently-used proxies here.
6+
7+
Now you can do something like this on the command line:
8+
"pytest SOME_TEST.py --proxy=proxy1"
9+
10+
Format of PROXY_LIST server entries:
11+
* "ip_address:port"
12+
13+
Example proxies in PROXY_LIST below are not guaranteed to be active or secure.
14+
If you don't already have a proxy server to connect to,
15+
you can try finding one from one of following sites:
16+
* https://hidemy.name/en/proxy-list/?country=US&type=h#list
17+
* http://proxyservers.pro/proxy/list/protocol/http/country/US/
18+
"""
19+
20+
PROXY_LIST = {
21+
# "example1": "35.196.26.166:3128", # (Example) - set your own proxy here
22+
# "example2": "208.95.62.81:3128", # (Example) - set your own proxy here
23+
"proxy1": None,
24+
"proxy2": None,
25+
"proxy3": None,
26+
"proxy4": None,
27+
"proxy5": None,
28+
}

seleniumbase/core/browser_launcher.py

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
1+
import re
12
import warnings
23
from selenium import webdriver
34
from selenium.common.exceptions import WebDriverException
45
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
56
from seleniumbase.config import settings
7+
from seleniumbase.config import proxy_list
68
from seleniumbase.core import download_helper
79
from seleniumbase.fixtures import constants
810

911

10-
def _create_firefox_profile(downloads_path):
12+
def _create_firefox_profile(downloads_path, proxy_string):
1113
profile = webdriver.FirefoxProfile()
1214
profile.set_preference("reader.parse-on-load.enabled", False)
1315
profile.set_preference("pdfjs.disabled", True)
16+
if proxy_string:
17+
proxy_server = proxy_string.split(':')[0]
18+
proxy_port = proxy_string.split(':')[1]
19+
profile.set_preference("network.proxy.type", 1)
20+
profile.set_preference("network.proxy.http", proxy_server)
21+
profile.set_preference("network.proxy.http_port", int(proxy_port))
22+
profile.set_preference("network.proxy.ssl", proxy_server)
23+
profile.set_preference("network.proxy.ssl_port", int(proxy_port))
1424
profile.set_preference(
1525
"security.mixed_content.block_active_content", False)
1626
profile.set_preference(
@@ -30,15 +40,43 @@ def _create_firefox_profile(downloads_path):
3040
return profile
3141

3242

43+
def display_proxy_warning(proxy_string):
44+
message = ('\n\nWARNING: Proxy String ["%s"] is NOT in the expected '
45+
'"ip_address:port" format, (OR the key does not exist '
46+
'in proxy_list.PROXY_LIST). '
47+
'*** DEFAULTING to NOT USING a Proxy Server! ***'
48+
% proxy_string)
49+
warnings.simplefilter('always', Warning) # See Warnings
50+
warnings.warn(message, category=Warning, stacklevel=2)
51+
warnings.simplefilter('default', Warning) # Set Default
52+
53+
54+
def validate_proxy_string(proxy_string):
55+
if proxy_string in proxy_list.PROXY_LIST.keys():
56+
proxy_string = proxy_list.PROXY_LIST[proxy_string]
57+
if not proxy_string:
58+
return None
59+
valid = re.match('^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$', proxy_string)
60+
if valid:
61+
proxy_string = valid.group()
62+
else:
63+
display_proxy_warning(proxy_string)
64+
proxy_string = None
65+
return proxy_string
66+
67+
3368
def get_driver(browser_name, headless=False, use_grid=False,
34-
servername='localhost', port=4444):
69+
servername='localhost', port=4444, proxy_string=None):
70+
if proxy_string:
71+
proxy_string = validate_proxy_string(proxy_string)
3572
if use_grid:
36-
return get_remote_driver(browser_name, headless, servername, port)
73+
return get_remote_driver(
74+
browser_name, headless, servername, port, proxy_string)
3775
else:
38-
return get_local_driver(browser_name, headless)
76+
return get_local_driver(browser_name, headless, proxy_string)
3977

4078

41-
def get_remote_driver(browser_name, headless, servername, port):
79+
def get_remote_driver(browser_name, headless, servername, port, proxy_string):
4280
downloads_path = download_helper.get_downloads_folder()
4381
download_helper.reset_downloads_folder()
4482
address = "http://%s:%s/wd/hub" % (servername, port)
@@ -58,6 +96,8 @@ def get_remote_driver(browser_name, headless, servername, port):
5896
chrome_options.add_argument("--disable-infobars")
5997
if headless:
6098
chrome_options.add_argument("--headless")
99+
if proxy_string:
100+
chrome_options.add_argument('--proxy-server=%s' % proxy_string)
61101
if settings.START_CHROME_IN_FULL_SCREEN_MODE:
62102
# Run Chrome in full screen mode on WINDOWS
63103
chrome_options.add_argument("--start-maximized")
@@ -71,7 +111,7 @@ def get_remote_driver(browser_name, headless, servername, port):
71111
if browser_name == constants.Browser.FIREFOX:
72112
try:
73113
# Use Geckodriver for Firefox if it's on the PATH
74-
profile = _create_firefox_profile(downloads_path)
114+
profile = _create_firefox_profile(downloads_path, proxy_string)
75115
firefox_capabilities = DesiredCapabilities.FIREFOX.copy()
76116
firefox_capabilities['marionette'] = True
77117
if headless:
@@ -85,7 +125,7 @@ def get_remote_driver(browser_name, headless, servername, port):
85125
browser_profile=profile)
86126
except WebDriverException:
87127
# Don't use Geckodriver: Only works for old versions of Firefox
88-
profile = _create_firefox_profile(downloads_path)
128+
profile = _create_firefox_profile(downloads_path, proxy_string)
89129
firefox_capabilities = DesiredCapabilities.FIREFOX.copy()
90130
firefox_capabilities['marionette'] = False
91131
if headless:
@@ -122,7 +162,7 @@ def get_remote_driver(browser_name, headless, servername, port):
122162
webdriver.DesiredCapabilities.PHANTOMJS))
123163

124164

125-
def get_local_driver(browser_name, headless):
165+
def get_local_driver(browser_name, headless, proxy_string):
126166
'''
127167
Spins up a new web browser and returns the driver.
128168
Can also be used to spin up additional browsers for the same test.
@@ -134,7 +174,7 @@ def get_local_driver(browser_name, headless):
134174
try:
135175
try:
136176
# Use Geckodriver for Firefox if it's on the PATH
137-
profile = _create_firefox_profile(downloads_path)
177+
profile = _create_firefox_profile(downloads_path, proxy_string)
138178
firefox_capabilities = DesiredCapabilities.FIREFOX.copy()
139179
firefox_capabilities['marionette'] = True
140180
options = webdriver.FirefoxOptions()
@@ -145,7 +185,7 @@ def get_local_driver(browser_name, headless):
145185
firefox_options=options)
146186
except WebDriverException:
147187
# Don't use Geckodriver: Only works for old versions of Firefox
148-
profile = _create_firefox_profile(downloads_path)
188+
profile = _create_firefox_profile(downloads_path, proxy_string)
149189
firefox_capabilities = DesiredCapabilities.FIREFOX.copy()
150190
firefox_capabilities['marionette'] = False
151191
firefox_driver = webdriver.Firefox(
@@ -182,12 +222,14 @@ def get_local_driver(browser_name, headless):
182222
chrome_options.add_argument("--disable-infobars")
183223
if headless:
184224
chrome_options.add_argument("--headless")
225+
if proxy_string:
226+
chrome_options.add_argument('--proxy-server=%s' % proxy_string)
185227
if settings.START_CHROME_IN_FULL_SCREEN_MODE:
186228
# Run Chrome in full screen mode on WINDOWS
187229
chrome_options.add_argument("--start-maximized")
188230
# Run Chrome in full screen mode on MAC/Linux
189231
chrome_options.add_argument("--kiosk")
190-
return webdriver.Chrome(chrome_options=chrome_options)
232+
return webdriver.Chrome(options=chrome_options)
191233
except Exception as e:
192234
if headless:
193235
raise Exception(e)

seleniumbase/fixtures/base_case.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1668,6 +1668,7 @@ def setUp(self):
16681668
self.with_page_source = pytest.config.option.with_page_source
16691669
self.servername = pytest.config.option.servername
16701670
self.port = pytest.config.option.port
1671+
self.proxy_string = pytest.config.option.proxy_string
16711672
self.database_env = pytest.config.option.database_env
16721673
self.log_path = pytest.config.option.log_path
16731674
self.browser = pytest.config.option.browser
@@ -1728,7 +1729,8 @@ def setUp(self):
17281729
self.headless,
17291730
self.use_grid,
17301731
self.servername,
1731-
self.port)
1732+
self.port,
1733+
self.proxy_string)
17321734

17331735
def __insert_test_result(self, state, err):
17341736
data_payload = TestcaseDataPayload()

seleniumbase/plugins/pytest_plugin.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,20 @@ def pytest_addoption(parser):
7070
parser.addoption('--server', action='store',
7171
dest='servername',
7272
default='localhost',
73-
help="""Designates the server used by the test.
73+
help="""Designates the Selenium Grid server to use.
7474
Default: localhost.""")
7575
parser.addoption('--port', action='store',
7676
dest='port',
7777
default='4444',
78-
help="""Designates the port used by the test.
78+
help="""Designates the Selenium Grid port to use.
7979
Default: 4444.""")
80+
parser.addoption('--proxy', action='store',
81+
dest='proxy_string',
82+
default=None,
83+
help="""Designates the proxy server:port to use.
84+
Format: servername:port. OR
85+
A dict key from proxy_list.PROXY_LIST
86+
Default: None.""")
8087
parser.addoption('--headless', action="store_true",
8188
dest='headless',
8289
default=False,

seleniumbase/plugins/selenium_plugin.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,21 @@ def options(self, parser, env):
4646
parser.add_option(
4747
'--server', action='store', dest='servername',
4848
default='localhost',
49-
help="""Designates the server used by the test.
49+
help="""Designates the Selenium Grid server to use.
5050
Default: localhost.""")
5151
parser.add_option(
5252
'--port', action='store', dest='port',
5353
default='4444',
54-
help="""Designates the port used by the test.
54+
help="""Designates the Selenium Grid port to use.
5555
Default: 4444.""")
56+
parser.add_option(
57+
'--proxy', action='store',
58+
dest='proxy_string',
59+
default=None,
60+
help="""Designates the proxy server:port to use.
61+
Format: servername:port. OR
62+
A dict key from proxy_list.PROXY_LIST
63+
Default: None.""")
5664
parser.add_option(
5765
'--headless', action="store_true",
5866
dest='headless',
@@ -102,6 +110,7 @@ def beforeTest(self, test):
102110
test.test.headless = self.options.headless
103111
test.test.servername = self.options.servername
104112
test.test.port = self.options.port
113+
test.test.proxy_string = self.options.proxy_string
105114
test.test.demo_mode = self.options.demo_mode
106115
test.test.demo_sleep = self.options.demo_sleep
107116
test.test.highlights = self.options.highlights

0 commit comments

Comments
 (0)