End-to-End Testing with Docker and Selenium

Why

In a recent Django project, I needed to implement end-to-end testing using Selenium. While the setup worked smoothly locally, I wanted to containerize the development environment, including the test suites. However, I encountered a challenge when running the tests in Docker: Selenium requires a browser to be installed in the system, and not all Docker images come with a browser pre-installed.

Problem

version: '3'
services:
  # django
  app:
    build: .
    command: python manage.py runserver 0.0.0.0:8080
    volumes:
      # ...
    ports:
      - "8080:8080"
  
  # database
  db:
    # ...

Writing a docker compose file for these services was quite straightforward, everything runs smoothly until I run the test suites. Selenium requires the chosen browser to be pre-installed in your system in order to perform the tests, however, not every docker image comes with a browser.

Solution

So there are two options:

  1. Modify the Dockerfile of app to include the target browser
  2. Use the Selenium official docker image

Whilst the first option can work, it might not be the most reusable and maintainable solution.

So here is the addition to the docker-compose.yaml file:

services:
  # ...
  # other services
  # ...

  # selenium firefox driver
  selenium-firefox:
    image: selenium/standalone-firefox
    shm_size: 2gb
    ports:
      - "4444:4444"
      - "7900:7900"
    restart: "no"

The project is using LiveServerTestCase from the django.test package that automatically sets up a live development server on a random port, and the tests can make real HTTP requests to this server. Therefore, an important step for the end-to-end testing to work is to modify the host variable for any class using the LiveServerTestCase.

from django.test import LiveServerTestCase

class SeleniumAppTest(LiveServerTestCase):
  """
  Test my app!
  """

  host = 'app'

Since we are running tests inside the app container, we would like the Selenium to connect to the live development server on http://app:{random_port}.