So far we've used Docker for Selenium Grid alone. But in a real project, you need more. You need the app running. A database. Maybe a mock API server. And the Grid. All of it should start with one command and tear down cleanly.
Docker Compose lets you define your entire test infrastructure in one YAML file. One command brings up the app, the database, and the Grid. Your tests run. One command tears it all down. Clean. Reproducible. Every time.
# docker-compose-test.yml
# Complete test infrastructure: App + DB + Selenium Grid
version: '3.8'
services:
# --- Application Under Test ---
app:
build: .
container_name: test-app
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://testuser:testpass@db:5432/testdb
- NODE_ENV=test
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "https://www.testerrank.com/health"]
interval: 10s
timeout: 5s
retries: 5
# --- Database ---
db:
image: postgres:16-alpine
container_name: test-db
environment:
- POSTGRES_USER=testuser
- POSTGRES_PASSWORD=testpass
- POSTGRES_DB=testdb
healthcheck:
test: ["CMD-SHELL", "pg_isready -U testuser"]
interval: 5s
timeout: 3s
retries: 5
# --- Selenium Grid Hub ---
selenium-hub:
image: selenium/hub:4.18.1
container_name: selenium-hub
ports:
- "4444:4444"
# --- Chrome Node ---
chrome:
image: selenium/node-chrome:4.18.1
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
- SE_NODE_OVERRIDE_MAX_SESSIONS=true
shm_size: '2g'
# --- Firefox Node ---
firefox:
image: selenium/node-firefox:4.18.1
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
- SE_NODE_OVERRIDE_MAX_SESSIONS=true
shm_size: '2g'# Start everything — app, database, Grid
docker compose -f docker-compose-test.yml up -d
# Wait for app to be healthy
docker compose -f docker-compose-test.yml ps
# All containers should show "healthy" or "running"
# Run tests against the Docker environment
mvn clean test \
-Dgrid.url=http://localhost:4444 \
-Dapp.url=http://test-app:3000 \
-DsuiteXmlFile=testng-crossbrowser.xml
# View test results
allure serve target/allure-results
# Tear everything down — clean slate
docker compose -f docker-compose-test.yml down -v
# -v removes volumes too (clean database)Without health checks, Docker starts the app container but doesn't wait for the app to be ready. Your tests start running immediately and fail because the app hasn't loaded yet. Health checks tell Docker to wait until the app is actually ready to serve requests.
The depends_on with condition: service_healthy is the key. Without it, the app starts before the database is ready and crashes. Health checks + depends_on conditions = reliable startup order.
// Jenkinsfile snippet
pipeline {
stages {
stage('Start Test Environment') {
steps {
sh 'docker compose -f docker-compose-test.yml up -d'
sh 'sleep 30' // Wait for health checks
}
}
stage('Run Cross-Browser Tests') {
steps {
sh '''mvn clean test \
-Dgrid.url=http://localhost:4444 \
-DsuiteXmlFile=testng-crossbrowser.xml'''
}
}
stage('Generate Report') {
steps {
allure includeProperties: false,
results: [[path: 'target/allure-results']]
}
}
}
post {
always {
sh 'docker compose -f docker-compose-test.yml down -v'
}
}
}Always use "down -v" in CI cleanup. The -v flag removes Docker volumes (database data). Without it, leftover test data from previous runs can cause flaky tests. Every CI run should start with a clean database.
Q: How does your test infrastructure work in CI/CD?
A: We use Docker Compose to spin up the entire test environment — application, database, and Selenium Grid — with one command. Our docker-compose-test.yml defines all services with health checks and dependency ordering. Jenkins starts the environment, waits for health checks, runs cross-browser tests against the Grid, generates Allure reports, and tears everything down with "docker compose down -v". The -v flag ensures a clean database for every run. This makes our tests completely reproducible — same environment on every developer's laptop and in CI.
Key Point: Docker Compose for the full stack: app + database + Grid. One command up, tests run, one command down. Same environment everywhere.