Docker packages an application or test environment — OS libraries, language runtime, browsers, tools and dependencies — into an image that runs identically anywhere. In CI, running tests inside a container eliminates 'works on my machine' by making the environment a versioned, reproducible artifact.
Test flakiness and CI-only failures often trace to environment drift: a different OS, a missing system library, a different browser or font-rendering behavior. A Docker image pins all of that. Playwright, for instance, publishes an official image with the three browsers and all their Linux system dependencies pre-installed, so a job that runs container: mcr.microsoft.com/playwright:... skips dependency installation and, crucially, matches the environment used to generate visual baselines. Beyond consistency, containers give isolation (each run is clean) and portability (the same image runs locally and in CI, so a developer can reproduce a CI failure exactly). The trade-offs are image size and build time, mitigated by layer caching and using slim base images. The interview point is that Docker converts 'the environment' from an implicit variable into an explicit, version-controlled dependency.
Visual tests fail only on CI due to font-rendering differences between a developer's macOS and the Ubuntu runner. Switching the E2E job to run inside the official Playwright Docker container makes CI and baseline generation use the identical environment, so the spurious pixel diffs vanish.
# Run the whole job inside the official Playwright image
jobs:
e2e:
runs-on: ubuntu-latest
container: mcr.microsoft.com/playwright:v1.50.0-jammy # browsers + deps preinstalled
steps:
- uses: actions/checkout@v4
- run: npm ci # no 'playwright install --with-deps' needed
- run: npx playwright test
# Or a custom Dockerfile pinning the environment:
# FROM node:20-bookworm-slim
# RUN apt-get update && apt-get install -y --no-install-recommends <libs>
# WORKDIR /app
# COPY package*.json ./ && RUN npm ci
# COPY . .Scenario: A suite passes on every developer's machine but fails intermittently on CI with missing-library and font-rendering errors, and each developer's local environment is subtly different. How does containerization solve this, and what are the trade-offs?