From 717b8cbb1ad74bb46bd636b04fc2c59c4c7f8bca Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 20 Jan 2016 13:37:58 -0500 Subject: [PATCH 1/9] Brand New Dockerfile --- Dockerfile | 111 ++++++++++++++++++++++++++--------------------------- 1 file changed, 54 insertions(+), 57 deletions(-) diff --git a/Dockerfile b/Dockerfile index 53ff7732205..f1fd953eacf 100755 --- a/Dockerfile +++ b/Dockerfile @@ -1,40 +1,29 @@ # SeleniumBase Docker Image FROM ubuntu:14.04 +#======================================= # Install Python and Basic Python Tools +#======================================= RUN apt-get update && apt-get install -y python python-pip python-setuptools python-dev python-distribute -#======================== -# Miscellaneous packages -# Includes minimal runtime used for executing selenium with firefox -#======================== -ENV BUILD_DEPS '\ - build-essential \ - libmysqlclient-dev \ - libpython-dev \ - libyaml-dev \ - libxml2-dev \ - libxslt1-dev \ - libxslt-dev \ - zlib1g-dev \ - ' - -RUN apt-get update -qqy \ - && apt-get -qy --no-install-recommends install \ - locales \ - language-pack-en \ +#================================= +# Install Bash Command Line Tools +#================================= +RUN apt-get -qy --no-install-recommends install \ sudo \ unzip \ wget \ curl \ vim \ xvfb \ - libaio1 \ - libxml2 \ - libxslt1.1 \ - mysql-client \ - ${BUILD_DEPS} \ - && rm -rf /var/lib/apt/lists/* + && rm -rf /var/lib/apt/lists/* + +#======================================== +# Add normal user with passwordless sudo +#======================================== +RUN sudo useradd seluser --shell /bin/bash --create-home \ + && sudo usermod -a -G sudo seluser \ + && echo 'ALL ALL = (ALL) NOPASSWD: ALL' >> /etc/sudoers #============================== # Locale and encoding settings @@ -44,19 +33,16 @@ ENV LANG ${LANGUAGE} RUN locale-gen ${LANGUAGE} \ && dpkg-reconfigure --frontend noninteractive locales -#==================== -# Firefox Latest ESR -#==================== -RUN apt-get update -qqy \ - && apt-get -qy --no-install-recommends install \ - $(apt-cache depends firefox | grep Depends | sed "s/.*ends:\ //" | tr '\n' ' ') \ - && rm -rf /var/lib/apt/lists/* \ - && cd /tmp \ - && wget --no-check-certificate -O firefox-esr.tar.bz2 \ - 'https://download.mozilla.org/?product=firefox-esr-latest&os=linux64&lang=en-US' \ - && tar -xjf firefox-esr.tar.bz2 -C /opt/ \ - && ln -s /opt/firefox/firefox /usr/bin/firefox \ - && rm -f /tmp/firefox-esr.tar.bz2 +#====================== +# Install Chromedriver +#====================== +RUN CHROMEDRIVER_VERSION=`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE` && \ + mkdir -p /opt/chromedriver-$CHROMEDRIVER_VERSION && \ + curl -sS -o /tmp/chromedriver_linux64.zip http://chromedriver.storage.googleapis.com/$CHROMEDRIVER_VERSION/chromedriver_linux64.zip && \ + unzip -qq /tmp/chromedriver_linux64.zip -d /opt/chromedriver-$CHROMEDRIVER_VERSION && \ + rm /tmp/chromedriver_linux64.zip && \ + chmod +x /opt/chromedriver-$CHROMEDRIVER_VERSION/chromedriver && \ + ln -fs /opt/chromedriver-$CHROMEDRIVER_VERSION/chromedriver /usr/local/bin/chromedriver #================ # Install Chrome @@ -67,22 +53,25 @@ RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key && apt-get install -y google-chrome-stable \ && rm -rf /var/lib/apt/lists/* -#=================== -# Timezone settings -#=================== -# Full list at http://en.wikipedia.org/wiki/List_of_tz_database_time_zones -# e.g. "US/Pacific" for Los Angeles, California, USA -ENV TZ "America/New_York" -# Apply TimeZone -RUN echo $TZ | tee /etc/timezone \ - && dpkg-reconfigure --frontend noninteractive tzdata +#================== +# Configure Chrome +#================== +RUN dpkg-divert --add --rename --divert /opt/google/chrome/google-chrome.real /opt/google/chrome/google-chrome && \ + echo "#!/bin/bash\nexec /opt/google/chrome/google-chrome.real --disable-setuid-sandbox \"\$@\"" > /opt/google/chrome/google-chrome && \ + chmod 755 /opt/google/chrome/google-chrome -#======================================== -# Add normal user with passwordless sudo -#======================================== -RUN sudo useradd seluser --shell /bin/bash --create-home \ - && sudo usermod -a -G sudo seluser \ - && echo 'ALL ALL = (ALL) NOPASSWD: ALL' >> /etc/sudoers +#================= +# Install Firefox +#================= +RUN apt-get -qy --no-install-recommends install \ + $(apt-cache depends firefox | grep Depends | sed "s/.*ends:\ //" | tr '\n' ' ') \ + && rm -rf /var/lib/apt/lists/* \ + && cd /tmp \ + && wget --no-check-certificate -O firefox-esr.tar.bz2 \ + 'https://download.mozilla.org/?product=firefox-esr-latest&os=linux64&lang=en-US' \ + && tar -xjf firefox-esr.tar.bz2 -C /opt/ \ + && ln -s /opt/firefox/firefox /usr/bin/firefox \ + && rm -f /tmp/firefox-esr.tar.bz2 #=================== # Install PhantomJS @@ -93,6 +82,15 @@ RUN ln -s /usr/local/share/phantomjs-1.9.7-linux-x86_64/bin/phantomjs /usr/local RUN ln -s /usr/local/share/phantomjs-1.9.7-linux-x86_64/bin/phantomjs /usr/local/bin/phantomjs RUN ln -s /usr/local/share/phantomjs-1.9.7-linux-x86_64/bin/phantomjs /usr/bin/phantomjs +#=========================== +# Configure Virtual Display +#=========================== +RUN set -e +RUN echo "Starting X virtual framebuffer (Xvfb) in background..." +RUN Xvfb -ac :99 -screen 0 1280x1024x16 > /dev/null 2>&1 & +RUN export DISPLAY=:99 +RUN exec "$@" + #===================== # Set up SeleniumBase #===================== @@ -103,13 +101,12 @@ COPY examples /SeleniumBase/examples/ RUN cd /SeleniumBase && ls && sudo pip install -r docker_requirements.txt RUN cd /SeleniumBase && ls && sudo python docker_setup.py install -#========================================= -# Create entrypoint and grab example test -#========================================= +#========================================== +# Create entrypoint and grab example tests +#========================================== COPY docker/docker-entrypoint.sh / COPY docker/run_docker_test_in_firefox.sh / COPY docker/run_docker_test_in_chrome.sh / -COPY docker/run_docker_test_in_phantomjs.sh / COPY docker/docker_config.cfg /SeleniumBase/examples/ ENTRYPOINT ["/docker-entrypoint.sh"] CMD ["/bin/bash"] From 2a5786b4c21a52a9c43634a4e85c54b2eafe08f8 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 20 Jan 2016 13:39:54 -0500 Subject: [PATCH 2/9] Add pyvirtualdisplay requirement --- requirements.txt | 1 + setup.py | 1 + 2 files changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index 5dcce8a493b..c7244d1c7a9 100755 --- a/requirements.txt +++ b/requirements.txt @@ -11,4 +11,5 @@ simplejson==3.8.1 boto==2.38.0 pdb==0.1 ipdb==0.8.1 +pyvirtualdisplay==0.1.5 -e . diff --git a/setup.py b/setup.py index 3b14a49482b..0bf6e6ec07e 100755 --- a/setup.py +++ b/setup.py @@ -26,6 +26,7 @@ 'simplejson==3.8.1', 'boto==2.38.0', 'ipdb==0.8.1', + 'pyvirtualdisplay==0.1.5', ], packages=['seleniumbase', 'seleniumbase.core', From d5c282e2784a6c5fd7223b79f7072335fb973a22 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 20 Jan 2016 13:41:40 -0500 Subject: [PATCH 3/9] Drop PhantomJS test from Docker due to font issue --- docker/run_docker_test_in_phantomjs.sh | 6 ------ 1 file changed, 6 deletions(-) delete mode 100755 docker/run_docker_test_in_phantomjs.sh diff --git a/docker/run_docker_test_in_phantomjs.sh b/docker/run_docker_test_in_phantomjs.sh deleted file mode 100755 index 7e903e86c54..00000000000 --- a/docker/run_docker_test_in_phantomjs.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -set -e -# Run example test from inside Docker image -echo "Running example SeleniumBase test from Docker with PhantomJS..." -cd /SeleniumBase/examples/ && nosetests my_first_test.py --config=docker_config.cfg --browser=phantomjs -exec "$@" From ede0f02429ae033d5eba9c80251bf8e657feee97 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 20 Jan 2016 13:42:38 -0500 Subject: [PATCH 4/9] Updated Docker ReadMe --- Docker_README.md | 24 ++++++++++++------------ docker/ReadMe.md | 24 ++++++++++++------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/Docker_README.md b/Docker_README.md index 3837a2c012b..2ed9e1e88f8 100755 --- a/Docker_README.md +++ b/Docker_README.md @@ -6,41 +6,41 @@ docker-machine create --driver virtualbox seleniumbase -#### 3. If your Docker environment ever goes down for any reason, you can bring it back up with a restart: +##### (If your Docker environment ever goes down for any reason, you can bring it back up with a restart.) docker-machine restart seleniumbase -#### 4. Configure your shell: +#### 3. Configure your shell: eval "$(docker-machine env seleniumbase)" -#### 5. Go to the SeleniumBase home directory. (That's where "Dockerfile" is located) +#### 4. Go to the SeleniumBase home directory. (That's where "Dockerfile" is located) -#### 6. Create your Docker image from your Dockerfile: (Get ready to wait awhile) +#### 5. Create your Docker image from your Dockerfile: (Get ready to wait awhile) docker build -t seleniumbase . -#### 7. Run a test inside your Docker: (Once the test completes after a few seconds, you'll automatically exit the Docker shell) +#### 6. Run a test inside your Docker: (Once the test completes after a few seconds, you'll automatically exit the Docker shell) docker run seleniumbase ./run_docker_test_in_firefox.sh -#### 8. Now run the same test with Chrome inside your Docker: +#### 7. Now run the same test with Chrome inside your Docker: docker run seleniumbase ./run_docker_test_in_chrome.sh -#### 9. You can also enter Docker and stay inside the shell: +#### 8. You can also enter Docker and stay inside the shell: docker run -i -t seleniumbase -#### 10. Now you can run the example test from inside the Docker shell: (This time with PhantomJS) +#### 9. Now you can run the example test from inside the Docker shell: - ./run_docker_test_in_phantomjs.sh + ./run_docker_test_in_chrome.sh -#### 11. When you're satisfied, you may exit the Docker shell: +#### 10. When you're satisfied, you may exit the Docker shell: exit -#### 12. (Optional) Since Docker images and containers take up a lot of space, you may want to clean up your machine from time to time when they’re not being used: +#### 11. (Optional) Since Docker images and containers take up a lot of space, you may want to clean up your machine from time to time when they’re not being used: http://stackoverflow.com/questions/17236796/how-to-remove-old-docker-containers Here are a few of those cleanup commands: @@ -57,7 +57,7 @@ Finally, if you want to wipe out your SeleniumBase Docker virtualbox, use these docker-machine kill seleniumbase docker-machine rm seleniumbase -#### 13. (Optional) More reading on Docker can be found here: +#### 12. (Optional) More reading on Docker can be found here: * https://docs.docker.com * https://docs.docker.com/mac/started/ * https://docs.docker.com/installation/mac/ diff --git a/docker/ReadMe.md b/docker/ReadMe.md index 3837a2c012b..2ed9e1e88f8 100755 --- a/docker/ReadMe.md +++ b/docker/ReadMe.md @@ -6,41 +6,41 @@ docker-machine create --driver virtualbox seleniumbase -#### 3. If your Docker environment ever goes down for any reason, you can bring it back up with a restart: +##### (If your Docker environment ever goes down for any reason, you can bring it back up with a restart.) docker-machine restart seleniumbase -#### 4. Configure your shell: +#### 3. Configure your shell: eval "$(docker-machine env seleniumbase)" -#### 5. Go to the SeleniumBase home directory. (That's where "Dockerfile" is located) +#### 4. Go to the SeleniumBase home directory. (That's where "Dockerfile" is located) -#### 6. Create your Docker image from your Dockerfile: (Get ready to wait awhile) +#### 5. Create your Docker image from your Dockerfile: (Get ready to wait awhile) docker build -t seleniumbase . -#### 7. Run a test inside your Docker: (Once the test completes after a few seconds, you'll automatically exit the Docker shell) +#### 6. Run a test inside your Docker: (Once the test completes after a few seconds, you'll automatically exit the Docker shell) docker run seleniumbase ./run_docker_test_in_firefox.sh -#### 8. Now run the same test with Chrome inside your Docker: +#### 7. Now run the same test with Chrome inside your Docker: docker run seleniumbase ./run_docker_test_in_chrome.sh -#### 9. You can also enter Docker and stay inside the shell: +#### 8. You can also enter Docker and stay inside the shell: docker run -i -t seleniumbase -#### 10. Now you can run the example test from inside the Docker shell: (This time with PhantomJS) +#### 9. Now you can run the example test from inside the Docker shell: - ./run_docker_test_in_phantomjs.sh + ./run_docker_test_in_chrome.sh -#### 11. When you're satisfied, you may exit the Docker shell: +#### 10. When you're satisfied, you may exit the Docker shell: exit -#### 12. (Optional) Since Docker images and containers take up a lot of space, you may want to clean up your machine from time to time when they’re not being used: +#### 11. (Optional) Since Docker images and containers take up a lot of space, you may want to clean up your machine from time to time when they’re not being used: http://stackoverflow.com/questions/17236796/how-to-remove-old-docker-containers Here are a few of those cleanup commands: @@ -57,7 +57,7 @@ Finally, if you want to wipe out your SeleniumBase Docker virtualbox, use these docker-machine kill seleniumbase docker-machine rm seleniumbase -#### 13. (Optional) More reading on Docker can be found here: +#### 12. (Optional) More reading on Docker can be found here: * https://docs.docker.com * https://docs.docker.com/mac/started/ * https://docs.docker.com/installation/mac/ From 7638877a7e22066af2b77b1b7caa1fb7b028cb84 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 20 Jan 2016 13:45:20 -0500 Subject: [PATCH 5/9] The Selenium plugin will handle virtual display --- docker/docker_config.cfg | 2 +- docker/docker_setup.py | 3 +- .../plugins/docker_selenium_plugin.py | 92 ------------------- seleniumbase/plugins/selenium_plugin.py | 25 ++++- 4 files changed, 23 insertions(+), 99 deletions(-) delete mode 100755 seleniumbase/plugins/docker_selenium_plugin.py diff --git a/docker/docker_config.cfg b/docker/docker_config.cfg index 48c63cc77c8..728c0821f09 100755 --- a/docker/docker_config.cfg +++ b/docker/docker_config.cfg @@ -1,5 +1,5 @@ [nosetests] -with-selenium_docker=1 +with-selenium=1 with-testing_base=1 with-basic_test_info=1 nocapture=1 diff --git a/docker/docker_setup.py b/docker/docker_setup.py index e0d6f26f006..c32450d9980 100755 --- a/docker/docker_setup.py +++ b/docker/docker_setup.py @@ -24,8 +24,7 @@ entry_points={ 'nose.plugins': [ 'base_plugin = seleniumbase.plugins.base_plugin:Base', - 'selenium_docker = ' - 'seleniumbase.plugins.docker_selenium_plugin:SeleniumBrowser', + 'selenium = seleniumbase.plugins.selenium_plugin:SeleniumBrowser', 'page_source = seleniumbase.plugins.page_source:PageSource', 'screen_shots = seleniumbase.plugins.screen_shots:ScreenShots', 'test_info = seleniumbase.plugins.basic_test_info:BasicTestInfo', diff --git a/seleniumbase/plugins/docker_selenium_plugin.py b/seleniumbase/plugins/docker_selenium_plugin.py deleted file mode 100755 index 88299194d3c..00000000000 --- a/seleniumbase/plugins/docker_selenium_plugin.py +++ /dev/null @@ -1,92 +0,0 @@ -""" -This is the Docker version of the Selenium plugin. -""" - -import os -from nose.plugins import Plugin -from pyvirtualdisplay import Display -from selenium import webdriver -from seleniumbase.fixtures import constants - - -class SeleniumBrowser(Plugin): - """ - The plugin for Selenium tests. Takes in key arguments and then - creates a WebDriver object. All arguments are passed to the tests. - - The following variables are made to the tests: - self.options.browser -- the browser to use (--browser) - self.options.server -- the server used by the test (--server) - self.options.port -- the port used by thest (--port) - """ - name = 'selenium_docker' # Usage: --with-selenium_docker - - def options(self, parser, env): - super(SeleniumBrowser, self).options(parser, env=env) - - parser.add_option('--browser', action='store', - dest='browser', - choices=constants.Browser.VERSION.keys(), - default=constants.Browser.FIREFOX, - help="""Specifies the browser. Default: FireFox. - If you want to use Chrome, indicate that.""") - parser.add_option('--browser_version', action='store', - dest='browser_version', - default="latest", - help="""The browser version to use. Explicitly select - a version number or use "latest".""") - parser.add_option('--server', action='store', dest='servername', - default='localhost', - help="""Designates the server used by the test. - Default: localhost.""") - parser.add_option('--port', action='store', dest='port', - default='4444', - help="""Designates the port used by the test. - Default: 4444.""") - parser.add_option('--demo_mode', action="store_true", - dest='demo_mode', - default=False, - help="""Using this slows down the automation so that - you can see what it's actually doing.""") - parser.add_option('--demo_sleep', action='store', dest='demo_sleep', - default=None, - help="""Setting this overrides the Demo Mode sleep - time that happens after browser actions.""") - - def configure(self, options, conf): - super(SeleniumBrowser, self).configure(options, conf) - self.display = Display(visible=0, size=(1200, 800)) - self.display.start() - self.driver = self.__select_browser() - self.options = options - - def beforeTest(self, test): - """ Running Selenium locally will be handled differently - from how Selenium is run remotely, such as from Jenkins. """ - - try: - self.driver = self.__select_browser() - test.test.driver = self.driver - test.test.browser = "firefox" - test.test.demo_mode = self.options.demo_mode - test.test.demo_sleep = self.options.demo_sleep - except Exception as err: - print "Error starting/connecting to Selenium:" - print err - os.kill(os.getpid(), 9) - return self.driver - - def afterTest(self, test): - try: - self.driver.quit() - self.display.stop() - except: - print "No driver to quit." - - def __select_browser(self): - try: - profile = webdriver.FirefoxProfile() - profile.set_preference("reader.parse-on-load.enabled", False) - return webdriver.Firefox(profile) - except: - return webdriver.Firefox() diff --git a/seleniumbase/plugins/selenium_plugin.py b/seleniumbase/plugins/selenium_plugin.py index df506f8d4fb..a0eee7032fd 100755 --- a/seleniumbase/plugins/selenium_plugin.py +++ b/seleniumbase/plugins/selenium_plugin.py @@ -7,6 +7,7 @@ import os from nose.plugins import Plugin from selenium import webdriver +from pyvirtualdisplay import Display from seleniumbase.core import selenium_launcher from seleniumbase.core import browser_launcher from seleniumbase.fixtures import constants @@ -20,7 +21,10 @@ class SeleniumBrowser(Plugin): The following variables are made to the tests: self.options.browser -- the browser to use (--browser) self.options.server -- the server used by the test (--server) - self.options.port -- the port used by thest (--port) + self.options.port -- the port used by the test (--port) + self.options.headless -- the option to run headlessly (--headless) + self.options.demo_mode -- the option to slow down Selenium (--demo_mode) + self.options.demo_sleep -- Selenium action delay in DemoMode (--demo_sleep) """ name = 'selenium' # Usage: --with-selenium @@ -46,6 +50,11 @@ def options(self, parser, env): default='4444', help="""Designates the port used by the test. Default: 4444.""") + parser.add_option('--headless', action="store_true", + dest='headless', + default=False, + help="""Using this makes Webdriver run headlessly, + which is useful inside a Linux Docker.""") parser.add_option('--demo_mode', action="store_true", dest='demo_mode', default=False, @@ -84,6 +93,7 @@ def configure(self, options, conf): self.browser_settings["version"] = options.browser_version self.options = options + self.headless_active = False if (self.options.servername == "localhost" and self.options.browser == constants.Browser.HTML_UNIT): @@ -95,6 +105,10 @@ def beforeTest(self, test): """ Running Selenium locally will be handled differently from how Selenium is run remotely, such as from Jenkins. """ + if self.options.headless: + self.display = Display(visible=0, size=(1200, 800)) + self.display.start() + self.headless_active = True if self.options.servername == "localhost": try: self.driver = self.__select_browser(self.options.browser) @@ -127,12 +141,12 @@ def beforeTest(self, test): except Exception as err: print "Attempt #%s to connect to Selenium failed" % i if i < 3: - print "Retrying in 15 seconds..." - time.sleep(15) + print "Retrying in 3 seconds..." + time.sleep(3) if not connected: print "Error starting/connecting to Selenium:" print err - print "\n\n\n" + print "\n\n" os.kill(os.getpid(), 9) def afterTest(self, test): @@ -140,6 +154,9 @@ def afterTest(self, test): self.driver.quit() except: print "No driver to quit." + if self.options.headless: + if self.headless_active: + self.display.stop() def __select_browser(self, browser_name): if (self.options.servername != "localhost" or From acfa70b708d0f2685804e1932fd27c6014ce449c Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 20 Jan 2016 13:46:17 -0500 Subject: [PATCH 6/9] Update Docker tests to use --headless --- docker/run_docker_test_in_chrome.sh | 2 +- docker/run_docker_test_in_firefox.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/run_docker_test_in_chrome.sh b/docker/run_docker_test_in_chrome.sh index 9f2b4f2308a..b070cb461a2 100755 --- a/docker/run_docker_test_in_chrome.sh +++ b/docker/run_docker_test_in_chrome.sh @@ -2,5 +2,5 @@ set -e # Run example test from inside Docker image echo "Running example SeleniumBase test from Docker with headless Chrome..." -cd /SeleniumBase/examples/ && nosetests my_first_test.py --config=docker_config.cfg --browser=chrome +cd /SeleniumBase/examples/ && nosetests my_first_test.py --config=docker_config.cfg --browser=chrome --headless exec "$@" diff --git a/docker/run_docker_test_in_firefox.sh b/docker/run_docker_test_in_firefox.sh index a4e93e5350c..cb69218536a 100755 --- a/docker/run_docker_test_in_firefox.sh +++ b/docker/run_docker_test_in_firefox.sh @@ -2,5 +2,5 @@ set -e # Run example test from inside Docker image echo "Running example SeleniumBase test from Docker with headless Firefox..." -cd /SeleniumBase/examples/ && nosetests my_first_test.py --config=docker_config.cfg --browser=firefox +cd /SeleniumBase/examples/ && nosetests my_first_test.py --config=docker_config.cfg --browser=firefox --headless exec "$@" From e3ecdb6d14cd36ae0553eb6b8715f3db703c166e Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 20 Jan 2016 14:54:08 -0500 Subject: [PATCH 7/9] Headless Selenium with pytest when using --headless --- conftest.py | 7 +++++++ seleniumbase/fixtures/base_case.py | 11 ++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/conftest.py b/conftest.py index 50829f86204..00c8d3bb63f 100755 --- a/conftest.py +++ b/conftest.py @@ -34,6 +34,11 @@ def pytest_addoption(parser): parser.addoption('--log_path', dest='log_path', default='logs/', help='Where the log files are saved.') + parser.addoption('--headless', action="store_true", + dest='headless', + default=False, + help="""Using this makes Webdriver run headlessly, + which is useful inside a Linux Docker.""") parser.addoption('--demo_mode', action="store_true", dest='demo_mode', default=False, @@ -50,6 +55,7 @@ def pytest_configure(config): with_testing_base = config.getoption('with_testing_base') browser = config.getoption('browser') log_path = config.getoption('log_path') + headless = config.getoption('headless') demo_mode = config.getoption('demo_mode') demo_sleep = '' data = '' @@ -65,6 +71,7 @@ def pytest_configure(config): config_file.write("data:::%s\n" % data) config_file.write("with_testing_base:::%s\n" % with_testing_base) config_file.write("log_path:::%s\n" % log_path) + config_file.write("headless:::%s\n" % headless) config_file.write("demo_mode:::%s\n" % demo_mode) config_file.write("demo_sleep:::%s\n" % demo_sleep) config_file.close() diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index f9dccbb9915..6f44c7a93ef 100755 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -11,6 +11,7 @@ import sys import time import unittest +from pyvirtualdisplay import Display from seleniumbase.config import settings from seleniumbase.core import browser_launcher from seleniumbase.core import log_helper @@ -303,12 +304,18 @@ def setUp(self): self.is_pytest = False if self.is_pytest: self.with_selenium = pytest.config.option.with_selenium + self.headless = pytest.config.option.headless + self.headless_active = False self.with_testing_base = pytest.config.option.with_testing_base self.log_path = pytest.config.option.log_path self.browser = pytest.config.option.browser self.data = pytest.config.option.data self.demo_mode = pytest.config.option.demo_mode self.demo_sleep = pytest.config.option.demo_sleep + if self.headless: + self.display = Display(visible=0, size=(1200, 800)) + self.display.start() + self.headless_active = True if self.with_selenium: self.driver = browser_launcher.get_driver(self.browser) @@ -336,6 +343,8 @@ def tearDown(self): test_logpath, self.driver, self.browser) # Handle page source logging log_helper.log_page_source(test_logpath, self.driver) - # Finally close the browser self.driver.quit() + if self.headless: + if self.headless_active: + self.display.stop() From 9925e127ef39927b3330d0dc57a097e26e95cfd7 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 20 Jan 2016 16:47:42 -0500 Subject: [PATCH 8/9] Update ReadMe for using Xvfb with "--headless" --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c05d6780735..bd1924d226a 100755 --- a/README.md +++ b/README.md @@ -265,7 +265,9 @@ If you're planning on using the full power of this test framework, there are a f * Setup your Selenium Grid and update your *.cfg file to point there. An example config file called selenium_server_config_example.cfg has been provided for you in the grid folder. The start-selenium-node.bat and start-selenium-server.sh files are for running your grid. In an example situation, your Selenium Grid server might live on a unix box and your Selenium Grid nodes might live on EC2 Windows virtual machines. When your build server runs a Selenium test, it would connect to your Selenium Grid to find out which Grid browser nodes are available to run that test. To simplify things, you can use [Browser Stack](https://www.browserstack.com/automate) as your entire Selenium Grid (and let them do all the fun work of maintaining the grid for you). -* There are ways of running your tests from Jenkins without having to utilize a remote machine. One way is by using PhantomJS as your browser (it runs headlessly). Another way is by using Xvfb (another headless system). [There's a plugin for Xvfb in Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Xvfb+Plugin). Here are some more helpful resources I found regarding the use of Xvfb: +* There are ways of running your tests from Jenkins without having to utilize a remote machine. One way is by using PhantomJS as your browser (it runs headlessly). Another way is by using Xvfb (another headless system). [There's a plugin for Xvfb in Jenkins](https://wiki.jenkins-ci.org/display/JENKINS/Xvfb+Plugin). +If you have Xvfb running in the background, you can add ``--headless`` to your run command in order to utilize it. +Here are some more helpful resources I found regarding the use of Xvfb: 1. http://stackoverflow.com/questions/6183276/how-do-i-run-selenium-in-xvfb 2. http://qxf2.com/blog/xvfb-plugin-for-jenkins-selenium/ 3. http://stackoverflow.com/questions/27202131/firefox-started-by-selenium-ignores-the-display-created-by-pyvirtualdisplay From f62dcea5361b5c5bf3256d05a00c124ab0f5bc4b Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 20 Jan 2016 16:49:32 -0500 Subject: [PATCH 9/9] Version 1.1.18 --- docker/docker_setup.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/docker_setup.py b/docker/docker_setup.py index c32450d9980..0a6d3af88b9 100755 --- a/docker/docker_setup.py +++ b/docker/docker_setup.py @@ -8,7 +8,7 @@ setup( name='seleniumbase', - version='1.1.17', + version='1.1.18', author='Michael Mintz', author_email='@mintzworld', maintainer='Michael Mintz', diff --git a/setup.py b/setup.py index 0bf6e6ec07e..b3fc4e7690a 100755 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name='seleniumbase', - version='1.1.17', + version='1.1.18', url='https://github.com/mdmintz/SeleniumBase', author='Michael Mintz', author_email='@mintzworld',