Skip to content

Commit 4553a90

Browse files
authored
Merge pull request #300 from seleniumbase/more-control-over-csp
Add a command-line option to disable the Content Security Policy
2 parents 0d17e9b + 65b2093 commit 4553a90

File tree

10 files changed

+69
-25
lines changed

10 files changed

+69
-25
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ report_archives
6161
archived_reports
6262
html_report.html
6363
report.html
64+
report.xml
6465

6566
# Tours
6667
tours_exported

examples/raw_parameter_script.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
b.database_env = "test"
3737
b.log_path = "latest_logs/"
3838
b.archive_logs = False
39+
b.disable_csp = False
3940
b.save_screenshot_after_test = False
4041
b.timeout_multiplier = None
4142
b.with_db_reporting = False

seleniumbase/config/settings.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,20 @@
6767
# Messenger notifications appear when reaching assert statements in Demo Mode.
6868
DEFAULT_MESSAGE_DURATION = 2.55
6969

70-
# If True, the Content Security Policy will be disabled on Chrome and Firefox.
70+
# If True, the Content Security Policy will be disabled on Firefox.
7171
# If False, each website's default Content Security Policy will be used.
7272
# (A website's CSP may prevent SeleniumBase from loading custom JavaScript.)
73-
DISABLE_CONTENT_SECURITY_POLICY = True
73+
# If using demo_mode or MasterQA, this value will become True regardless.
74+
# You can also disable the CSP on the command line by using "--disable_csp".
75+
DISABLE_CSP_ON_FIREFOX = True
76+
77+
# If True, the Content Security Policy will be disabled on Chrome.
78+
# If False, each website's default Content Security Policy will be used.
79+
# (A website's CSP may prevent SeleniumBase from loading custom JavaScript.)
80+
# If using demo_mode or MasterQA, this value will become True regardless,
81+
# with the exception of running in headless mode, in which case it'll be False.
82+
# You can also disable the CSP on the command line by using "--disable_csp".
83+
DISABLE_CSP_ON_CHROME = False
7484

7585
# If True, an Exception is raised immediately for invalid proxy string syntax.
7686
# If False, a Warning will appear after the test, with no proxy server used.

seleniumbase/core/browser_launcher.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ def _add_chrome_disable_csp_extension(chrome_options):
9595

