Selenium Tests in Django & Docker

Dec 17, 2017 09:43 · 504 words · 3 minutes read Docker Django Selenium Testing

Running Selenium tests in Django using Docker is an easy, convenient and repeatable strategy to run UI tests across multiple development and testing environments. It requires some light customization of the StaticLiveServerTestCase class, but once configured, the Selenium UI tests will seamlessly integrate into your existing test suite and dockerized CI build.

SeleniumHQ provides Docker images for Chrome and Firefox – if these browsers are sufficient for your UI testing needs, great! You can test against real browsers and avoid the cost of a third-party service subscription.

If you are already familiar with Selenium tests in Django, the setup is very similar with the exception of a few caveats:

  1. Use the selenium Remote web driver to connect to the Docker container
  2. The ALLOWED_HOSTS setting is enforced during LiveServerTestCase
  3. The Django test server must bind to 0.0.0.0 in order to allow the selenium docker container to connect.

How-To

For the full example, check out the example app:
https://github.com/marcgibbons/django-selenium-docker

The app uses docker-compose to link the Docker containers.

docker-compose.yml

Under services, define a container called selenium. In this example, we’ll use the standalone-chrome-debugcontainer which gives us the ability to connect remotely using VNC Viewer. This means we can gain access to the GUI to debug, inspect the DOM, use the JS console, etc.

  selenium:
    image: selenium/standalone-chrome-debug:3.7.1
    ports:
      - 4444:4444   # Selenium
      - 5900:5900   # VNC server

Make sure you add a link to this container from the Django container:

  django:
    ...
    links:
      - selenium
    ...

tests.py

The following is a slightly modified version of the example provided in the Django LiveServerTestCase documentation. Use this base class for all your Selenium test cases.

import socket

from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from django.test import override_settings, tag
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities


@override_settings(ALLOWED_HOSTS=['*'])  # Disable ALLOW_HOSTS
class BaseTestCase(StaticLiveServerTestCase):
    """
    Provides base test class which connects to the Docker
    container running Selenium.
    """
    host = '0.0.0.0'  # Bind to 0.0.0.0 to allow external access

    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        # Set host to externally accessible web server address
        cls.host = socket.gethostbyname(socket.gethostname())

        # Instantiate the remote WebDriver
        cls.selenium = webdriver.Remote(
            #  Set to: htttp://{selenium-container-name}:port/wd/hub
            #  In our example, the container is named `selenium`
            #  and runs on port 4444
            command_executor='http://selenium:4444/wd/hub',
            # Set to CHROME since we are using the Chrome container
            desired_capabilities=DesiredCapabilities.CHROME,

        )
        cls.selenium.implicitly_wait(5)

    @classmethod
    def tearDownClass(cls):
        cls.selenium.quit()
        super().tearDownClass()

Connecting with VNC Viewer

This is the cool part. The SeleniumHQ containers with the -debug suffix run a VNC server to which we can connect from the host (i.e. remote desktop.) The setup is very easy.

  1. First, download and install VNC Viewer.

  2. Create a new connection to 0.0.0.0:5900

  3. Start the selenium container (docker-compose start selenium)

  4. Connect to container from VNC. The password is secret.

  5. Run the test suite and watch the browser spin up!

Debugging

Now that you have a remote connection established to the container, you can insert a breakpoint in your code (pdb) and have the ability to control the browser, use the console, etc. Awesome!

Enjoy!

Credits

The Django TestCase configuration was pieced together from this StackOverflow article.