Reputation: 888
I'm having trouble getting my python Selenium running in github actions.
I have been using Circle CI for the past year, but recently began migrating over to github actions.
For Circle CI to run selenium in a chrome browser, I had the following lines in my config.yml:
docker:
# includes chrome browser for selenium testing
- image: circleci/python:3.7.4-browsers
and there didn't seem to be a need to install a chromedriver.
I am using the following in my githubs action .yml file:
jobs:
build:
runs-on: ubuntu-latest
services:
selenium:
image: selenium/standalone-chrome
steps:
- uses: actions/checkout@v1
- name: Set up Python 3.7
uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pipenv
pipenv install
- name: Prepare Selenium
# https://github.com/marketplace/actions/setup-chromedriver
uses: nanasess/setup-chromedriver@master
- name: Launch browser
run: |
google-chrome --version
export DISPLAY=:99
chromedriver --url-base=/wd/hub &
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & # optional, disables headless mode
- name: Run tests
run: pipenv run python manage.py test functional_tests.tests.test_selenium.test_exams -v 2
But I get the following error when in my python code I try to run:
from selenium import webdriver
driver = webdriver.Chrome()
File "/home/runner/.local/share/virtualenvs/lang-EMCZ4oUT/lib/python3.7/site-packages/selenium/webdriver/chrome/webdriver.py", line 81, in __init__
desired_capabilities=desired_capabilities)
File "/home/runner/.local/share/virtualenvs/lang-EMCZ4oUT/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py", line 157, in __init__
self.start_session(capabilities, browser_profile)
File "/home/runner/.local/share/virtualenvs/lang-EMCZ4oUT/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py", line 252, in start_session
response = self.execute(Command.NEW_SESSION, parameters)
File "/home/runner/.local/share/virtualenvs/lang-EMCZ4oUT/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "/home/runner/.local/share/virtualenvs/lang-EMCZ4oUT/lib/python3.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: unknown error: Chrome failed to start: exited abnormally.
(unknown error: DevToolsActivePort file doesn't exist)
(The process started from chrome location /usr/bin/google-chrome is no longer running, so ChromeDriver is assuming that Chrome has crashed.)
From what I can read online, I should need just the uses: nanasess/setup-chromedriver@master
and shouldn't need image: selenium/standalone-chrome
, but switching either in or out doesn't make any difference, the python tests still cannot find chrome browser.
Am I supposed to set up a port to listen to?
Upvotes: 10
Views: 8314
Reputation: 1
Check out the chromedriver-autoinstaller python package.
With the line of code below in your script, you can automatically check and download the latest version of chromedriver exists and then add it to path.
chromedriver_autoinstaller.install()
You should check out this template as well.
Upvotes: 0
Reputation: 689
I’m going to answer your question first and then I’m going to offer an alternative approach. I’m going to use a unified diff format to highlight the changes I would make to your workflow. If you’re not familiar with the format, ignore the first three lines, and then imagine that I’m deleting the lines starting with “-
” from your workflow and adding the lines starting with “+
”. Lines starting with “
” are left as-is.
When you posted your question, the action nanasess/setup-chromedriver
downloaded Chrome Browser along with chromedriver (that was v1.0.1). As of this writing, it still does the same (v1.0.5). Because of this, you don’t need an extra service container to run Chrome Browser and chromedriver – they are already in your primary container.
--- original.yml 2020-06-13 20:42:25 +0000
+++ step1.yml 2021-04-23 00:01:00 +0000
@@ -1,9 +1,6 @@
jobs:
build:
runs-on: ubuntu-latest
- services:
- selenium:
- image: selenium/standalone-chrome
steps:
- uses: actions/checkout@v1
- name: Set up Python 3.7
You also don’t need your “Launch browser” step. Selenium library will do it for you. It executes local chromedriver binary by default, which in turn executes Chrome Browser binary by default. If you don’t want to use headless mode, you still have to start the virtual framebuffer (but nothing else):
--- step1.yml 2021-04-23 00:01:00 +0000
+++ step2.yml 2021-04-23 00:02:00 +0000
@@ -15,11 +15,10 @@
- name: Prepare Selenium
# https://github.com/marketplace/actions/setup-chromedriver
uses: nanasess/setup-chromedriver@master
- - name: Launch browser
+ - name: Start XVFB
run: |
- google-chrome --version
- export DISPLAY=:99
- chromedriver --url-base=/wd/hub &
sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & # optional, disables headless mode
- name: Run tests
run: pipenv run python manage.py test functional_tests.tests.test_selenium.test_exams -v 2
+ env:
+ DISPLAY: :99
And this should do the trick. Notice addition of env
with the same DISPLAY
port as was passed when starting XVFB.
My guess is that the error you shared here occurs due to conflict between chromedriver and Google Chrome you’ve started and the ones your test suite is trying to start and control.
What is my alternative approach? I’m personally a bit cautious when introducing third-party dependencies. Especially for things which should be just about couple lines of code. And when looking for inspiration, I try to look as close to the source as possible. So, how is Selenium testing their code?
Interestingly, Selenium project is using GitHub Actions to test the libraries themselves and they have quite extensive integration test suite which requires running browsers. They don’t use third-party action to setup the browser environment. Their tests are pretty complex, but you can take a hint, take individuals actions and steps, and apply them based on your needs.
The important part is the action to setup Chrome and chromedriver. Straightforward and pretty much the same compared to the action from Kentaro Ohkouchi (a.k.a. nanasess) which you’re using.
The next important part is starting the virtual framebuffer. Again, you don’t need it if you are using headless mode. They are starting it very simply compared to you or Ohkouchi’s example:
--- step2.yml 2021-04-23 00:02:00 +0000
+++ step3.yml 2021-04-23 00:03:00 +0000
@@ -18,3 +18,3 @@
- name: Start XVFB
run: |
- sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & # optional, disables headless mode
+ Xvfb :99 &
No sudo
, no extra arguments, just the DISPLAY
port.
P.S.: When using a third-party action, use tags. You never know what kind of change squeezes into someone else’s code. Rather let the test fail during CI, investigate what changed and then bump the version, than blindly trust that someone is always going to make the right change for you…
--- step3.yml 2021-04-23 00:03:00 +0000
+++ step4.yml 2021-04-23 00:04:00 +0000
@@ -15,3 +15,3 @@
- name: Prepare Selenium
# https://github.com/marketplace/actions/setup-chromedriver
- uses: nanasess/setup-chromedriver@master
+ uses: nanasess/[email protected]
Upvotes: 9
Reputation: 1
Use headless Chromedriver
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument('--headless')
driver = webdriver.Chrome(options=chrome_options)
If you need Chrome with GUI - you can use macos or windows instead of ubuntu
MacOS
jobs:
build:
runs-on: macos-latest
...
Windows
jobs:
build:
runs-on: windows-latest
...
Upvotes: -2