petrkindlmann/qa-skillsMIT3 files

Test Environments

>-

Specification
Skill ID
petrkindlmann/qa-skills/test-environments
Publisher
petrkindlmann
Repository
qa-skills
Installs
0
Files
3
License
MIT
Synced
Sep 23, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

petrkindlmann/qa-skills/test-environmentsInstalls these files
  • SKILL.md
  • references/docker-compose.md
  • references/stubbing.md

What this skill tells the agent

<objective> Staging on SQLite passes tests that break on prod Postgres; a shared staging box becomes a queue where one broken deploy blocks the whole team; an unmocked Stripe call flakes CI at random. This skill prevents those by designing environment tiers that mirror production where it matters, isolate per-PR, and stub external dependencies at the HTTP boundary. It delivers a working docker compose up local/CI stack, a parity checklist, and a stubbing strategy keyed to dependency type. </objective>

Discovery Questions

Check .agents/qa-project-context.md first — if it exists, use it and skip anything already answered there. Then:

  1. How many environments exist today? Local dev, CI, staging, preview, production? Map what you have before designing what you need.
  2. Is the app containerized? Check for Dockerfile, docker-compose.yml, or compose.yaml. If yes, multi-stage targets and compose come for free; if not, that is the first deliverable.
  3. How is test data seeded? Manual SQL, migration-based, factory libraries, or production snapshots? This decides whether seed scripts are a quick win or a rewrite.
  4. How close is staging to production? Same DB engine, queue, cache, auth provider, orchestration? Each mismatch is a class of bugs staging can never catch.
  5. External dependencies: How many third-party APIs does the system call, and are they stubbed in non-prod? Unstubbed third parties are the top source of CI flake.

Core Principles

1. Staging must mirror production where bugs hide. If staging uses SQLite and production uses PostgreSQL, staging tests prove nothing about prod behavior. Match the database engine and version, the queue system, the cache layer, and the auth provider — those are where environment-specific bugs live.

2. Ephemeral environments beat long-lived ones. A shared staging environment becomes a bottleneck where one broken deploy blocks the entire team. Per-PR preview environments give isolation and parallel testing; keep staging only for final pre-release validation.

3. Deterministic seed data, not production copies. Production snapshots carry PII, stale references, and non-reproducible state. Build seed data from factories that generate consistent, valid, minimal datasets. (For factory patterns, see test-data-management.)

4. Stub external dependencies at the boundary, not deep inside. Third-party APIs are unreliable, rate-limited, and expensive. Stub them at the HTTP boundary with MSW or WireMock — never by mocking internal service classes, which hides integration bugs between your own code.

5. Environment config is code. Every environment difference (URLs, flags, credentials, resource limits) must be version-controlled and reviewable. No manual setup that cannot be reproduced from the repo.


Environment Strategy

Environment Tiers

EnvironmentPurposeDataExternal DepsLifecycle
Local devFast inner loopSeeded fixtures, minimalStubbed (MSW/WireMock)Developer-managed
CIAutomated validationSeeded per-run, ephemeralStubbed or containerizedCreated/destroyed per pipeline
PreviewPR-level review & E2ESeeded from factoriesStubbed or sandboxCreated on PR, destroyed on close
StagingPre-production validationAnonymized production-likeReal integrations (sandbox accounts)Long-lived, regularly reset
ProductionLive usersRealRealPermanent

Local Development

Fast feedback, zero shared state. Developers must be able to run the full stack locally in under two minutes:

docker compose -f docker-compose.test.yml up -d
npm run db:seed
npm run dev

Use Docker Compose for infrastructure deps (database, cache, queue) but run the application natively for fast reload. External APIs are stubbed with MSW handlers loaded in dev mode.

CI Environment

Fully containerized, created fresh per pipeline run, destroyed after. The block below is the `services:` fragment of a job — nest it under jobs.<id>.services alongside runs-on and steps; on its own it is not a valid workflow file.

# .github/workflows/test.yml — fragment: nest under jobs.test.services
services:
  postgres:
    image: postgres:18-alpine
    env:
      POSTGRES_DB: testdb
      POSTGRES_USER: test
      POSTGRES_PASSWORD: test
    ports: ['5432:5432']
    options: >-
      --health-cmd="pg_isready -U test"
      --health-interval=5s
      --health-timeout=3s
      --health-retries=5
  redis:
    image: redis:8-alpine
    ports: ['6379:6379']
    options: >-
      --health-cmd="redis-cli ping"
      --health-interval=5s
      --health-timeout=3s
      --health-retries=5

Docker Compose vs Testcontainers

Two ways to give tests real infrastructure. Pick by where the lifecycle should live:

  • Docker Compose — declarative stack you bring up before the suite (docker compose up --wait) and tear down after, usually via a trap-guarded script. Best for local dev, a shared CI stack, and E2E where many tests share one set of services.
  • Testcontainers (Node / JVM / Python / Go) — containers spun up from test code and auto-torn-down per suite or per test, with no compose file or trap to maintain. Best for integration tests that need isolated, programmatic infra (a throwaway Postgres per test class). The 2026 default for "ephemeral infra owned by the test," and a strong alternative to hand-rolled compose + trap scripts.

Reach for Compose when humans and many tests share the stack; reach for Testcontainers when each test (or suite) wants its own disposable copy.

Preview Environments (Per-PR)

Each pull request gets its own isolated environment; reviewers click a link and test the exact changes without interfering with other PRs.

Hosting options (2026), pick by stack:

  • Vercel preview deployments — Next.js / static / serverless; per-PR URL automatically.
  • Cloudflare Pages preview — git-integrated, generous free tier.
  • Render / Railway preview environments — full-stack including databases.
  • Northflank, Qovery, Bunnyshell, Uffizzi — full ephemeral-environment platforms (Kubernetes-backed) when previews need the whole stack, not just a frontend.

For each preview, pair the env lifecycle with a database branch (Neon, Supabase, PlanetScale-style): create a branch on PR open, drop it on close. That gives every preview a cheap, instant, isolated DB copy instead of a shared staging DB. (See test-data-management.)

For local-dev parity with CI:

  • Devcontainers (.devcontainer/devcontainer.json) — VS Code, Codespaces, JetBrains. The standard for "everyone gets the same Docker-backed dev env."
  • Tilt (Tiltfile) — Kubernetes-first local dev with hot reload and multi-service orchestration. Pick when staging itself is K8s.

A frontend preview with E2E against the generated URL is a few lines:

- name: Run E2E against preview
  env:
    BASE_URL: ${{ steps.deploy.outputs.preview-url }}
  run: npx playwright test --project=chromium

A custom Docker preview keyed to a per-PR namespace, auto-torn-down on close:

- name: Deploy preview
  run: |
    NAMESPACE="pr-${{ github.event.number }}"
    docker compose -f docker-compose.preview.yml -p "$NAMESPACE" up -d
    echo "preview-url=https://${NAMESPACE}.preview.example.com" >> "$GITHUB_OUTPUT"

- name: Teardown preview
  if: github.event.action == 'closed'
  run: |
    NAMESPACE="pr-${{ github.event.number }}"
    docker compose -p "$NAMESPACE" down -v

Staging

Long-lived environment that mirrors production infrastructure. Reset weekly or on-demand to prevent drift:

#!/bin/bash
# scripts/reset-staging.sh
set -euo pipefail

echo "Resetting staging database..."
psql "$STAGING_DATABASE_URL" -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;"

Use this skill in a project

Open any RiverX project, search the Skills panel for petrkindlmann/qa-skills/test-environments, and install it in one click.

Use this skill