9696
def _set_chrome_options(
9797
downloads_path, headless, proxy_string, proxy_auth,
98-
proxy_user, proxy_pass, user_agent):
98+
proxy_user, proxy_pass, user_agent, disable_csp):
9999
chrome_options = webdriver.ChromeOptions()
100100
prefs = {
101101
"download.default_directory": downloads_path,
@@ -119,7 +119,7 @@ def _set_chrome_options(
119119
chrome_options.add_argument("--disable-single-click-autofill")
120120
chrome_options.add_argument("--disable-translate")
121121
chrome_options.add_argument("--disable-web-security")
122-
if settings.DISABLE_CONTENT_SECURITY_POLICY and not headless:
122+
if (settings.DISABLE_CSP_ON_CHROME or disable_csp) and not headless:
123123
# Headless Chrome doesn't support extensions, which are required
124124
# for disabling the Content Security Policy on Chrome
125125
chrome_options = _add_chrome_disable_csp_extension(chrome_options)
@@ -131,7 +131,8 @@ def _set_chrome_options(
131131
return chrome_options
132132

133133

134-
def _create_firefox_profile(downloads_path, proxy_string, user_agent):
134+
def _create_firefox_profile(
135+
downloads_path, proxy_string, user_agent, disable_csp):
135136
profile = webdriver.FirefoxProfile()
136137
profile.accept_untrusted_certs = True
137138
profile.set_preference("reader.parse-on-load.enabled", False)
@@ -150,7 +151,7 @@ def _create_firefox_profile(downloads_path, proxy_string, user_agent):
150151
profile.set_preference("general.useragent.override", user_agent)
151152
profile.set_preference(
152153
"security.mixed_content.block_active_content", False)
153-
if settings.DISABLE_CONTENT_SECURITY_POLICY:
154+
if settings.DISABLE_CSP_ON_FIREFOX or disable_csp:
154155
profile.set_preference("security.csp.enable", False)
155156
profile.set_preference(
156157
"browser.download.manager.showAlertOnComplete", False)
@@ -216,7 +217,7 @@ def validate_proxy_string(proxy_string):
216217

217218
def get_driver(browser_name, headless=False, use_grid=False,
218219
servername='localhost', port=4444, proxy_string=None,
219-
user_agent=None, cap_file=None):
220+
user_agent=None, cap_file=None, disable_csp=None):
220221
proxy_auth = False
221222
proxy_user = None
222223
proxy_pass = None
@@ -245,16 +246,16 @@ def get_driver(browser_name, headless=False, use_grid=False,
245246
if use_grid:
246247
return get_remote_driver(
247248
browser_name, headless, servername, port, proxy_string, proxy_auth,
248-
proxy_user, proxy_pass, user_agent, cap_file)
249+
proxy_user, proxy_pass, user_agent, cap_file, disable_csp)
249250
else:
250251
return get_local_driver(
251252
browser_name, headless, proxy_string, proxy_auth,
252-
proxy_user, proxy_pass, user_agent)
253+
proxy_user, proxy_pass, user_agent, disable_csp)
253254

254255

255256
def get_remote_driver(
256257
browser_name, headless, servername, port, proxy_string, proxy_auth,
257-
proxy_user, proxy_pass, user_agent, cap_file):
258+
proxy_user, proxy_pass, user_agent, cap_file, disable_csp):
258259
downloads_path = download_helper.get_downloads_folder()
259260
download_helper.reset_downloads_folder()
260261
address = "http://%s:%s/wd/hub" % (servername, port)
@@ -264,7 +265,7 @@ def get_remote_driver(
264265
if browser_name == constants.Browser.GOOGLE_CHROME:
265266
chrome_options = _set_chrome_options(
266267
downloads_path, headless, proxy_string, proxy_auth,
267-
proxy_user, proxy_pass, user_agent)
268+
proxy_user, proxy_pass, user_agent, disable_csp)
268269
if headless:
269270
if not proxy_auth:
270271
# Headless Chrome doesn't support extensions, which are
@@ -285,7 +286,7 @@ def get_remote_driver(
285286
try:
286287
# Use Geckodriver for Firefox if it's on the PATH
287288
profile = _create_firefox_profile(
288-
downloads_path, proxy_string, user_agent)
289+
downloads_path, proxy_string, user_agent, disable_csp)
289290
firefox_capabilities = DesiredCapabilities.FIREFOX.copy()
290291
firefox_capabilities['marionette'] = True
291292
if headless:
@@ -302,7 +303,7 @@ def get_remote_driver(
302303
except WebDriverException:
303304
# Don't use Geckodriver: Only works for old versions of Firefox
304305
profile = _create_firefox_profile(
305-
downloads_path, proxy_string, user_agent)
306+
downloads_path, proxy_string, user_agent, disable_csp)
306307
firefox_capabilities = DesiredCapabilities.FIREFOX.copy()
307308
firefox_capabilities['marionette'] = False
308309
if headless:
@@ -382,7 +383,7 @@ def get_remote_driver(
382383

383384
def get_local_driver(
384385
browser_name, headless, proxy_string, proxy_auth,
385-
proxy_user, proxy_pass, user_agent):
386+
proxy_user, proxy_pass, user_agent, disable_csp):
386387
'''
387388
Spins up a new web browser and returns the driver.
388389
Can also be used to spin up additional browsers for the same test.
@@ -395,7 +396,7 @@ def get_local_driver(
395396
try:
396397
# Use Geckodriver for Firefox if it's on the PATH
397398
profile = _create_firefox_profile(
398-
downloads_path, proxy_string, user_agent)
399+
downloads_path, proxy_string, user_agent, disable_csp)
399400
firefox_capabilities = DesiredCapabilities.FIREFOX.copy()
400401
firefox_capabilities['marionette'] = True
401402
options = webdriver.FirefoxOptions()
@@ -416,7 +417,7 @@ def get_local_driver(
416417
except WebDriverException:
417418
# Don't use Geckodriver: Only works for old versions of Firefox
418419
profile = _create_firefox_profile(
419-
downloads_path, proxy_string, user_agent)
420+
downloads_path, proxy_string, user_agent, disable_csp)
420421
firefox_capabilities = DesiredCapabilities.FIREFOX.copy()
421422
firefox_capabilities['marionette'] = False
422423
firefox_driver = webdriver.Firefox(
@@ -475,7 +476,7 @@ def get_local_driver(
475476
try:
476477
chrome_options = _set_chrome_options(
477478
downloads_path, headless, proxy_string, proxy_auth,
478-
proxy_user, proxy_pass, user_agent)
479+
proxy_user, proxy_pass, user_agent, disable_csp)
479480
if headless:
480481
# Headless Chrome doesn't support extensions, which are
481482
# required when using a proxy server that has authentication.

seleniumbase/fixtures/base_case.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2405,7 +2405,7 @@ def save_screenshot(self, name, folder=None):
24052405

24062406
def get_new_driver(self, browser=None, headless=None,
24072407
servername=None, port=None, proxy=None, agent=None,
2408-
switch_to=True, cap_file=None):
2408+
switch_to=True, cap_file=None, disable_csp=None):
24092409
""" This method spins up an extra browser for tests that require
24102410
more than one. The first browser is already provided by tests
24112411
that import base_case.BaseCase from seleniumbase. If parameters
@@ -2458,6 +2458,10 @@ def get_new_driver(self, browser=None, headless=None,
24582458
user_agent = agent
24592459
if user_agent is None:
24602460
user_agent = self.user_agent
2461+
if disable_csp is None:
2462+
disable_csp = self.disable_csp
2463+
if self.demo_mode or self.masterqa_mode:
2464+
disable_csp = True
24612465
if cap_file is None:
24622466
cap_file = self.cap_file
24632467
valid_browsers = constants.ValidBrowsers.valid_browsers
@@ -2473,7 +2477,8 @@ def get_new_driver(self, browser=None, headless=None,
24732477
port=port,
24742478
proxy_string=proxy_string,
24752479
user_agent=user_agent,
2476-
cap_file=cap_file)
2480+
cap_file=cap_file,
2481+
disable_csp=disable_csp)
24772482
self._drivers_list.append(new_driver)
24782483
if switch_to:
24792484
self.driver = new_driver
@@ -2798,12 +2803,13 @@ def __highlight_with_jquery_2(self, message, selector, o_bs):
27982803

27992804
############
28002805

2801-
def setUp(self):
2806+
def setUp(self, masterqa_mode=False):
28022807
"""
28032808
Be careful if a subclass of BaseCase overrides setUp()
28042809
You'll need to add the following line to the subclass setUp() method:
28052810
super(SubClassOfBaseCase, self).setUp()
28062811
"""
2812+
self.masterqa_mode = masterqa_mode
28072813
self.is_pytest = None
28082814
try:
28092815
# This raises an exception if the test is not coming from pytest
@@ -2843,6 +2849,7 @@ def setUp(self):
28432849
self.js_checking_on = sb_config.js_checking_on
28442850
self.ad_block_on = sb_config.ad_block_on
28452851
self.verify_delay = sb_config.verify_delay
2852+
self.disable_csp = sb_config.disable_csp
28462853
self.save_screenshot_after_test = sb_config.save_screenshot
28472854
self.timeout_multiplier = sb_config.timeout_multiplier
28482855
self.use_grid = False
@@ -2910,7 +2917,8 @@ def setUp(self):
29102917
proxy=self.proxy_string,
29112918
agent=self.user_agent,
29122919
switch_to=True,
2913-
cap_file=self.cap_file)
2920+
cap_file=self.cap_file,
2921+
disable_csp=self.disable_csp)
29142922
self._default_driver = self.driver
29152923

29162924
def __insert_test_result(self, state, err):

seleniumbase/fixtures/js_utils.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,9 @@ def activate_jquery(driver):
125125
# Since jQuery still isn't activating, give up and raise an exception
126126
raise Exception(
127127
'''Unable to load jQuery on "%s" due to a possible violation '''
128-
'''of the website's Content Security Policy '''
129-
'''directive. ''' % driver.current_url)
128+
'''of the website's Content Security Policy directive. '''
129+
'''To override this policy, add "--disable_csp" on the '''
130+
'''command-line when running your tests.''' % driver.current_url)
130131

