Testing

Test preview environments

A preview environment is a full Zuplo deployment of a branch, on the same edge network as production, at its own URL. That makes it the highest-fidelity place to run your test suite before a change merges — closer to production than any local server, and without the queueing and drift of a shared staging environment.

Because zuplo test takes the target as a flag, the files you run against http://localhost:9000 are the files you run against the preview URL. Nothing in the suite changes.

How branches become environments

Push a branch to a connected repository and Zuplo deploys it:

  • The repository's default branch deploys to Production.
  • Every other branch deploys to a Preview environment with its own URL.

For the full mapping, see branch-based deployments. For how preview environments differ from working copies, see environments.

Get the URL into your tests

Preview URLs are derived from the branch name and project, so hard-coding one is a maintenance problem. Read the URL from the environment instead.

From the Zuplo GitHub integration

The integration reports a GitHub Deployment for each build, and the deployment status carries the environment URL. In a workflow triggered by the deployment_status event, that value is github.event.deployment_status.environment_url. This is the mechanism used in testing GitHub deployments, and it is the approach to prefer: no URL construction, and the tests cannot start before the deployment exists.

From your own pipeline

If you deploy from your own CI with zuplo deploy, capture the URL from the deploy command's output and pass it through:

TerminalCode
OUTPUT=$(npx zuplo deploy --api-key "$ZUPLO_API_KEY" --environment "$BRANCH" 2>&1) echo "$OUTPUT" DEPLOY_URL=$(echo "$OUTPUT" | grep -oP 'Deployed to \K(https://[^ ]+)') npx zuplo test --endpoint "$DEPLOY_URL"

For the complete workflow, see GitHub Actions: deploy and test. For pipeline patterns for other providers, see custom CI/CD.

Wait for the environment before testing

A deployment reporting success is not the same as a gateway serving traffic, and the gap between the two is the single most common cause of "flaky" gateway tests. The first few requests fail, the run is retried, and the real problem — a race in the pipeline — is filed as test flakiness.

Poll a cheap unauthenticated route with a hard deadline instead of sleeping:

TerminalCode
deadline=$((SECONDS + 120)) until curl --fail --silent --output /dev/null "$API_URL/health"; do if ((SECONDS >= deadline)); then echo "Gateway at $API_URL not ready after 120s" >&2 exit 1 fi sleep 2 done npx zuplo test --endpoint "$API_URL"

If your gateway has no health route, add one. See health checks.

Per-environment services and secrets

Preview environments have their own configuration, and a test that passes locally can fail on a preview for reasons that have nothing to do with your change:

  • Environment variables. Values are set per environment in the Zuplo Portal. A variable that exists in production but not on the preview is a real defect the preview run catches — but assert on the behavior, not on the variable.
  • API key buckets. API key authentication is backed by a bucket tied to the environment. Keys minted for one environment do not authenticate against another, so CI needs a fixture key for the environment it is testing.
  • Rate limit buckets. Rate limit state is per environment too. This works in your favor: a preview environment's limits are not being consumed by production traffic, which is part of what makes the rate limit recipe deterministic.

Keep fixture credentials in your CI provider's secret store and pass them to zuplo test as environment variables. Inside the test they are available on TestHelper.environment:

TerminalCode
TENANT_A_JWT="$PREVIEW_TENANT_A_JWT" npx zuplo test --endpoint "$API_URL"

Scope what runs where

The same files can run everywhere, but that does not mean every test runs everywhere:

TargetWhat to run
http://localhost:9000Everything. Fast feedback while editing.
Preview deploymentEverything. This is the run that gates the merge.
ProductionA small, read-only smoke subset selected with --filter.

Name the production-safe tests consistently — a smoke: prefix works well — and select them by name:

TerminalCode
npx zuplo test --endpoint https://api.example.com --filter "smoke"

Nothing with side effects belongs in that subset. See gateway test recipes for the test data hygiene rules that make this safe.

Clean up preview environments

Preview environments outlive the branch unless something removes them. Delete the branch and the environment goes with it when you use the GitHub integration. If you deploy from your own pipeline, add an explicit cleanup step on branch delete. See cleanup on branch delete.

Last modified on