Skip to content
This repository has been archived by the owner on Jan 19, 2024. It is now read-only.

Commit

Permalink
Merge pull request #211 from edx/jmbowman/TE-2663
Browse files Browse the repository at this point in the history
TE-2663 Support headless Chrome and Firefox
  • Loading branch information
jmbowman authored Aug 1, 2018
2 parents 8545c1c + 51ccb30 commit 8938e9c
Show file tree
Hide file tree
Showing 13 changed files with 59 additions and 28 deletions.
10 changes: 4 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,13 @@ branches:
only:
- master
before_install:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
- sleep 3 # give xvfb some time to start
- wget https://github.com/mozilla/geckodriver/releases/download/v0.20.0/geckodriver-v0.20.0-linux64.tar.gz
- wget https://github.com/mozilla/geckodriver/releases/download/v0.21.0/geckodriver-v0.21.0-linux64.tar.gz
- mkdir geckodriver
- tar -xzf geckodriver-v0.20.0-linux64.tar.gz -C geckodriver
- tar -xzf geckodriver-v0.21.0-linux64.tar.gz -C geckodriver
- export PATH=$PATH:$PWD/geckodriver
- export BOKCHOY_HEADLESS=true
addons:
firefox: '59.0.1'
firefox: '61.0.1'
install:
- pip install -r requirements/travis.txt
script:
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
v0.8.1 (08/01/18)
* Support use of headless Chrome and Firefox by setting the BOKCHOY_HEADLESS environment variable to "true"
* Only try to save logs which are available for the browser in use

v0.8.0 (07/18/18)
* Preserve geckodriver log for Firefox test failures
* Better handling of screenshot and log directory settings
Expand Down
7 changes: 6 additions & 1 deletion bok_choy/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def save_driver_logs(driver, prefix):
copyfile(log_path, dest_path)
return

log_types = ['browser', 'driver', 'client', 'server']
log_types = driver.log_types
for log_type in log_types:
try:
log = driver.get_log(log_type)
Expand Down Expand Up @@ -357,6 +357,7 @@ def _local_browser_class(browser_name):

