Preparing a Docker image for running Selenium tests

Sometimes your team members complain about automated tests not working on their computer while you are able to run the automated tests at your end completely fine. We too, at Qxf2, have experienced this issue. Our automated tests run fine at our end but occasionally fail when they run on our colleagues and client machines. Invariably, we trace this sort of failure down to variations in the setup/environment. So we looked to tackle this issue. We decided to build a Docker container for running our Selenium tests. The process was very quick and we decided to help all our fellow testers by sharing how we went about doing it.

This post assumes you already know a little about Docker.

NOTE: If you are just looking for a Docker image, you can skip ‘Step 1. Creating a Dockerfile’ section and directly move on to the step 2 titled as ‘Build/Pull the Docker image’.


Overview:

We will be performing the following steps:
1. Creating a Dockerfile
2. Build/Pull the Docker image
3. Creating a container and running Selenium tests


Step 1. Creating a Dockerfile for running Selenium tests:

To get setup with Docker CE you can refer to this link. To build a Docker image for running our Selenium tests, we needed to perform the following steps:

  1. Pull a Base image
  2. Install Xvfb virtual/headless display
  3. Setup Chrome and Chrome driver
  4. Setup Firefox and Geckodrivers
  5. Install Python 2.7 and Python Pip
  6. Get your project code into image/container and install requirements with help of pip and project requirements.txt file

All the steps except the final one rarely change unless when we decide to change the version of software installed. However, your project code and requirements change frequently. So, we decided to come up with a base image for Selenium which includes the first 5 steps i.e Ubuntu, Chrome with Chrome driver, Firefox with Geckodriver, Xvfb, Python and Python Pip.

We will code these steps into a file called a Dockerfile. A Dockerfile is a text document that contains all the commands a user could execute on the command line to assemble an image. To build the base image for running the Selenium test, we wrote the following Dockerfile.

1. Pull a Base Image
We used Ubuntu 16.04.

#Contents of Dockerfile
#Dockerfile to build an image which supports testing our Qxf2 Page Object Model.
FROM ubuntu
MAINTAINER Qxf2 Services

2. Install Xvfb virtual/headless display

# Essential tools and xvfb
RUN apt-get update && apt-get install -y \
    software-properties-common \
    unzip \
    curl \
    xvfb

3. Setup Chrome and Chrome driver

# Chrome browser to run the tests
RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub -o /tmp/google.pub \
    && cat /tmp/google.pub | apt-key add -; rm /tmp/google.pub \
    && echo 'deb http://dl.google.com/linux/chrome/deb/ stable main' > /etc/apt/sources.list.d/google.list \
    && mkdir -p /usr/share/desktop-directories \
    && apt-get -y update && apt-get install -y google-chrome-stable
# Disable the SUID sandbox so that chrome can launch without being in a privileged container
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 --no-sandbox --disable-setuid-sandbox \"\$@\"" > /opt/google/chrome/google-chrome \
    && chmod 755 /opt/google/chrome/google-chrome
 
# Chrome Driver
RUN mkdir -p /opt/selenium \
    && curl http://chromedriver.storage.googleapis.com/2.45/chromedriver_linux64.zip -o /opt/selenium/chromedriver_linux64.zip \
    && cd /opt/selenium; unzip /opt/selenium/chromedriver_linux64.zip; rm -rf chromedriver_linux64.zip; ln -fs /opt/selenium/chromedriver /usr/local/bin/chromedriver;

4. Setup Firefox and Geckodrivers

# Firefox browser to run the tests
RUN apt-get install -y firefox
 
# Gecko Driver
ENV GECKODRIVER_VERSION 0.23.0
RUN wget --no-verbose -O /tmp/geckodriver.tar.gz https://github.com/mozilla/geckodriver/releases/download/v$GECKODRIVER_VERSION/geckodriver-v$GECKODRIVER_VERSION-linux64.tar.gz \
  && rm -rf /opt/geckodriver \
  && tar -C /opt -zxf /tmp/geckodriver.tar.gz \
  && rm /tmp/geckodriver.tar.gz \
  && mv /opt/geckodriver /opt/geckodriver-$GECKODRIVER_VERSION \
  && chmod 755 /opt/geckodriver-$GECKODRIVER_VERSION \
  && ln -fs /opt/geckodriver-$GECKODRIVER_VERSION /usr/bin/geckodriver \
  && ln -fs /opt/geckodriver-$GECKODRIVER_VERSION /usr/bin/wires

Note: Please make sure you update the script to download the latest ChromeDriver and geckodriver versions

5. Install Python 2.7 and Python Pip

# python
RUN apt-get update && apt-get install -y \
    python \
    python-setuptools \
    python-pip

Putting it all together
Our final Dockerfile looks like this:

#Contents of Dockerfile
#Dockerfile to build an image which supports testing our Qxf2 Page Object Model.
FROM ubuntu
MAINTAINER Qxf2 Services
 
# Essential tools and xvfb
RUN apt-get update && apt-get install -y \
    software-properties-common \
    unzip \
    curl \
    xvfb 
 
