← Blog

"Selenium Series #17: Headless Browsers and Docker — Containerised Test Execution"

Run Selenium tests on servers with no display. Configure headless Chrome and Firefox, build a Docker image for your test suite, and run zero-dependency containerised tests anywhere.

reading now
views
comments

Series Navigation

Part 16: CI/CD Integration — Jenkins

Part 18: Selenium 4 — New Features, Relative Locators and CDP


Why Headless Mode?

CI/CD servers have no display. A browser that requires a GUI cannot open. Headless mode runs Chrome/Firefox without rendering a visible window — same browser engine, same behaviour, no display required.

Headed Chrome:  Opens visible window → Cannot run on headless Linux CI server
Headless Chrome: No window → Runs anywhere, slightly faster

Headless Chrome

ChromeOptions options = new ChromeOptions();
options.addArguments("--headless");
options.addArguments("--disable-gpu");              // required on Windows
options.addArguments("--window-size=1920,1080");    // important: set explicit size
options.addArguments("--no-sandbox");               // required on Linux
options.addArguments("--disable-dev-shm-usage");    // prevents crashes in Docker
options.addArguments("--disable-extensions");
options.addArguments("--proxy-server='direct://'"); // bypass proxy for local

WebDriverManager.chromedriver().setup();
WebDriver driver = new ChromeDriver(options);

Headless Firefox

FirefoxOptions options = new FirefoxOptions();
options.setHeadless(true);
options.addArguments("--width=1920");
options.addArguments("--height=1080");

WebDriverManager.firefoxdriver().setup();
WebDriver driver = new FirefoxDriver(options);

Virtual Display on Linux (Alternative to Headless)

Some older tests break in headless mode (file uploads, certain JavaScript). Use Xvfb (virtual framebuffer):

# Install Xvfb
sudo apt-get install xvfb

# Start virtual display
Xvfb :99 -screen 0 1920x1080x24 &
export DISPLAY=:99

# Run tests normally (non-headless) on the virtual display
mvn test -Dheadless=false

Dockerfile for Selenium Tests

# Dockerfile
FROM maven:3.8-openjdk-11-slim

# Install Chrome
RUN apt-get update && apt-get install -y \
    wget curl gnupg2 unzip \
    && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
    && echo "deb http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list \
    && apt-get update \
    && apt-get install -y google-chrome-stable \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Copy pom.xml and download dependencies (cached layer)
COPY pom.xml .
RUN mvn dependency:resolve -q

# Copy source code
COPY src/ src/

# Default command: run all tests headless
CMD ["mvn", "test", "-Dheadless=true", "-Dbrowser=chrome"]

Build and run:

# Build image
docker build -t selenium-tests:latest .

# Run tests
docker run --rm \
  -e BASE_URL=https://staging.example.com \
  -e BROWSER=chrome \
  -v $(pwd)/test-output:/app/test-output \
  selenium-tests:latest

# Override with specific suite
docker run --rm \
  selenium-tests:latest \
  mvn test -DsuiteXmlFile=src/test/resources/smoke-testng.xml -Dheadless=true

Docker Compose — Full Stack Testing

# docker-compose.test.yml
version: "3.8"

services:

  # Your application under test
  app:
    image: your-app:latest
    ports:
      - "8080:8080"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 10s
      timeout: 5s
      retries: 5

  # Selenium Grid Hub
  selenium-hub:
    image: selenium/hub:4.1.0
    ports:
      - "4444:4444"

  chrome-node:
    image: selenium/node-chrome:4.1.0
    depends_on: [selenium-hub]
    environment:
      SE_EVENT_BUS_HOST: selenium-hub
      SE_EVENT_BUS_PUBLISH_PORT: 4442
      SE_EVENT_BUS_SUBSCRIBE_PORT: 4443
      SE_NODE_MAX_SESSIONS: 4
    volumes:
      - /dev/shm:/dev/shm

  # Test runner
  selenium-tests:
    build: .
    depends_on:
      app:
        condition: service_healthy
      selenium-hub:
        condition: service_started
    environment:
      BASE_URL: http://app:8080
      GRID_URL: http://selenium-hub:4444
      BROWSER: chrome
    volumes:
      - ./test-output:/app/test-output
    command: >
      mvn test
        -Dbase.url=http://app:8080
        -DgridUrl=http://selenium-hub:4444
        -Dbrowser=chrome
        -DsuiteXmlFile=src/test/resources/testng.xml
# Run the full stack
docker-compose -f docker-compose.test.yml up --abort-on-container-exit

# Check exit code (0=pass, non-zero=failure)
echo "Exit: $?"

# Get reports from container
docker cp selenium-tests:/app/test-output ./test-output

What's Next

In Part 18 — the final post in the series — we explore Selenium 4's new features: relative locators, native Windows API, CDP (Chrome DevTools Protocol) integration, and the upgraded WebDriver API.

Discussion

Loading...

Leave a Comment

All comments are reviewed before appearing. No links please.

0 / 1000