Skip to content

Commit 9ee27eb

Browse files
authored
Merge pull request #288 from seleniumbase/user-agent-feature
Add the ability to set the User-Agent for the browser
2 parents 41eb330 + 9900a73 commit 9ee27eb

File tree

13 files changed

+134
-49
lines changed

13 files changed

+134
-49
lines changed

Dockerfile

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,6 @@ RUN apt-get -qy --no-install-recommends install \
2020
xvfb \
2121
&& rm -rf /var/lib/apt/lists/*
2222

23-
#========================================
24-
# Add normal user with passwordless sudo
25-
#========================================
26-
#RUN sudo useradd seluser --shell /bin/bash --create-home \
27-
# && sudo usermod -a -G sudo seluser \
28-
# && echo 'ALL ALL = (ALL) NOPASSWD: ALL' >> /etc/sudoers
29-
30-
#======================
31-
# Install Chromedriver
32-
#======================
33-
RUN CHROMEDRIVER_VERSION=`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE` && \
34-
mkdir -p /opt/chromedriver-$CHROMEDRIVER_VERSION && \
35-
curl -sS -o /tmp/chromedriver_linux64.zip http://chromedriver.storage.googleapis.com/$CHROMEDRIVER_VERSION/chromedriver_linux64.zip && \
36-
unzip -qq /tmp/chromedriver_linux64.zip -d /opt/chromedriver-$CHROMEDRIVER_VERSION && \
37-
rm /tmp/chromedriver_linux64.zip && \
38-
chmod +x /opt/chromedriver-$CHROMEDRIVER_VERSION/chromedriver && \
39-
ln -fs /opt/chromedriver-$CHROMEDRIVER_VERSION/chromedriver /usr/local/bin/chromedriver
40-
4123
#================
4224
# Install Chrome
4325
#================
@@ -67,15 +49,6 @@ RUN apt-get -qy --no-install-recommends install \
6749
&& ln -s /opt/firefox/firefox /usr/bin/firefox \
6850
&& rm -f /tmp/firefox-esr.tar.bz2
6951

70-
#===================
71-
# Install PhantomJS
72-
#===================
73-
# RUN cd /usr/local/share && wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2
74-
# RUN cd /usr/local/share && tar xjf phantomjs-2.1.1-linux-x86_64.tar.bz2
75-
# RUN ln -s /usr/local/share/phantomjs-2.1.1-linux-x86_64/bin/phantomjs /usr/local/share/phantomjs
76-
# RUN ln -s /usr/local/share/phantomjs-2.1.1-linux-x86_64/bin/phantomjs /usr/local/bin/phantomjs
77-
# RUN ln -s /usr/local/share/phantomjs-2.1.1-linux-x86_64/bin/phantomjs /usr/bin/phantomjs
78-
7952
#===========================
8053
# Configure Virtual Display
8154
#===========================
@@ -97,6 +70,8 @@ RUN pip install --upgrade pip
9770
RUN pip install --upgrade setuptools
9871
RUN cd /SeleniumBase && ls && pip install -r requirements.txt --upgrade
9972
RUN cd /SeleniumBase && python setup.py develop
73+
RUN seleniumbase install chromedriver
74+
RUN seleniumbase install geckodriver
10075

10176
#==========================================
10277
# Create entrypoint and grab example tests

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,16 @@ To make things easier, you can add your frequently-used proxies to PROXY_LIST in
348348
pytest proxy_test.py --proxy=proxy1
349349
```
350350

351+
352+
### <img src="https://cdn2.hubspot.net/hubfs/100006/images/super_square_logo_3a.png" title="SeleniumBase" height="32"> **Changing the User-Agent:**
353+
354+
If you wish to change the User-Agent for your browser tests (Chrome and Firefox only), you can add ``--agent="USER AGENT STRING"`` as an argument on the command line.
355+
356+
```bash
357+
pytest user_agent_test.py --agent="Mozilla/5.0 (Nintendo 3DS; U; ; en) Version/1.7412.EU"
358+
```
359+
360+
351361
<a id="utilizing_advanced_features"></a>
352362
### <img src="https://cdn2.hubspot.net/hubfs/100006/images/super_square_logo_3a.png" title="SeleniumBase" height="32"> **Production Environments & Integrations:**
353363

examples/user_agent_test.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import time
2+
from seleniumbase import BaseCase
3+
4+
5+
class MyTestClass(BaseCase):
6+
7+
def test_user_agent(self):
8+
self.open('http://www.whatsmyua.info/')
9+
user_agent = self.get_text("#custom-ua-string")
10+
print("\n\nUser-Agent = %s\n" % user_agent)
11+
print("Displaying User-Agent Info:")
12+
print(self.get_text("#useragent"))
13+
print("\nThe browser will close automatically in 7 seconds...")
14+
time.sleep(7)

help_docs/ReadMe.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
> - [**Installing Python, Pip, & Git**](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/install_python_pip_git.md)
88
> - [**Python Virtual Env Tutorial**](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/virtualenv_instructions.md)
99
> - [**Verify Webdriver Installation**](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/verify_webdriver.md)
10-
> - [**The Command Line Tutorial**](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/command_line.md)
10+
> - [**The Command Line Tutorial**](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/customizing_test_runs.md)
11+
> - [**The Console Scripts Tutorial**](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/console_scripts/ReadMe.md)
1112
> - [**SeleniumBase Method Summary**](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/method_summary.md)
1213
> - [**MySQL Installation Overview**](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/mysql_installation.md)
1314
> - [**Safari Driver Detailed Info**](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/using_safari_driver.md)

help_docs/customizing_test_runs.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ In addition to [settings.py](https://github.com/seleniumbase/SeleniumBase/blob/m
66
* Choose betweeen pytest & nose unittest runners
77
* Choose whether to enter Debug Mode on failures
88
* Choose additional variables to pass into tests
9+
* Choose the User-Agent for the browser to use
910
* Change the automation speed (with Demo Mode)
1011
* Choose whether to run tests multi-threaded
1112
* Choose whether to retry failing tests
@@ -39,9 +40,11 @@ pytest test_suite.py --reruns 1 --reruns-delay 2
3940

4041
pytest test_suite.py --server=IP_ADDRESS --port=4444
4142

42-
pytest test_suite.py --proxy=IP_ADDRESS:PORT
43+
pytest proxy_test.py --proxy=IP_ADDRESS:PORT
44+
45+
pytest proxy_test.py --proxy=USERNAME:PASSWORD@IP_ADDRESS:PORT
4346

44-
pytest test_suite.py --proxy=USERNAME:PASSWORD@IP_ADDRESS:PORT
47+
pytest user_agent_test.py --agent="USER-AGENT STRING"
4548

4649
pytest test_fail.py --pdb -s
4750
```
@@ -178,3 +181,11 @@ To make things easier, you can add your frequently-used proxies to PROXY_LIST in
178181
```bash
179182
pytest proxy_test.py --proxy=proxy1
180183
```
184+
185+
#### **Changing the User-Agent:**
186+
187+
If you wish to change the User-Agent for your browser tests (Chrome and Firefox only), you can add ``--agent="USER-AGENT STRING"`` as an argument on the command line.
188+
189+
```bash
190+
pytest user_agent_test.py --agent="Mozilla/5.0 (Nintendo 3DS; U; ; en) Version/1.7412.EU"
191+
```

integrations/docker/run_docker_test_in_chrome.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
set -e
33
# Run example test from inside Docker image
44
echo "Running example SeleniumBase test from Docker with headless Chrome..."
5-
cd /SeleniumBase/examples/ && nosetests my_first_test.py --config=docker_config.cfg --browser=chrome --headless
5+
cd /SeleniumBase/examples/ && pytest my_first_test.py --browser=chrome --headless
66
exec "$@"

integrations/docker/run_docker_test_in_firefox.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
set -e
33
# Run example test from inside Docker image
44
echo "Running example SeleniumBase test from Docker with headless Firefox..."
5-
cd /SeleniumBase/examples/ && nosetests my_first_test.py --config=docker_config.cfg --browser=firefox --headless
5+
cd /SeleniumBase/examples/ && pytest my_first_test.py --browser=firefox --headless
66
exec "$@"

seleniumbase/core/browser_launcher.py

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ def _add_chrome_proxy_extension(
8383

8484

8585
def _set_chrome_options(
86-
downloads_path, proxy_string, proxy_auth, proxy_user, proxy_pass):
86+
downloads_path, proxy_string, proxy_auth,
87+
proxy_user, proxy_pass, user_agent):
8788
chrome_options = webdriver.ChromeOptions()
8889
prefs = {
8990
"download.default_directory": downloads_path,
@@ -100,6 +101,8 @@ def _set_chrome_options(
100101
chrome_options.add_argument("--allow-file-access-from-files")
101102
chrome_options.add_argument("--allow-insecure-localhost")
102103
chrome_options.add_argument("--allow-running-insecure-content")
104+
if user_agent:
105+
chrome_options.add_argument("--user-agent=%s" % user_agent)
103106
chrome_options.add_argument("--disable-infobars")
104107
chrome_options.add_argument("--disable-save-password-bubble")
105108
chrome_options.add_argument("--disable-single-click-autofill")
@@ -113,7 +116,7 @@ def _set_chrome_options(
113116
return chrome_options
114117

115118

116-
def _create_firefox_profile(downloads_path, proxy_string):
119+
def _create_firefox_profile(downloads_path, proxy_string, user_agent):
117120
profile = webdriver.FirefoxProfile()
118121
profile.accept_untrusted_certs = True
119122
profile.set_preference("reader.parse-on-load.enabled", False)
@@ -128,6 +131,8 @@ def _create_firefox_profile(downloads_path, proxy_string):
128131
profile.set_preference("network.proxy.http_port", int(proxy_port))
129132
profile.set_preference("network.proxy.ssl", proxy_server)
130133
profile.set_preference("network.proxy.ssl_port", int(proxy_port))
134+
if user_agent:
135+
profile.set_preference("general.useragent.override", user_agent)
131136
profile.set_preference(
132137
"security.mixed_content.block_active_content", False)
133138
profile.set_preference("security.csp.enable", False)
@@ -195,7 +200,7 @@ def validate_proxy_string(proxy_string):
195200

196201
def get_driver(browser_name, headless=False, use_grid=False,
197202
servername='localhost', port=4444, proxy_string=None,
198-
cap_file=None):
203+
user_agent=None, cap_file=None):
199204
proxy_auth = False
200205
proxy_user = None
201206
proxy_pass = None
@@ -224,27 +229,26 @@ def get_driver(browser_name, headless=False, use_grid=False,
224229
if use_grid:
225230
return get_remote_driver(
226231
browser_name, headless, servername, port, proxy_string, proxy_auth,
227-
proxy_user, proxy_pass, cap_file)
232+
proxy_user, proxy_pass, user_agent, cap_file)
228233
else:
229234
return get_local_driver(
230235
browser_name, headless, proxy_string, proxy_auth,
231-
proxy_user, proxy_pass)
236+
proxy_user, proxy_pass, user_agent)
232237

233238

234239
def get_remote_driver(
235240
browser_name, headless, servername, port, proxy_string, proxy_auth,
236-
proxy_user, proxy_pass, cap_file):
241+
proxy_user, proxy_pass, user_agent, cap_file):
237242
downloads_path = download_helper.get_downloads_folder()
238243
download_helper.reset_downloads_folder()
239244
address = "http://%s:%s/wd/hub" % (servername, port)
240245
desired_caps = {}
241246
if cap_file:
242247
desired_caps = capabilities_parser.get_desired_capabilities(cap_file)
243-
244248
if browser_name == constants.Browser.GOOGLE_CHROME:
245249
chrome_options = _set_chrome_options(
246250
downloads_path, proxy_string, proxy_auth,
247-
proxy_user, proxy_pass)
251+
proxy_user, proxy_pass, user_agent)
248252
if headless:
249253
if not proxy_auth:
250254
# Headless Chrome doesn't support extensions, which are
@@ -264,7 +268,8 @@ def get_remote_driver(
264268
elif browser_name == constants.Browser.FIREFOX:
265269
try:
266270
# Use Geckodriver for Firefox if it's on the PATH
267-
profile = _create_firefox_profile(downloads_path, proxy_string)
271+
profile = _create_firefox_profile(
272+
downloads_path, proxy_string, user_agent)
268273
firefox_capabilities = DesiredCapabilities.FIREFOX.copy()
269274
firefox_capabilities['marionette'] = True
270275
if headless:
@@ -280,7 +285,8 @@ def get_remote_driver(
280285
browser_profile=profile)
281286
except WebDriverException:
282287
# Don't use Geckodriver: Only works for old versions of Firefox
283-
profile = _create_firefox_profile(downloads_path, proxy_string)
288+
profile = _create_firefox_profile(
289+
downloads_path, proxy_string, user_agent)
284290
firefox_capabilities = DesiredCapabilities.FIREFOX.copy()
285291
firefox_capabilities['marionette'] = False
286292
if headless:
@@ -360,7 +366,7 @@ def get_remote_driver(
360366

361367
def get_local_driver(
362368
browser_name, headless, proxy_string, proxy_auth,
363-
proxy_user, proxy_pass):
369+
proxy_user, proxy_pass, user_agent):
364370
'''
365371
Spins up a new web browser and returns the driver.
366372
Can also be used to spin up additional browsers for the same test.
@@ -372,7 +378,8 @@ def get_local_driver(
372378
try:
373379
try:
374380
# Use Geckodriver for Firefox if it's on the PATH
375-
profile = _create_firefox_profile(downloads_path, proxy_string)
381+
profile = _create_firefox_profile(
382+
downloads_path, proxy_string, user_agent)
376383
firefox_capabilities = DesiredCapabilities.FIREFOX.copy()
377384
firefox_capabilities['marionette'] = True
378385
options = webdriver.FirefoxOptions()
@@ -392,7 +399,8 @@ def get_local_driver(
392399
options=options)
393400
except WebDriverException:
394401
# Don't use Geckodriver: Only works for old versions of Firefox
395-
profile = _create_firefox_profile(downloads_path, proxy_string)
402+
profile = _create_firefox_profile(
403+
downloads_path, proxy_string, user_agent)
396404
firefox_capabilities = DesiredCapabilities.FIREFOX.copy()
397405
firefox_capabilities['marionette'] = False
398406
firefox_driver = webdriver.Firefox(
@@ -451,7 +459,7 @@ def get_local_driver(
451459
try:
452460
chrome_options = _set_chrome_options(
453461
downloads_path, proxy_string, proxy_auth,
454-
proxy_user, proxy_pass)
462+
proxy_user, proxy_pass, user_agent)
455463
if headless:
456464
# Headless Chrome doesn't support extensions, which are
457465
# required when using a proxy server that has authentication.

seleniumbase/fixtures/base_case.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2348,8 +2348,8 @@ def save_screenshot(self, name, folder=None):
23482348
return page_actions.save_screenshot(self.driver, name, folder)
23492349

23502350
def get_new_driver(self, browser=None, headless=None,
2351-
servername=None, port=None, proxy=None, switch_to=True,
2352-
cap_file=None):
2351+
servername=None, port=None, proxy=None, agent=None,
2352+
switch_to=True, cap_file=None):
23532353
""" This method spins up an extra browser for tests that require
23542354
more than one. The first browser is already provided by tests
23552355
that import base_case.BaseCase from seleniumbase. If parameters
@@ -2399,6 +2399,9 @@ def get_new_driver(self, browser=None, headless=None,
23992399
proxy_string = proxy
24002400
if proxy_string is None:
24012401
proxy_string = self.proxy_string
2402+
user_agent = agent
2403+
if user_agent is None:
2404+
user_agent = self.user_agent
24022405
if cap_file is None:
24032406
cap_file = self.cap_file
24042407
valid_browsers = constants.ValidBrowsers.valid_browsers
@@ -2413,6 +2416,7 @@ def get_new_driver(self, browser=None, headless=None,
24132416
servername=servername,
24142417
port=port,
24152418
proxy_string=proxy_string,
2419+
user_agent=user_agent,
24162420
cap_file=cap_file)
24172421
self._drivers_list.append(new_driver)
24182422
if switch_to:
@@ -2776,6 +2780,7 @@ def setUp(self):
27762780
self.servername = sb_config.servername
27772781
self.port = sb_config.port
27782782
self.proxy_string = sb_config.proxy_string
2783+
self.user_agent = sb_config.user_agent
27792784
self.cap_file = sb_config.cap_file
27802785
self.database_env = sb_config.database_env
27812786
self.message_duration = sb_config.message_duration
@@ -2846,6 +2851,7 @@ def setUp(self):
28462851
servername=self.servername,
28472852
port=self.port,
28482853
proxy=self.proxy_string,
2854+
agent=self.user_agent,
28492855
switch_to=True,
28502856
cap_file=self.cap_file)
28512857
self._default_driver = self.driver

seleniumbase/plugins/pytest_plugin.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ def pytest_addoption(parser):
9797
username:password@servername:port OR
9898
A dict key from proxy_list.PROXY_LIST
9999
Default: None.""")
100+
parser.addoption('--agent', action='store',
101+
dest='user_agent',
102+
default=None,
103+
help="""Designates the User-Agent for the browser to use.
104+
Format: A string.
105+
Default: None.""")
100106
parser.addoption('--headless', action="store_true",
101107
dest='headless',
102108
default=False,
@@ -155,6 +161,7 @@ def pytest_configure(config):
155161
sb_config.data = config.getoption('data')
156162
sb_config.environment = config.getoption('environment')
157163
sb_config.with_selenium = config.getoption('with_selenium')
164+
sb_config.user_agent = config.getoption('user_agent')
158165
sb_config.headless = config.getoption('headless')
159166
sb_config.with_testing_base = config.getoption('with_testing_base')
160167
sb_config.with_db_reporting = config.getoption('with_db_reporting')

0 commit comments

Comments
 (0)