Don't take chances with changes.
Test your gateway at every step — locally, on a real preview deployment
for every PR, and in production. One test suite, one command, and the
only thing that changes is --endpoint. Because your gateway is code in Git, not console state.
The gateway holds your highest-consequence logic — and it's the least tested thing you own
Auth, rate limits, routing, request validation, error shapes. In most stacks that behavior lives as console state in someone's browser tab, verified by clicking around and hoping.
Auth logic tested, auth policy untested
Your application's auth code has 90% coverage. The gateway policy that actually enforces auth in production — attached in a console, verified by clicking around — has none. The highest-consequence config in your stack is the least tested thing you own.
The happy path hides the worst bugs
A policy attached to the wrong route doesn't fail — it succeeds, for the wrong user. Requests flow, dashboards stay green, and every unit test passes. Only a test that asserts the rejections can see it.
Console config makes testing an afterthought
When gateway config lives as database state behind a portal UI, there is no artifact a pull request can hold — so testing gets bolted on afterwards, as a linter, an interactive debugger, or a separate product. What you rarely get is a test file in the same repo as the config it tests.
Staging is a queue, not a safety net
One shared staging environment means teams wait in line, config drifts from production, and test data collides. A pre-merge test result from an environment that doesn't match production doesn't mean much.
One suite. Three endpoints.
The same test files run against your local dev server, against the
real preview deployment Zuplo builds for your branch, and against
production. TestHelper.TEST_URL is whatever you pass to --endpoint — nothing else in the suite changes. Against production, run a small
read-only smoke subset, not the whole suite.
Setup: none. @zuplo/test arrives with the zuplo package, and assertions come from Node's built-in node:assert/strict. No assertion library to install.
Every pull request gets a real gateway, not a mock
Push a branch and Zuplo deploys a full gateway — the complete runtime, on the same edge network as production, at its own URL. Your tests run against a real deployment before merge, so a pre-merge result actually predicts production behavior. And the tests sit in your repo, next to the config they test.
Test what actually breaks
The interesting assertions at a gateway are the rejections. These four
defects don't show up in unit tests or happy-path checks — and they're
all one fetch away.
In the box. Every plan.
In the box, on every plan
zuplo test ships with the Zuplo CLI — no testing tier, no separate product, no add-on license. Elsewhere the first-party equivalents often sit behind a paywall: KrakenD's e2e runner is Enterprise-only, Gravitee's Debug mode is Enterprise-only, and Azure's policy debugger is Developer-tier, the tier Microsoft excludes from its production SLA.
Plain TypeScript, standard tools
Tests use fetch and Node's built-in node:assert/strict. describe, it, hooks, and TestHelper come from @zuplo/test — no proprietary DSL, no GUI-authored test documents, no declarative JSON spec format to learn, and no assertion library to install. Under the hood it's the Node.js test runner.
Filter and skip by name
--filter selects tests by name (a plain string or a regex), --skip-filter excludes them, and the two compose. Tag your read-only smoke tests in their names and run just that subset against production.
Green in CI means green in production
Zuplo's GitHub integration fires a deployment_status event after deploying your branch. Trigger a workflow on it, run the
suite against the preview URL, and make the workflow a required status
check — a failing gateway test now blocks the merge.
One discipline the snippet bakes in: poll a health route before running tests instead of sleeping. A deploy reporting success is not the same as a gateway ready to serve traffic, and a blanket retry on a flaky suite is not a fix — it's the pipeline lying about readiness.
Testable by architecture, not by add-on
A real deployment, not a mock
Every branch deploys as a full Zuplo gateway on the same edge network as production, with its own URL. Your pre-merge tests hit real policy execution, real routing, real error handling — so a green check means something.
Config and tests in one PR
routes.oas.json, policies.json, modules/*.ts, and tests/*.test.ts live in the same repo and ship in the same pull request. The reviewer sees the policy change and the test that pins its behavior, side by side.
Testable because it's code
Config-shaped failures — a wrong route, a policy on the wrong path, a missing env var — are a defect class unit tests can't see. Git-native config is the precondition for testing them: there's an artifact to test before deploy, not just a running system to poke afterward.
One suite, three targets, no add-on
As far as we can establish from vendor documentation, no other API gateway offers this conjunction: a first-party test command at no extra tier, tests as ordinary TypeScript in your own repo beside the config they test, and the identical suite running unchanged against localhost, a per-PR preview deployment, and production by changing only the --endpoint flag. Individual clauses have competitors; the conjunction doesn't.
Frequently Asked Questions
Common questions about testing API gateways with Zuplo.
Test at every step
Free Zuplo project, write a test, run it against localhost — then watch the same suite run against a real preview deployment on your first PR.