# Chrome browser to run the tests
RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub -o /tmp/google.pub \
    && cat /tmp/google.pub | apt-key add -; rm /tmp/google.pub \
    && echo 'deb http://dl.google.com/linux/chrome/deb/ stable main' > /etc/apt/sources.list.d/google.list \
    && mkdir -p /usr/share/desktop-directories \
    && apt-get -y update && apt-get install -y google-chrome-stable
# Disable the SUID sandbox so that chrome can launch without being in a privileged container
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 --no-sandbox --disable-setuid-sandbox \"\$@\"" > /opt/google/chrome/google-chrome \
    && chmod 755 /opt/google/chrome/google-chrome
 
# Chrome Driver
RUN mkdir -p /opt/selenium \
    && curl http://chromedriver.storage.googleapis.com/2.45/chromedriver_linux64.zip -o /opt/selenium/chromedriver_linux64.zip \
    && cd /opt/selenium; unzip /opt/selenium/chromedriver_linux64.zip; rm -rf chromedriver_linux64.zip; ln -fs /opt/selenium/chromedriver /usr/local/bin/chromedriver;
 
# Firefox browser to run the tests
RUN apt-get install -y firefox
 
# Gecko Driver
ENV GECKODRIVER_VERSION 0.23.0
RUN wget --no-verbose -O /tmp/geckodriver.tar.gz https://github.com/mozilla/geckodriver/releases/download/v$GECKODRIVER_VERSION/geckodriver-v$GECKODRIVER_VERSION-linux64.tar.gz \
  && rm -rf /opt/geckodriver \
  && tar -C /opt -zxf /tmp/geckodriver.tar.gz \
  && rm /tmp/geckodriver.tar.gz \
  && mv /opt/geckodriver /opt/geckodriver-$GECKODRIVER_VERSION \
  && chmod 755 /opt/geckodriver-$GECKODRIVER_VERSION \
  && ln -fs /opt/geckodriver-$GECKODRIVER_VERSION /usr/bin/geckodriver \
  && ln -fs /opt/geckodriver-$GECKODRIVER_VERSION /usr/bin/wires
 
# python
RUN apt-get update && apt-get install -y \
    python \
    python-setuptools \
    python-pip

Step 2. Build/Pull the Docker image:

You can either build your own image using above Dockerfile or you can directly download the image from our Docker Hub repository.

To build the image using above dockerfile, you need to save dockerfile to any directory in your system and use the following command:

docker build -t image_name path/to/dockerfile

To directly download it from our Docker Hub repository, you need to use the following command:

docker pull qxf2rohand/qxf2_pom_essentials

Step 3. Creating a container and running Selenium tests:

We decided to use this image for testing our Qxf2’s open sourced GUI automation framework. We named the image as qxf2_pom_essentials. qxf2_pom_essentials image is capable of running any Python based Selenium tests. To run the Selenium tests using this image, you need to go through following steps:

  1. Create a Docker container out of this image and enter into the container using the following command:
    docker run -it qxf2rohand/qxf2_pom_essentials "/bin/bash"
  2. Export display and enable Xvfb using following 2 commands:
    export DISPLAY=:20
    Xvfb :20 -screen 0 1366x768x16 &
  3. Install Selenium using pip
    pip install selenium
  4. Use any Linux editor you like and add your test inside the container. You can also use the sample Selenium code (selenium_docker.py) given below. This selenium test visits Qxf2 Services website and prints the title.
    # contents of selenium_docker.py
    from selenium import webdriver
     
    driver = webdriver.Firefox()
    driver.get("http://www.qxf2.com")
    print driver.title
    driver.quit()
  5. Run the selenium test using the following command:
    python selenium_docker.py

    The output will be similar to the screenshot shown below.

    Fig. 1 Output of selenium_docker.py

Note: The above steps are only to show you how to use our Docker image. At Qxf2 Services, for testing our Qxf2’s Public Page Object Model we use another Dockerfile which automatically gets our code from GitHub, setup our requirements, run shell script file to enable Xvfb and run the test.


To know more about how to get your code inside the container and run the test, please stay tuned. We will post about it soon. Until then enjoy running your tests anywhere without thinking about environment set up using this Docker image. Happy testing!

If you are a startup finding it hard to hire technical QA engineers, learn more about Qxf2 Services.

Subscribe to our weekly Newsletter


View a sample



Rohan Dudam

I love technology and learning new things. I explore both hardware and software. I am passionate about robotics and embedded systems which motivate me to develop my software and hardware skills. I have good knowledge of Python, Selenium, Arduino, C and hardware design. I have developed several robots and participated in robotics competitions. I am constantly exploring new test ideas and test tools for software and hardware. At Qxf2, I am working on developing hardware tools for automated tests ala Tapster. Incidentally, I created Qxf2’s first robot. Besides testing, I like playing cricket, badminton and developing embedded gadget for fun.