# Get class of local browser based on name
browser_class = BROWSERS.get(browser_name)
headless = os.environ.get('BOKCHOY_HEADLESS', 'false').lower() == 'true'
if browser_class is None:
raise BrowserConfigError(
"Invalid browser name {name}. Options are: {options}".format(
Expand All @@ -370,6 +371,8 @@ def _local_browser_class(browser_name):

firefox_options = FirefoxOptions()
firefox_options.log.level = 'trace'
if headless:
firefox_options.set_headless(True)
browser_args = []
browser_kwargs = {
'firefox_profile': _firefox_profile(),
Expand All @@ -394,6 +397,8 @@ def _local_browser_class(browser_name):

elif browser_name == 'chrome':
chrome_options = ChromeOptions()
if headless:
chrome_options.set_headless(True)

# Emulate webcam and microphone for testing purposes
chrome_options.add_argument('--use-fake-device-for-media-stream')
Expand Down
18 changes: 16 additions & 2 deletions docs/testing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,19 @@ Testing Environment Configuration
Testing via TravisCI
--------------------

``bok-choy`` can be used along with Travis CI to test changes remotely. One way to accomplish this testing is by using the X Virtual Framebuffer (xvfb) to imitate a display. To use xvfb, you'll start it up via a ``before_script`` section in your ``.travis.yml`` file, like this:
``bok-choy`` can be used along with Travis CI to test changes remotely.
One way to accomplish this testing is to use the headless version of Chrome or Firefox.
bok-choy does this when the ``BOKCHOY_HEADLESS`` environment is set to "true".

.. code-block:: yaml
before_script:
- export BOKCHOY_HEADLESS=true
Another option is to use the X Virtual Framebuffer (xvfb) to imitate a display.
Headless versions of Chrome and Firefox are relatively new developments,
so you may want to use xvfb if you encounter a bug with headless browser usage.
To use xvfb, you'll start it up via a ``before_script`` section in your ``.travis.yml`` file, like this:

.. code-block:: yaml
Expand All @@ -23,7 +35,9 @@ Testing via tox

``bok-choy`` can be used along with tox to test against multiple Python virtual environments containing different versions of requirements.

An important detail when using tox in a Travis CI environment: tox passes along only a fixed list of environment variables to each tox-created virtual environment. When using ``bok-choy`` in tox, the DISPLAY environment variable is needed but is not automatically passed-in. The tox.ini file needs to specify the DISPLAY variable like this:
An important detail when using tox in a Travis CI environment: tox passes along only a fixed list of environment variables to each tox-created virtual environment.
When using ``bok-choy`` via xvfb in tox, the DISPLAY environment variable is needed but is not automatically passed-in.
The tox.ini file needs to specify the DISPLAY variable like this:

.. code-block:: yaml
Expand Down
14 changes: 8 additions & 6 deletions requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,15 @@ lazy-object-proxy==1.3.1
lazy==1.3
mccabe==0.6.1
mock==2.0.0
more-itertools==4.2.0
more-itertools==4.3.0
needle==0.5.0
nose==1.3.7
packaging==17.1
pbr==4.1.0
pathlib2==2.3.2
pbr==4.2.0
pillow==5.2.0
pip-tools==2.0.2
pluggy==0.6.0
pluggy==0.7.1
py==1.5.4
pycodestyle==2.4.0
pylint-celery==0.3
Expand All @@ -45,15 +46,16 @@ pylint==1.7.1
pyparsing==2.2.0
pytest-cov==2.5.1
pytest-forked==0.2
pytest-xdist==1.22.2
pytest==3.6.3
pytest-xdist==1.22.5
pytest==3.7.0
requests==2.19.1
scandir==1.7
selenium==3.13.0
singledispatch==3.4.0.3
six==1.11.0
tox-battery==0.5.1
tox-travis==0.10
tox==3.1.1
tox==3.1.2
urllib3==1.23
virtualenv==16.0.0
wrapt==1.10.11
2 changes: 1 addition & 1 deletion requirements/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ requests==2.19.1 # via sphinx
selenium==3.13.0
six==1.11.0
snowballstemmer==1.2.1 # via sphinx
sphinx==1.7.5
sphinx==1.7.6
sphinxcontrib-websupport==1.1.0 # via sphinx
typing==3.6.4 # via sphinx
urllib3==1.23 # via requests
Expand Down
1 change: 1 addition & 0 deletions requirements/test.in
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ futures ; python_version == "2.7" # via isort
mock # For mocking functionality in assorted tests
packaging # For version number parsing and comparisons
pycodestyle # For checking compliance with PEP 8 coding style guidelines
pylint-plugin-utils<0.4 # via pylint-celery, pylint-django; newer versions drop Python 2 support
pytest-cov # For code coverage statistics generation
pytest-xdist # For parallel test execution
14 changes: 8 additions & 6 deletions requirements/test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,26 @@ lazy-object-proxy==1.3.1 # via astroid
lazy==1.3
mccabe==0.6.1 # via pylint
mock==2.0.0
more-itertools==4.2.0 # via pytest
more-itertools==4.3.0 # via pytest
needle==0.5.0
nose==1.3.7
packaging==17.1
pbr==4.1.0 # via mock
pathlib2==2.3.2 # via pytest
pbr==4.2.0 # via mock
pillow==5.2.0
pluggy==0.6.0 # via pytest
pluggy==0.7.1 # via pytest
py==1.5.4 # via pytest
pycodestyle==2.4.0
pylint-celery==0.3 # via edx-lint
pylint-django==0.7.2 # via edx-lint
pylint-plugin-utils==0.3 # via pylint-celery, pylint-django
pylint-plugin-utils==0.3
pylint==1.7.1 # via edx-lint, pylint-celery, pylint-django, pylint-plugin-utils
pyparsing==2.2.0 # via packaging
pytest-cov==2.5.1
pytest-forked==0.2 # via pytest-xdist
pytest-xdist==1.22.2
pytest==3.6.3 # via pytest-cov, pytest-forked, pytest-xdist
pytest-xdist==1.22.5
pytest==3.7.0 # via pytest-cov, pytest-forked, pytest-xdist
scandir==1.7 # via pathlib2
selenium==3.13.0
singledispatch==3.4.0.3 # via astroid, pylint
six==1.11.0
Expand Down
4 changes: 2 additions & 2 deletions requirements/travis.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ codecov==2.0.15
coverage==4.5.1 # via codecov
idna==2.7 # via requests
packaging==17.1 # via tox
pluggy==0.6.0 # via tox
pluggy==0.7.1 # via tox
py==1.5.4 # via tox
pyparsing==2.2.0 # via packaging
requests==2.19.1 # via codecov
six==1.11.0 # via packaging, tox
tox-battery==0.5.1
tox-travis==0.10
tox==3.1.1
tox==3.1.2
urllib3==1.23 # via requests
virtualenv==16.0.0 # via tox
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import sys
from setuptools import setup

VERSION = '0.8.0'
VERSION = '0.8.1'
DESCRIPTION = 'UI-level acceptance test framework'


Expand Down
6 changes: 4 additions & 2 deletions tests/test_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ def test_save_driver_logs_dir_not_set(self, caplog, monkeypatch):
bok_choy.browser.save_driver_logs(browser, 'empty')
assert 'The SELENIUM_DRIVER_LOG_DIR environment variable was not set; not saving logs' in caplog.text

@pytest.mark.skipif(os.environ.get('SELENIUM_BROWSER', 'firefox') != "firefox",
reason="Selenium driver logs are supported on non-firefox browsers")
def test_save_driver_logs_unsupported(self):
browser = self.browser
tempdir_path = self.tempdir_path
Expand Down Expand Up @@ -252,7 +254,7 @@ def test_save_driver_logs(self):

# Check that the files were created.
# Note that the 'client' and 'server' log files will be empty.
log_types = ['browser', 'driver', 'client', 'server']
log_types = browser.log_types
for log_type in log_types:
expected_file = os.path.join(tempdir_path, 'js_page_{}.log'.format(log_type))
assert os.path.isfile(expected_file)
Expand All @@ -270,7 +272,7 @@ def test_save_driver_logs_exception(self, caplog):
bok_choy.browser.save_driver_logs(browser, 'js_page')

# Check that no files were created.
log_types = ['browser', 'driver', 'client', 'server']
log_types = browser.log_types
for log_type in log_types:
expected_file = os.path.join(tempdir_path, 'js_page_{}.log'.format(log_type))
assert not os.path.exists(expected_file)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def test_scroll(self):
self.long_page.scroll_to_element('#element_after_long_part')
# Different browsers, CI systems, and resolutions may present the
# element in varying locations. Use a greater-than instead of an equals.
self.assertGreaterEqual(self._get_window_position(), 1900)
self.assertGreaterEqual(self._get_window_position(), 1800)

def test_scroll_false_element(self):
"""
Expand Down
3 changes: 3 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ deps =
-r{toxinidir}/requirements/test.txt
passenv =
DISPLAY
BOKCHOY_HEADLESS
MOZ_HEADLESS
SELENIUM_BROWSER
setenv =
SCREENSHOT_DIR={toxinidir}/logs
SELENIUM_DRIVER_LOG_DIR={toxinidir}/logs
Expand Down

0 comments on commit 8938e9c

Please sign in to comment.