# Docker and Containers > **When to use**: Running Playwright tests in containers for reproducible environments, CI pipelines, or local development with consistent browser versions. Essential when your team needs identical test environments across machines. ## Quick Reference ```bash # Official Playwright Docker images docker pull mcr.microsoft.com/playwright:v1.52.0-noble # Ubuntu 24.04, all browsers docker pull mcr.microsoft.com/playwright:v1.52.0-jammy # Ubuntu 22.04, all browsers # Run tests in container docker run --rm -v $(pwd):/app -w /app mcr.microsoft.com/playwright:v1.52.0-noble \ npx playwright test # Check your Playwright version (must match image tag) npx playwright --version ``` ## Patterns ### Pattern 1: Running Tests in the Official Image **Use when**: Quick, reproducible test runs without building a custom image. **Avoid when**: You need application services (database, API) running alongside -- use docker-compose instead. ```bash # Run all tests docker run --rm \ -v $(pwd):/app \ -w /app \ mcr.microsoft.com/playwright:v1.52.0-noble \ bash -c "npm ci && npx playwright test" # Run with environment variables docker run --rm \ -v $(pwd):/app \ -w /app \ -e CI=true \ -e BASE_URL=http://host.docker.internal:3000 \ mcr.microsoft.com/playwright:v1.52.0-noble \ bash -c "npm ci && npx playwright test" # Run and extract report docker run --rm \ -v $(pwd):/app \ -w /app \ -v $(pwd)/playwright-report:/app/playwright-report \ mcr.microsoft.com/playwright:v1.52.0-noble \ bash -c "npm ci && npx playwright test" ``` ### Pattern 2: Custom Dockerfile **Use when**: You need additional system dependencies, pre-installed npm packages, or a smaller image with only certain browsers. **Avoid when**: The official image works as-is. ```dockerfile # Dockerfile.playwright FROM mcr.microsoft.com/playwright:v1.52.0-noble WORKDIR /app # Copy package files first for better layer caching COPY package.json package-lock.json ./ RUN npm ci # Copy the rest of the project COPY . . # Default command CMD ["npx", "playwright", "test"] ``` ```bash # Build and run docker build -f Dockerfile.playwright -t my-e2e-tests . docker run --rm my-e2e-tests # Run with specific options docker run --rm my-e2e-tests npx playwright test --project=chromium # Extract report docker run --rm -v $(pwd)/reports:/app/playwright-report my-e2e-tests ``` **Slim image with only Chromium:** ```dockerfile # Dockerfile.playwright-chromium FROM node:20-slim # Install only Chromium dependencies RUN npx playwright install --with-deps chromium WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci COPY . . CMD ["npx", "playwright", "test", "--project=chromium"] ``` ### Pattern 3: Docker Compose with Application Stack **Use when**: Tests need the full application stack: web server, database, cache, and Playwright running together. **Avoid when**: Tests run against a remote environment (staging/prod) -- no local services needed. ```yaml # docker-compose.yml services: # Application under test app: build: context: . dockerfile: Dockerfile ports: - "3000:3000" environment: - NODE_ENV=test - DATABASE_URL=postgresql://postgres:postgres@db:5432/test - REDIS_URL=redis://cache:6379 depends_on: db: condition: service_healthy cache: condition: service_started # Database db: image: postgres:16-alpine environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: test healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s timeout: 5s retries: 5 tmpfs: - /var/lib/postgresql/data # RAM disk for speed # Cache cache: image: redis:7-alpine # Playwright test runner e2e: image: mcr.microsoft.com/playwright:v1.52.0-noble working_dir: /app volumes: - .:/app - /app/node_modules # prevent host node_modules from overriding environment: - CI=true - BASE_URL=http://app:3000 depends_on: - app command: bash -c "npm ci && npx playwright test" profiles: - test # only start with: docker compose --profile test up ``` ```bash # Run the full stack with tests docker compose --profile test up --abort-on-container-exit --exit-code-from e2e # Run just the app (for local dev) docker compose up app # Run tests against already-running stack docker compose --profile test run --rm e2e npx playwright test # Tear down everything docker compose --profile test down -v ``` ### Pattern 4: Extracting Reports and Traces from Containers **Use when**: You need test artifacts (HTML reports, traces, screenshots) accessible on the host after container tests complete. **Avoid when**: CI handles artifact collection natively (GitHub Actions, GitLab artifacts). ```bash # Method 1: Bind mount the output directories docker run --rm \ -v $(pwd):/app \ -v $(pwd)/playwright-report:/app/playwright-report \ -v $(pwd)/test-results:/app/test-results \ -w /app \ mcr.microsoft.com/playwright:v1.52.0-noble \ bash -c "npm ci && npx playwright test" # Method 2: Copy artifacts from a stopped container docker run --name e2e-run \ -v $(pwd):/app \ -w /app \ mcr.microsoft.com/playwright:v1.52.0-noble \ bash -c "npm ci && npx playwright test" || true docker cp e2e-run:/app/playwright-report ./playwright-report docker cp e2e-run:/app/test-results ./test-results docker rm e2e-run # View the report npx playwright show-report ./playwright-report ``` **Docker Compose for report extraction:** ```yaml # docker-compose.yml (add to e2e service) services: e2e: image: mcr.microsoft.com/playwright:v1.52.0-noble working_dir: /app volumes: - .:/app - ./playwright-report:/app/playwright-report - ./test-results:/app/test-results # ... rest of config ``` ### Pattern 5: CI Container Strategies **Use when**: Your CI environment benefits from containerized test execution. **GitHub Actions -- container job:** ```yaml # .github/workflows/playwright.yml jobs: test: runs-on: ubuntu-latest container: image: mcr.microsoft.com/playwright:v1.52.0-noble steps: - uses: actions/checkout@v4 - run: npm ci - run: npx playwright test env: HOME: /root ``` **GitLab CI -- image directive:** ```yaml # .gitlab-ci.yml test: image: mcr.microsoft.com/playwright:v1.52.0-noble script: - npm ci - npx playwright test ``` **Jenkins -- Docker agent:** ```groovy // Jenkinsfile pipeline { agent { docker { image 'mcr.microsoft.com/playwright:v1.52.0-noble' args '-u root' } } stages { stage('Test') { steps { sh 'npm ci' sh 'npx playwright test' } } } } ``` ### Pattern 6: Development Container (devcontainer) **Use when**: Your team uses VS Code Dev Containers or GitHub Codespaces and needs Playwright available in the development environment. **Avoid when**: Everyone installs Playwright locally and version differences don't cause issues. ```json // .devcontainer/devcontainer.json { "name": "Playwright Dev", "image": "mcr.microsoft.com/playwright:v1.52.0-noble", "features": { "ghcr.io/devcontainers/features/node:1": { "version": "20" } }, "postCreateCommand": "npm ci", "customizations": { "vscode": { "extensions": ["ms-playwright.playwright"] } }, "forwardPorts": [3000, 9323], "remoteUser": "root" } ``` ## Decision Guide | Scenario | Approach | Why | | --------------------------------- | ----------------------------------------------------------- | ------------------------------------------------- | | Simple CI pipeline | Official Playwright image as CI image | Browsers pre-installed; zero browser install time | | Tests need database + cache | Docker Compose with app, db, cache, e2e services | Full stack in isolated containers | | Team needs identical environments | Dev Container or custom Dockerfile | Eliminate "works on my machine" | | Only testing Chromium | Slim image: `node:20-slim` + `install --with-deps chromium` | Smaller image, faster pulls | | Cross-browser testing | Official Playwright image (has all browsers) | All three engines pre-installed | | Local development | Run directly on host, not in container | Faster iteration, easier debugging | | CI with artifact extraction | Bind mount report/results dirs or use CI artifact upload | Reports accessible after container exits | | Image | Size | Browsers | Base OS | | -------------------------------------------- | ------- | ------------------------- | --------------- | | `mcr.microsoft.com/playwright:v1.52.0-noble` | ~2 GB | Chromium, Firefox, WebKit | Ubuntu 24.04 | | `mcr.microsoft.com/playwright:v1.52.0-jammy` | ~2 GB | Chromium, Firefox, WebKit | Ubuntu 22.04 | | Custom slim (Chromium only) | ~800 MB | Chromium | Depends on base | ## Anti-Patterns | Anti-Pattern | Problem | Do This Instead | | ---------------------------------------------------- | --------------------------------------------------------- | ---------------------------------------------------------------------------------------- | | Image tag doesn't match `@playwright/test` version | Browser binaries incompatible with Playwright library | Always match: `v1.52.0` image for `@playwright/test@1.52.0` | | Using `latest` tag | Unpredictable; image updates can break tests | Pin to exact version: `v1.52.0-noble` | | Installing browsers inside container at runtime | Wastes 60-90 seconds on every run | Use official image (browsers pre-installed) or build custom image with browsers baked in | | Running as non-root without configuring sandbox | Chromium sandbox fails with permission errors | Run as root (`-u root`) or disable sandbox (`--no-sandbox` in launch args) | | Bind-mounting `node_modules` from host | Platform-specific binaries (macOS vs Linux) cause crashes | Use anonymous volume: `-v /app/node_modules` | | No health checks on dependent services | Tests start before database is ready | Add `healthcheck` to db service; use `depends_on: condition: service_healthy` | | Building application inside the Playwright container | Large image, slow builds, wrong base for your app | Separate app and e2e containers in docker-compose | ## Troubleshooting ### "browserType.launch: Executable doesn't exist" in container **Cause**: Playwright version in `package.json` doesn't match the Docker image version. **Fix**: Ensure exact version match: ```bash # Check your version npm ls @playwright/test # @playwright/test@1.52.0 # Use matching image docker pull mcr.microsoft.com/playwright:v1.52.0-noble ``` ### Tests fail with "net::ERR_CONNECTION_REFUSED" in docker-compose **Cause**: Tests are trying to reach `localhost:3000` but the app is in a different container. **Fix**: Use the service name as hostname and configure `baseURL`: ```ts // playwright.config.ts import { defineConfig } from "@playwright/test" export default defineConfig({ use: { baseURL: process.env.BASE_URL || "http://localhost:3000", }, // Disable webServer in Docker -- app is managed by docker-compose ...(process.env.CI ? {} : { webServer: { command: "npm run dev", url: "http://localhost:3000", reuseExistingServer: true, }, }), }) ``` ```yaml # docker-compose.yml e2e: environment: - BASE_URL=http://app:3000 # "app" is the service name ``` ### Permission denied on mounted volumes **Cause**: Container runs as root but host files are owned by your user, or vice versa. **Fix**: Match user IDs or run as root: ```bash # Run as your host user docker run --rm -u $(id -u):$(id -g) \ -v $(pwd):/app -w /app \ mcr.microsoft.com/playwright:v1.52.0-noble \ npx playwright test # Or run as root (simpler, fine for CI) docker run --rm \ -v $(pwd):/app -w /app \ mcr.microsoft.com/playwright:v1.52.0-noble \ npx playwright test ``` ### Container tests are much slower than local **Cause**: Docker Desktop on macOS/Windows has I/O overhead for bind-mounted volumes. **Fix**: Copy files into the container instead of mounting: ```dockerfile # Dockerfile.playwright FROM mcr.microsoft.com/playwright:v1.52.0-noble WORKDIR /app COPY . . RUN npm ci CMD ["npx", "playwright", "test"] ``` Or use delegated mount on macOS: ```bash docker run --rm \ -v $(pwd):/app:delegated \ -w /app \ mcr.microsoft.com/playwright:v1.52.0-noble \ bash -c "npm ci && npx playwright test" ``` ## Related - [ci/ci-github-actions.md](ci-github-actions.md) -- container jobs in GitHub Actions - [ci/ci-gitlab.md](ci-gitlab.md) -- Docker images in GitLab CI - [ci/ci-other.md](ci-other.md) -- Docker agents in Jenkins, CircleCI - [ci/parallel-and-sharding.md](parallel-and-sharding.md) -- sharding within containers - [ci/reporting-and-artifacts.md](reporting-and-artifacts.md) -- extracting reports from containers