Docker packages an application and its dependencies into a repeatable environment. For QA automation, this helps the same tests run locally and in CI with fewer environment differences.

Core concepts

Image

A read-only package containing the files and dependencies needed to run something.

Container

A running instance of an image. Containers can be created, stopped and removed.

Dockerfile

A text file with instructions for building an image.

Registry

A service that stores images, such as Docker Hub or a private company registry.

Volume

Storage mounted into a container. It can persist data or expose reports to the host.

Compose

A YAML file that defines and runs one or more related containers.

Common Docker commands

CommandUse
docker --versionCheck that Docker is installed.
docker pull image:tagDownload an image.
docker imagesList local images.
docker build -t qa-tests .Build and name an image from the current folder.
docker run --rm qa-testsRun a container and remove it when it stops.
docker psList running containers.
docker ps -aList all containers.
docker logs container-nameShow container output.
docker exec -it container-name shOpen a shell inside a running container.
docker stop container-nameStop a running container.
docker rm container-nameRemove a stopped container.
docker rmi image-nameRemove a local image.

Understand a Dockerfile

FROM node:22-bookworm WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . CMD ["npm", "test"]
InstructionMeaning
FROMSelects the base image.
WORKDIRSets the current folder inside the image.
COPYCopies files from the build context into the image.
RUNRuns a command while building the image.
CMDDefines the default command when the container starts.
Important: an image is created by docker build. A container is created from that image by docker run.

Playwright project example

This minimal TypeScript project runs one Playwright test inside Docker.

Project structure

playwright-docker-example/ ├── tests/ │ └── example.spec.ts ├── .dockerignore ├── Dockerfile ├── package.json ├── package-lock.json └── playwright.config.ts

1. package.json

{ "name": "playwright-docker-example", "private": true, "scripts": { "test": "playwright test" }, "devDependencies": { "@playwright/test": "1.62.0" } }

Run npm install once locally to generate package-lock.json.

2. playwright.config.ts

import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: './tests', reporter: [['list'], ['html', { open: 'never' }]], use: { baseURL: 'https://example.com', trace: 'retain-on-failure', screenshot: 'only-on-failure' }, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] } } ] });

3. tests/example.spec.ts

import { test, expect } from '@playwright/test'; test('example page has the correct title', async ({ page }) => { await page.goto('/'); await expect(page).toHaveTitle(/Example Domain/); await expect(page.getByRole('heading')).toHaveText('Example Domain'); });

4. Dockerfile

FROM mcr.microsoft.com/playwright:v1.62.0-noble WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . CMD ["npx", "playwright", "test"]

5. .dockerignore

node_modules playwright-report test-results .git .env *.log
Keep versions aligned: the Playwright version in package.json should match the Docker image version. Update both together when the project is upgraded.

Build and run the tests

# Build the image docker build -t playwright-tests . # Run the tests docker run --rm --init --ipc=host playwright-tests

Save the HTML report on your computer

Mount the report folder when starting the container.

docker run --rm --init --ipc=host \ -v "$(pwd)/playwright-report:/app/playwright-report" \ playwright-tests

On PowerShell, replace $(pwd) with ${PWD}.

Pass a base URL at runtime

Use an environment variable in the Playwright configuration:

baseURL: process.env.BASE_URL || 'https://example.com'

Then run:

docker run --rm --init --ipc=host \ -e BASE_URL=https://test.example.com \ playwright-tests

Docker Compose

Compose is useful when tests need an application, API or database container.

services: web: image: nginx:alpine ports: - "8080:80" tests: build: . environment: BASE_URL: http://web depends_on: - web # Build and run the services docker compose up --build --abort-on-container-exit # Stop and remove the services docker compose down
Note: depends_on controls start order, but it does not guarantee that the application is ready. Use a health check or retry strategy for real projects.

Practical QA uses

  • Run the same browser and dependency versions locally and in CI.
  • Create a clean test environment for each execution.
  • Run API mocks, databases and the application with Compose.
  • Reproduce an environment-specific automation failure.
  • Share a ready-to-run automation setup with another tester.
  • Run tests in parallel using separate containers or CI jobs.

Common problems

ProblemCheck
Browser executable not foundConfirm that project and Docker image Playwright versions match.
Application is unreachableInside a container, localhost means that container. Use the Compose service name or the correct host address.
Reports disappearMount the report folder as a volume.
Build is slowCopy dependency files and run npm ci before copying frequently changed project files.
Tests fail only in DockerCompare environment variables, URLs, permissions, CPU, memory and browser versions.

Useful links