10 Comments

  1. John said:

    Hi Rohan,
    Thanks for this page, which is very useful to me.
    One more question I have is would the Dockerfile copy you provided, may also create an env for runing “py.test” cases ?

    Thanks

    September 18, 2018
    Reply
    • Rohan Joshi Rohan Joshi said:

      John , Yes it can create env for running py.test cases provided that you have included step in dockerfile to install pytest plugin . Hope that helps you

      September 19, 2018
      Reply
  2. John said:

    Hi Rohan,
    I just realize where the problem is, here is the details.
    1) I was using exactly the Dockerfile provided on this page, The image was created “successfully”, while the chromdriver part was actually failing, here is the log says:

    Removing intermediate container 174dbbcb223b
    —> 594b60de714d
    Step 6/10 : RUN mkdir -p /opt/selenium && curl http://chromedriver.storage.googleapis.com/2.30/chromedriver_linux64.zip -o /opt/selenium/chromedriver_linux64.zip && cd /opt/selenium; unzip /opt/selenium/chromedriver_linux64.zip; rm -rf chromedriver_linux64.zip; ln -fs /opt/selenium/chromedriver /usr/local/bin/chromedriver;
    —> Running in ebf3ee3157a4
    % Total % Received % Xferd Average Speed Time Time Time Current
    Dload Upload Total Spent Left Speed
    0 0 0 0 0 0 0 0 –:–:– –:–:– –:–:– 0
    curl: (52) Empty reply from server
    unzip: cannot find or open /opt/selenium/chromedriver_linux64.zip, /opt/selenium/chromedriver_linux64.zip.zip or /opt/selenium/chromedriver_linux64.zip.ZIP.
    :.”
    2) Once the image was created, I was able to have it stared, and I was able to have the chromedriver installed on top of it.

    3) When I was trying your “python selenium_docker.py”, which is for firefox, I was able to get the exact result. but if I was to switch it to Chrome, I got this kind of message:

    Traceback (most recent call last):
    File “tests/selenium_docker.py”, line 4, in
    driver = webdriver.Chrome()
    File “/usr/local/lib/python2.7/dist-packages/selenium/webdriver/chrome/webdriver.py”, line 68, in __init__
    self.service.start()
    File “/usr/local/lib/python2.7/dist-packages/selenium/webdriver/common/service.py”, line 98, in start
    self.assert_process_still_running()
    File “/usr/local/lib/python2.7/dist-packages/selenium/webdriver/common/service.py”, line 111, in assert_process_still_running
    % (self.path, return_code)
    selenium.common.exceptions.WebDriverException: Message: Service chromedriver unexpectedly exited. Status code was: 127

    So my question is, if manually installing chromedriver on top of the created image, is a valid way to do for Chrome case ?

    Thanks,

    John

    September 19, 2018
    Reply
    • Rohan Joshi Rohan Joshi said:

      Hii John , Actually chromedriver should have installed automatically while creating image . Now since you have manually installed chromedriver on top of image , can you check if the chrome driver version which you installed is compatible with chrome browser version . What version you are using ?

      September 21, 2018
      Reply
  3. Anonymous said:

    I followed the steps above to build an image. I got this error when running the sample python test –
    driver = webdriver.Firefox()
    File “/usr/local/lib/python2.7/dist-packages/selenium/webdriver/firefox/webdriver.py”, line 174, in __init__
    keep_alive=True)
    File “/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py”, line 157, in __init__
    self.start_session(capabilities, browser_profile)
    File “/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py”, line 252, in start_session
    response = self.execute(Command.NEW_SESSION, parameters)
    File “/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py”, line 321, in execute
    self.error_handler.check_response(response)
    File “/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/errorhandler.py”, line 242, in check_response
    raise exception_class(message, screen, stacktrace)
    selenium.common.exceptions.WebDriverException: Message: newSession

    The tests runs fine on image qxf2rohand/qxf2_pom_essentials from repo. What’s difference between the two?

    November 1, 2018
    Reply
    • Annapoorani Gurusamy Annapoorani Gurusamy said:

      Hi,
      Can you please check the Firefox version and driver version?.

      November 2, 2018
      Reply
  4. Saurabh said:

    Hi Rohan,

    I want to include a step in Dockerfile that should run some pip install commands.
    How can I include requirements.txt in the Dockerfile in the example mentioned.

    January 1, 2019
    Reply
  5. Kat said:

    Hi,

    I already have a main.py created but how would I add the contents to the container?
    When I enter the root@ terminal, python can’t open ‘main.py’: [Errno 2] No such file or directory

    April 16, 2019
    Reply
    • Indira Nellutla Indira Nellutla said:

      Kat,

      Where did you create the main.py file?

      i) After you run the (1) command in ‘Creating a container and running Selenium tests’ section, you should enter into a container,
      ii) Inside the container run (2) and (3) commands,
      iii) Inside the container, create a test file ‘main.py’ with the below contents

      “`
      from selenium import webdriver

      driver = webdriver.Firefox()
      driver.get(“http://www.qxf2.com”)
      print driver.title
      driver.quit()

      “`
      iv) Run the test.

      Hope this helps!

      April 17, 2019
      Reply

Leave a Reply

Your email address will not be published.