Why Docker for QA

Docker solves one of QA’s oldest problems: environment inconsistency. How many times have you heard “it works on my machine” when reporting a bug? Docker eliminates this by packaging applications and their dependencies into containers that run identically everywhere.

For QA engineers, Docker provides:

  • Consistent test environments across local machines, CI servers, and staging
  • Isolated test execution — tests do not interfere with each other or the host system
  • Reproducible bugs — if it fails in a container, it fails the same way every time
  • Fast environment setup — spin up a complete test environment in seconds, not hours

Core Docker Concepts

Images

A Docker image is a lightweight, standalone package that includes everything needed to run a piece of software: code, runtime, system tools, libraries, and settings.

Think of an image as a snapshot of a configured machine. It is read-only and immutable.

# Pull an image from Docker Hub
docker pull node:20

# List local images
docker images

# Pull a specific testing image
docker pull mcr.microsoft.com/playwright:v1.40.0-focal

Containers

A container is a running instance of an image. It is isolated from the host system and other containers, but can expose ports and mount volumes for communication.

# Run a container
docker run -it node:20 bash

# Run in background (detached mode)
docker run -d -p 3000:3000 --name my-app my-app-image

# List running containers
docker ps

# Stop a container
docker stop my-app

# View container logs
docker logs my-app

Volumes

Volumes persist data beyond a container’s lifecycle. For QA, they are essential for saving test reports and sharing test data:

# Mount a local directory into a container
docker run -v $(pwd)/test-results:/app/test-results playwright-tests

# Create a named volume
docker volume create test-data
docker run -v test-data:/data my-test-image

Networks

Docker networks enable containers to communicate with each other:

# Create a network
docker network create test-network

# Run containers on the same network
docker run -d --network test-network --name db postgres:15
docker run -d --network test-network --name app my-app-image

# Containers can reach each other by name (db, app)

Building Test Images with Dockerfile

A Dockerfile defines how to build an image. Here is a Dockerfile for a test automation project:

FROM mcr.microsoft.com/playwright:v1.40.0-focal

WORKDIR /app

# Copy dependency files first (for cache efficiency)
COPY package.json package-lock.json ./

# Install dependencies
RUN npm ci

# Copy test files
COPY . .

# Default command: run all tests
CMD ["npx", "playwright", "test"]

Dockerfile Best Practices for QA

Layer ordering matters. Docker caches each layer. Put things that change rarely (base image, dependencies) first, and things that change often (test code) last:

FROM node:20-slim

# System dependencies (rarely change)
RUN apt-get update && apt-get install -y \
    chromium \
    && rm -rf /var/lib/apt/lists/*

# Application dependencies (change when package.json changes)
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

# Test code (changes frequently)
COPY . .

CMD ["npm", "test"]

Use .dockerignore to exclude unnecessary files:

node_modules
.git
test-results
playwright-report
*.md

Building and Running

# Build the image
docker build -t my-tests .

# Run tests
docker run my-tests

# Run specific test file
docker run my-tests npx playwright test tests/login.spec.ts

# Run with environment variables
docker run -e BASE_URL=https://staging.example.com my-tests

# Save test results to host
docker run -v $(pwd)/results:/app/test-results my-tests

Debugging Containerized Applications

QA engineers frequently need to debug applications running in Docker:

Inspecting Running Containers

# Execute a shell inside a running container
docker exec -it container-name bash

# View real-time logs
docker logs -f container-name

# Inspect container configuration
docker inspect container-name

# Check resource usage
docker stats container-name

Common Debugging Scenarios

Application not responding:

# Check if the container is running
docker ps -a

# Check logs for errors
docker logs container-name --tail 50

# Check if the port is exposed correctly
docker port container-name

Tests fail in container but pass locally:

# Run tests interactively to see the environment
docker run -it my-tests bash

# Check environment inside the container
env | sort

# Verify file permissions
ls -la /app/

# Check available memory
free -h

Exercise: Containerize a Test Suite

Given a Node.js test project with:

  • Unit tests (Jest)
  • E2E tests (Playwright)
  • API tests (against a PostgreSQL-backed REST API)

Create a Dockerfile that can run all three types of tests.

Solution
FROM mcr.microsoft.com/playwright:v1.40.0-focal

# Install PostgreSQL client for DB setup
RUN apt-get update && apt-get install -y \
    postgresql-client \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Dependencies (cached layer)
COPY package.json package-lock.json ./
RUN npm ci

# Test configuration
COPY playwright.config.ts jest.config.ts tsconfig.json ./

# Test files
COPY tests/ tests/
COPY src/ src/

# Environment defaults
ENV NODE_ENV=test
ENV CI=true

# Default: run all tests
CMD ["npm", "run", "test:all"]

Running different test types:

# All tests
docker run my-tests

# Unit tests only
docker run my-tests npm run test:unit

# E2E tests only
docker run my-tests npx playwright test

# API tests with database
docker run --network test-net \
  -e DATABASE_URL=postgresql://test:test@db:5432/testdb \
  my-tests npm run test:api

Docker Commands QA Engineers Use Daily

CommandPurpose
docker runCreate and start a container
docker psList running containers
docker logsView container output
docker exec -itRun commands inside a container
docker buildBuild an image from Dockerfile
docker stop / rmStop and remove containers
docker imagesList local images
docker pullDownload an image
docker cpCopy files between host and container
docker system pruneClean up unused resources

Common Docker Images for QA

ImageUse Case
mcr.microsoft.com/playwrightPlaywright E2E testing with browsers
cypress/includedCypress E2E testing
selenium/standalone-chromeSelenium with Chrome
selenium/hub + selenium/node-*Selenium Grid
postgresPostgreSQL for integration tests
redisRedis for caching tests
localstack/localstackAWS service emulation
mailhog/mailhogEmail testing

Key Takeaways

  1. Docker ensures environment consistency — the same image runs identically on your laptop and in CI
  2. Images are blueprints, containers are instances — one image can spawn many containers
  3. Layer your Dockerfile efficiently — dependencies first, test code last, for optimal caching
  4. Use volumes for test artifacts — mount host directories to extract reports and screenshots
  5. Learn basic debugging commandsdocker exec, docker logs, and docker inspect will save you hours