131132

132133
def are_quotes_escaped(string):

seleniumbase/masterqa/master_qa.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ class MasterQA(__MasterQATestCase__):
392392
def setUp(self):
393393
self.check_count = 0
394394
self.auto_close_results_page = False
395-
super(__MasterQATestCase__, self).setUp()
395+
super(__MasterQATestCase__, self).setUp(masterqa_mode=True)
396396
self.manual_check_setup()
397397
if self.headless:
398398
self.auto_close_results_page = True

seleniumbase/plugins/pytest_plugin.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,15 @@ def pytest_addoption(parser):
159159
default=None,
160160
help="""Setting this overrides the default wait time
161161
before each MasterQA verification pop-up.""")
162+
parser.addoption('--disable_csp', action="store_true",
163+
dest='disable_csp',
164+
default=False,
165+
help="""Using this disables the Content Security Policy of
166+
websites, which may interfere with some features of
167+
SeleniumBase, such as loading custom JavaScript
168+
libraries for various testing actions.
169+
Setting this to True (--disable_csp) overrides the
170+
value set in seleniumbase/config/settings.py""")
162171
parser.addoption('--save_screenshot', action='store_true',
163172
dest='save_screenshot',
164173
default=False,
@@ -201,6 +210,7 @@ def pytest_configure(config):
201210
sb_config.js_checking_on = config.getoption('js_checking_on')
202211
sb_config.ad_block_on = config.getoption('ad_block_on')
203212
sb_config.verify_delay = config.getoption('verify_delay')
213+
sb_config.disable_csp = config.getoption('disable_csp')
204214
sb_config.save_screenshot = config.getoption('save_screenshot')
205215
sb_config.timeout_multiplier = config.getoption('timeout_multiplier')
206216

seleniumbase/plugins/selenium_plugin.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class SeleniumBrowser(Plugin):
2828
self.options.js_checking_on -- option to check for js errors (--check_js)
2929
self.options.ad_block -- the option to block some display ads (--ad_block)
3030
self.options.verify_delay -- delay before MasterQA checks (--verify_delay)
31+
self.options.disable_csp -- disable Content Security Policy (--disable_csp)
3132
self.options.save_screenshot -- save screen after test (--save_screenshot)
3233
self.options.timeout_multiplier -- increase defaults (--timeout_multiplier)
3334
"""
@@ -127,6 +128,16 @@ def options(self, parser, env):
127128
dest='verify_delay', default=None,
128129
help="""Setting this overrides the default wait time
129130
before each MasterQA verification pop-up.""")
131+
parser.add_option(
132+
'--disable_csp', action="store_true",
133+
dest='disable_csp',
134+
default=False,
135+
help="""Using this disables the Content Security Policy of
136+
websites, which may interfere with some features of
137+
SeleniumBase, such as loading custom JavaScript
138+
libraries for various testing actions.
139+
Setting this to True (--disable_csp) overrides the
140+
value set in seleniumbase/config/settings.py""")
130141
parser.add_option(
131142
'--save_screenshot', action="store_true",
132143
dest='save_screenshot',
@@ -163,6 +174,7 @@ def beforeTest(self, test):
163174
test.test.js_checking_on = self.options.js_checking_on
164175
test.test.ad_block_on = self.options.ad_block_on
165176
test.test.verify_delay = self.options.verify_delay # MasterQA
177+
test.test.disable_csp = self.options.disable_csp
166178
test.test.save_screenshot_after_test = self.options.save_screenshot
167179
test.test.timeout_multiplier = self.options.timeout_multiplier
168180
test.test.use_grid = False

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
setup(
1919
name='seleniumbase',
20-
version='1.21.8',
20+
version='1.21.9',
2121
description='Reliable Browser Automation & Testing Framework',
2222
long_description=long_description,
2323
long_description_content_type='text/markdown',

0 commit comments

Comments
 (0)