Skip to content
SDETRole
SDETRole

Docker interview question

How would you write a Dockerfile for a test runner?

intermediate 2–5 yrs #dockerfile#layer-caching#ci

Short answer

Start from a pinned base image that already has the browsers or runtime you need, copy dependency manifests first and install so the layer is cached, then copy the test code. Run as a non-root user, keep secrets out of the image, pass config at runtime, and write reports to a mounted directory.

Answer

A test runner image should be reproducible, fast to rebuild and free of secrets. The test code changes constantly, the dependencies change occasionally, and the base image changes rarely, so the Dockerfile is ordered in that direction.

Example: Playwright with TypeScript

# Pinned image that already contains the browsers and their OS dependencies.
# Keep this tag in sync with the @playwright/test version in package.json.
FROM mcr.microsoft.com/playwright:v1.65.0-noble

WORKDIR /tests

# Dependency layer: only rebuilt when the manifests change
COPY package.json package-lock.json ./
RUN npm ci

# Test code: changes most often, so it comes last
COPY . .

# The base image provides a non-root user called pwuser
USER pwuser

# Config arrives at runtime, never at build time
ENV CI=true
ENTRYPOINT ["npx", "playwright", "test"]

A matching .dockerignore keeps the build context small and avoids leaking local files:

node_modules
playwright-report
test-results
.env
.git

Run it, passing configuration and collecting reports through a mount:

docker build -t e2e-tests:local .
docker run --rm --ipc=host \
  -e BASE_URL=https://staging.example.com \
  -e TEST_USER_PASSWORD \
  -v "$PWD/playwright-report:/tests/playwright-report" \
  e2e-tests:local --project=chromium

Because the entrypoint is npx playwright test, extra arguments after the image name go straight to the runner.

Decisions worth explaining

  • Base image choice. Building browsers on top of a generic Node image means installing many system libraries; the vendor images (Playwright’s, or selenium/standalone-* for a Selenium node) already handle that. For a Java REST Assured suite, a maven:3.9-eclipse-temurin-21 image works, with COPY pom.xml and mvn -B dependency:go-offline before copying src.
  • Pin versions. latest makes builds non-reproducible. Pin the tag (or digest) and update deliberately, for example with Dependabot or Renovate.
  • Layer caching. If COPY . . comes before npm ci, every code change reinstalls all dependencies.
  • Secrets. ENV PASSWORD=... or copying a .env file bakes credentials into an image layer that anyone with the image can read. Pass them at runtime from the CI secret store.
  • Chromium in Docker needs adequate shared memory; Playwright recommends --ipc=host and Selenium images document --shm-size=2g.
  • Non-root user. Reduces the impact of anything malicious running in the container.

Common mistakes

  • Using latest tags and wondering why last week’s green build is red.
  • Baking the environment URL into the image, so you need one image per environment.
  • Writing reports inside the container and losing them when it exits with --rm.

What interviewers look for

  • Correct layer ordering and an explanation of the build cache.
  • Pinned versions and an appropriate base image.
  • Runtime configuration and secrets, with reports extracted via volumes.

A strong answer covers

  • Pin a suitable base image (version tag, not latest)
  • Order layers for caching: copy manifests and install dependencies before source
  • No secrets baked in; pass config and credentials at runtime
  • Reports written to a volume or mounted directory
  • Small and secure: .dockerignore, non-root user
Practise answering under time pressure

Type to search across SDETRole.

Full-text search by Pagefind · runs in your browser Open search page →