zuplo 7.4.4 → 7.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/articles/ci-cd-azure/local-testing.mdx +22 -4
- package/docs/articles/ci-cd-bitbucket/local-testing.mdx +22 -4
- package/docs/articles/ci-cd-circleci/local-testing.mdx +21 -4
- package/docs/articles/ci-cd-github/deploy-and-test.mdx +28 -13
- package/docs/articles/ci-cd-github/local-testing.mdx +36 -16
- package/docs/articles/ci-cd-gitlab/local-testing.mdx +22 -4
- package/docs/articles/github-deployment-testing.mdx +118 -31
- package/docs/articles/testing-getting-started.mdx +220 -0
- package/docs/articles/testing-preview-environments.mdx +148 -0
- package/docs/articles/testing-recipes.mdx +429 -0
- package/docs/articles/testing.mdx +138 -408
- package/docs/mcp-gateway/auth/configuring-auth0.mdx +6 -5
- package/docs/mcp-gateway/auth/configuring-clerk.mdx +4 -4
- package/docs/mcp-gateway/auth/configuring-cognito.mdx +5 -4
- package/docs/mcp-gateway/auth/configuring-entra.mdx +5 -4
- package/docs/mcp-gateway/auth/configuring-generic-oidc.mdx +8 -8
- package/docs/mcp-gateway/auth/configuring-google.mdx +4 -4
- package/docs/mcp-gateway/auth/configuring-keycloak.mdx +4 -3
- package/docs/mcp-gateway/auth/configuring-logto.mdx +4 -4
- package/docs/mcp-gateway/auth/configuring-okta.mdx +3 -3
- package/docs/mcp-gateway/auth/configuring-onelogin.mdx +3 -3
- package/docs/mcp-gateway/auth/configuring-ping.mdx +3 -3
- package/docs/mcp-gateway/auth/configuring-workos.mdx +5 -4
- package/docs/mcp-gateway/auth/manual-oauth-testing.mdx +8 -8
- package/docs/mcp-gateway/auth/overview.mdx +17 -17
- package/docs/mcp-gateway/auth/upstream-oauth.mdx +5 -5
- package/docs/mcp-gateway/code-config/local-development.mdx +14 -12
- package/docs/mcp-gateway/code-config/overview.mdx +9 -4
- package/docs/mcp-gateway/connect-clients/chatgpt.mdx +114 -56
- package/docs/mcp-gateway/how-it-works.mdx +11 -9
- package/docs/mcp-gateway/introduction.mdx +3 -1
- package/docs/mcp-gateway/quickstart-local.mdx +7 -7
- package/docs/mcp-gateway/reference.mdx +58 -25
- package/docs/mcp-gateway/server-registry.mdx +179 -0
- package/docs/mcp-gateway/test-clients.mdx +2 -2
- package/docs/mcp-server/custom-tools.mdx +32 -0
- package/docs/programmable-api/mcp-gateway-plugin.mdx +137 -0
- package/docs/programmable-api/mcp-sdk.mdx +240 -0
- package/docs/self-hosted/overview.md +2 -0
- package/package.json +5 -5
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Get started with zuplo test
|
|
3
|
+
sidebar_label: Get started
|
|
4
|
+
description:
|
|
5
|
+
Take a Zuplo project from no tests to a green run against a local dev server
|
|
6
|
+
in three steps. Covers test file location, the TestHelper API, and CLI flags
|
|
7
|
+
for filtering and skipping tests.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
This guide takes a Zuplo project from no tests to a green test run against a
|
|
11
|
+
local dev server, in three steps. It covers where test files live, what
|
|
12
|
+
`TestHelper` gives you, and the CLI flags worth knowing. The only install is one
|
|
13
|
+
assertion library.
|
|
14
|
+
|
|
15
|
+
Every test `zuplo test` runs is an integration test: it makes a real HTTP
|
|
16
|
+
request to a real running gateway and asserts on the real response. The endpoint
|
|
17
|
+
is a command-line flag, so the same files run against local dev, a preview
|
|
18
|
+
deployment, or production.
|
|
19
|
+
|
|
20
|
+
<Stepper>
|
|
21
|
+
|
|
22
|
+
1. **Install an assertion library**
|
|
23
|
+
|
|
24
|
+
`describe`, `it`, the lifecycle hooks, and `TestHelper` come from
|
|
25
|
+
`@zuplo/test`, which arrives transitively with the `zuplo` package. The CLI
|
|
26
|
+
requires Node.js 24.0.0 or later, which every sample here assumes.
|
|
27
|
+
|
|
28
|
+
Assertions in these docs use [`expect`](https://www.chaijs.com/api/bdd/) from
|
|
29
|
+
chai. Chai is **not** included in a new Zuplo project, so install it
|
|
30
|
+
yourself:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install --save-dev chai @types/chai
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The CLI marks `chai` as external when it compiles your tests, so it resolves
|
|
37
|
+
from `node_modules` at run time. Skip the install step and the compiler fails
|
|
38
|
+
with `Cannot find package 'chai'` before any test runs.
|
|
39
|
+
|
|
40
|
+
:::tip
|
|
41
|
+
|
|
42
|
+
Prefer no dependencies? Node's built-in
|
|
43
|
+
[`node:assert/strict`](https://nodejs.org/api/assert.html#strict-assertion-mode)
|
|
44
|
+
works instead and needs nothing installed. The strict form compares with
|
|
45
|
+
`===`, so `assert.equal(200, "200")` fails instead of quietly passing.
|
|
46
|
+
|
|
47
|
+
:::
|
|
48
|
+
|
|
49
|
+
2. **Write the first test**
|
|
50
|
+
|
|
51
|
+
Test files go in a `tests` folder at the root of your project and must end in
|
|
52
|
+
`.test.ts`. Nested folders are fine.
|
|
53
|
+
|
|
54
|
+
```ts title="/tests/health.test.ts"
|
|
55
|
+
import { describe, it, TestHelper } from "@zuplo/test";
|
|
56
|
+
import { expect } from "chai";
|
|
57
|
+
|
|
58
|
+
describe("gateway", () => {
|
|
59
|
+
it("serves the root route", async () => {
|
|
60
|
+
const response = await fetch(TestHelper.TEST_URL);
|
|
61
|
+
expect(response.status).to.equal(200);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`TestHelper.TEST_URL` is whatever you passed to `--endpoint`. Build request
|
|
67
|
+
URLs from it rather than hard-coding a host — that is the single change that
|
|
68
|
+
lets one suite serve every environment:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
const url = (path: string) => new URL(path, TestHelper.TEST_URL).toString();
|
|
72
|
+
|
|
73
|
+
const response = await fetch(url("/v1/orders"));
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
3. **Run it**
|
|
77
|
+
|
|
78
|
+
Start the dev server in one terminal:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npx zuplo dev
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Run the suite in another:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npx zuplo test --endpoint http://localhost:9000
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The CLI discovers every `tests/**/*.test.ts` file, compiles them into
|
|
91
|
+
`.zuplo/__tests__`, and runs them. `.zuplo` is generated output — leave it
|
|
92
|
+
out of source control.
|
|
93
|
+
|
|
94
|
+
:::tip
|
|
95
|
+
|
|
96
|
+
Add the endpoint you use most to a script so the common case is one word:
|
|
97
|
+
|
|
98
|
+
```json title="package.json"
|
|
99
|
+
{
|
|
100
|
+
"scripts": {
|
|
101
|
+
"test": "zuplo test --endpoint http://localhost:9000"
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
:::
|
|
107
|
+
|
|
108
|
+
</Stepper>
|
|
109
|
+
|
|
110
|
+
## TestHelper reference
|
|
111
|
+
|
|
112
|
+
`TestHelper` has two static members.
|
|
113
|
+
|
|
114
|
+
| Member | Type | Description |
|
|
115
|
+
| ------------------------ | ------------------------ | ------------------------------------------------------------------------------------------------------------------ |
|
|
116
|
+
| `TestHelper.TEST_URL` | `string` | The value passed to `--endpoint`. Throws if `zuplo test` was not given one. |
|
|
117
|
+
| `TestHelper.environment` | `Record<string, string>` | The test process environment. This is `process.env` — the two are interchangeable, including anything from `.env`. |
|
|
118
|
+
|
|
119
|
+
`TestHelper.environment` reads the environment of the **test process**, not the
|
|
120
|
+
environment variables configured on your Zuplo project. Those belong to the
|
|
121
|
+
gateway; these belong to the test process. Fixture tokens, API keys, and seed
|
|
122
|
+
data come in this way:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
TENANT_A_JWT=eyJhbGciOi... npx zuplo test --endpoint http://localhost:9000
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
```ts title="/tests/auth.test.ts"
|
|
129
|
+
import { describe, it, TestHelper } from "@zuplo/test";
|
|
130
|
+
import { expect } from "chai";
|
|
131
|
+
|
|
132
|
+
describe("auth", () => {
|
|
133
|
+
it("accepts a valid token", async () => {
|
|
134
|
+
const response = await fetch(`${TestHelper.TEST_URL}/v1/orders`, {
|
|
135
|
+
headers: {
|
|
136
|
+
Authorization: `Bearer ${TestHelper.environment.TENANT_A_JWT}`,
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
expect(response.status).to.equal(200);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The CLI also loads a `.env` file from the directory you run it in, so local
|
|
145
|
+
fixture values can live there instead of on the command line.
|
|
146
|
+
|
|
147
|
+
:::warning
|
|
148
|
+
|
|
149
|
+
Never commit fixture credentials. Keep them in `.env` (gitignored) locally and
|
|
150
|
+
in your CI provider's secret store in the pipeline.
|
|
151
|
+
|
|
152
|
+
:::
|
|
153
|
+
|
|
154
|
+
## Select which tests run
|
|
155
|
+
|
|
156
|
+
Two flags select tests by name. Both match against the full test name, which is
|
|
157
|
+
the `describe` label and the `it` label joined together, so a test named
|
|
158
|
+
`smoke: orders route answers` is selected by `--filter smoke` even when its
|
|
159
|
+
enclosing `describe` does not match.
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
# Only tests whose name contains "auth"
|
|
163
|
+
npx zuplo test --endpoint http://localhost:9000 --filter "auth"
|
|
164
|
+
|
|
165
|
+
# Regex form — wrap the pattern in slashes
|
|
166
|
+
npx zuplo test --endpoint http://localhost:9000 --filter "/#label[Aa]/"
|
|
167
|
+
|
|
168
|
+
# Everything except tests tagged [slow] in their name
|
|
169
|
+
npx zuplo test --endpoint http://localhost:9000 --skip-filter "\[slow\]"
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
`--skip-filter` is applied after `--filter`, so the two compose. This is the
|
|
173
|
+
mechanism behind production smoke checks: name the read-only subset
|
|
174
|
+
consistently, then run only that subset against production.
|
|
175
|
+
|
|
176
|
+
## Skip a test in code
|
|
177
|
+
|
|
178
|
+
Prefix a suite or test with `.skip` (or its alias `.ignore`) to declare it
|
|
179
|
+
without running it:
|
|
180
|
+
|
|
181
|
+
```ts title="/tests/skip.test.ts"
|
|
182
|
+
import { describe, it } from "@zuplo/test";
|
|
183
|
+
import { expect } from "chai";
|
|
184
|
+
|
|
185
|
+
describe("arithmetic", () => {
|
|
186
|
+
it.skip("this test is declared but not run", () => {
|
|
187
|
+
expect(1 + 4).to.equal(6);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it("this test runs", () => {
|
|
191
|
+
expect(1 + 4).to.equal(5);
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
:::caution
|
|
197
|
+
|
|
198
|
+
`.only` takes effect only when the run is started with `--only`. Without the
|
|
199
|
+
flag, `zuplo test` runs the marked test **and every other test** — silently the
|
|
200
|
+
opposite of what you wanted, and it looks like it worked.
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
npx zuplo test --endpoint http://localhost:9000 --only
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
With the flag, only the marked tests and suites execute. If your CLI does not
|
|
207
|
+
recognize `--only`, upgrade the `zuplo` package — or use `--filter` to narrow
|
|
208
|
+
the run by test name, which works on every version.
|
|
209
|
+
|
|
210
|
+
:::
|
|
211
|
+
|
|
212
|
+
## Next steps
|
|
213
|
+
|
|
214
|
+
- [Gateway test recipes](./testing-recipes.mdx) — what to assert at a gateway,
|
|
215
|
+
as copy-pasteable files
|
|
216
|
+
- [Testing preview environments](./testing-preview-environments.mdx) — run the
|
|
217
|
+
same suite against the real deployment of your branch
|
|
218
|
+
- [Testing GitHub deployments](./github-deployment-testing.mdx) — make a failing
|
|
219
|
+
gateway test block the merge
|
|
220
|
+
- [Testing overview](./testing.mdx) — when to run what, and why
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Test preview environments
|
|
3
|
+
sidebar_label: Preview environments
|
|
4
|
+
description:
|
|
5
|
+
Run the same test suite against a real per-branch Zuplo deployment before
|
|
6
|
+
merging. Covers getting the preview URL into your tests, waiting for
|
|
7
|
+
readiness, per-environment secrets, and scoping what runs where.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
A preview environment is a full Zuplo deployment of a branch, on the same edge
|
|
11
|
+
network as production, at its own URL. That makes it the highest-fidelity place
|
|
12
|
+
to run your test suite before a change merges — closer to production than any
|
|
13
|
+
local server, and without the queueing and drift of a shared staging
|
|
14
|
+
environment.
|
|
15
|
+
|
|
16
|
+
Because `zuplo test` takes the target as a flag, the files you run against
|
|
17
|
+
`http://localhost:9000` are the files you run against the preview URL. Nothing
|
|
18
|
+
in the suite changes.
|
|
19
|
+
|
|
20
|
+
## How branches become environments
|
|
21
|
+
|
|
22
|
+
Push a branch to a connected repository and Zuplo deploys it:
|
|
23
|
+
|
|
24
|
+
- The repository's default branch deploys to **Production**.
|
|
25
|
+
- Every other branch deploys to a **Preview** environment with its own URL.
|
|
26
|
+
|
|
27
|
+
For the full mapping, see
|
|
28
|
+
[branch-based deployments](./branch-based-deployments.mdx). For how preview
|
|
29
|
+
environments differ from working copies, see [environments](./environments.mdx).
|
|
30
|
+
|
|
31
|
+
## Get the URL into your tests
|
|
32
|
+
|
|
33
|
+
Preview URLs are derived from the branch name and project, so hard-coding one is
|
|
34
|
+
a maintenance problem. Read the URL from the environment instead.
|
|
35
|
+
|
|
36
|
+
### From the Zuplo GitHub integration
|
|
37
|
+
|
|
38
|
+
The integration reports a GitHub Deployment for each build, and the deployment
|
|
39
|
+
status carries the environment URL. In a workflow triggered by the
|
|
40
|
+
`deployment_status` event, that value is
|
|
41
|
+
`github.event.deployment_status.environment_url`. This is the mechanism used in
|
|
42
|
+
[testing GitHub deployments](./github-deployment-testing.mdx), and it is the
|
|
43
|
+
approach to prefer: no URL construction, and the tests cannot start before the
|
|
44
|
+
deployment exists.
|
|
45
|
+
|
|
46
|
+
### From your own pipeline
|
|
47
|
+
|
|
48
|
+
If you deploy from your own CI with `zuplo deploy`, capture the URL from the
|
|
49
|
+
deploy command's output and pass it through:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
OUTPUT=$(npx zuplo deploy --api-key "$ZUPLO_API_KEY" --environment "$BRANCH" 2>&1)
|
|
53
|
+
echo "$OUTPUT"
|
|
54
|
+
DEPLOY_URL=$(echo "$OUTPUT" | grep -oP 'Deployed to \K(https://[^ ]+)')
|
|
55
|
+
|
|
56
|
+
npx zuplo test --endpoint "$DEPLOY_URL"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
For the complete workflow, see
|
|
60
|
+
[GitHub Actions: deploy and test](./ci-cd-github/deploy-and-test.mdx). For
|
|
61
|
+
pipeline patterns for other providers, see [custom CI/CD](./custom-ci-cd.mdx).
|
|
62
|
+
|
|
63
|
+
## Wait for the environment before testing
|
|
64
|
+
|
|
65
|
+
A deployment reporting success is not the same as a gateway serving traffic, and
|
|
66
|
+
the gap between the two is the single most common cause of "flaky" gateway
|
|
67
|
+
tests. The first few requests fail, the run is retried, and the real problem — a
|
|
68
|
+
race in the pipeline — is filed as test flakiness.
|
|
69
|
+
|
|
70
|
+
Poll a cheap unauthenticated route with a hard deadline instead of sleeping:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
deadline=$((SECONDS + 120))
|
|
74
|
+
until curl --fail --silent --output /dev/null "$API_URL/health"; do
|
|
75
|
+
if ((SECONDS >= deadline)); then
|
|
76
|
+
echo "Gateway at $API_URL not ready after 120s" >&2
|
|
77
|
+
exit 1
|
|
78
|
+
fi
|
|
79
|
+
sleep 2
|
|
80
|
+
done
|
|
81
|
+
|
|
82
|
+
npx zuplo test --endpoint "$API_URL"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
If your gateway has no health route, add one. See
|
|
86
|
+
[health checks](./health-checks.mdx).
|
|
87
|
+
|
|
88
|
+
## Per-environment services and secrets
|
|
89
|
+
|
|
90
|
+
Preview environments have their own configuration, and a test that passes
|
|
91
|
+
locally can fail on a preview for reasons that have nothing to do with your
|
|
92
|
+
change:
|
|
93
|
+
|
|
94
|
+
- **Environment variables.** Values are set per environment in the Zuplo Portal.
|
|
95
|
+
A variable that exists in production but not on the preview is a real defect
|
|
96
|
+
the preview run catches — but assert on the behavior, not on the variable.
|
|
97
|
+
- **API key buckets.** API key authentication is backed by a bucket tied to the
|
|
98
|
+
environment. Keys minted for one environment do not authenticate against
|
|
99
|
+
another, so CI needs a fixture key for the environment it is testing.
|
|
100
|
+
- **Rate limit buckets.** Rate limit state is per environment too. This works in
|
|
101
|
+
your favor: a preview environment's limits are not being consumed by
|
|
102
|
+
production traffic, which is part of what makes the rate limit recipe
|
|
103
|
+
deterministic.
|
|
104
|
+
|
|
105
|
+
Keep fixture credentials in your CI provider's secret store and pass them to
|
|
106
|
+
`zuplo test` as environment variables. Inside the test they are available on
|
|
107
|
+
`TestHelper.environment`:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
TENANT_A_JWT="$PREVIEW_TENANT_A_JWT" npx zuplo test --endpoint "$API_URL"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Scope what runs where
|
|
114
|
+
|
|
115
|
+
The same files can run everywhere, but that does not mean every test runs
|
|
116
|
+
everywhere:
|
|
117
|
+
|
|
118
|
+
| Target | What to run |
|
|
119
|
+
| ----------------------- | --------------------------------------------------------- |
|
|
120
|
+
| `http://localhost:9000` | Everything. Fast feedback while editing. |
|
|
121
|
+
| Preview deployment | Everything. This is the run that gates the merge. |
|
|
122
|
+
| Production | A small, read-only smoke subset selected with `--filter`. |
|
|
123
|
+
|
|
124
|
+
Name the production-safe tests consistently — a `smoke:` prefix works well — and
|
|
125
|
+
select them by name:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
npx zuplo test --endpoint https://api.example.com --filter "smoke"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Nothing with side effects belongs in that subset. See
|
|
132
|
+
[gateway test recipes](./testing-recipes.mdx) for the test data hygiene rules
|
|
133
|
+
that make this safe.
|
|
134
|
+
|
|
135
|
+
## Clean up preview environments
|
|
136
|
+
|
|
137
|
+
Preview environments outlive the branch unless something removes them. Delete
|
|
138
|
+
the branch and the environment goes with it when you use the GitHub integration.
|
|
139
|
+
If you deploy from your own pipeline, add an explicit cleanup step on branch
|
|
140
|
+
delete. See
|
|
141
|
+
[cleanup on branch delete](./ci-cd-github/cleanup-on-branch-delete.mdx).
|
|
142
|
+
|
|
143
|
+
## Related
|
|
144
|
+
|
|
145
|
+
- [Get started with zuplo test](./testing-getting-started.mdx)
|
|
146
|
+
- [Gateway test recipes](./testing-recipes.mdx)
|
|
147
|
+
- [Testing GitHub deployments](./github-deployment-testing.mdx)
|
|
148
|
+
- [Environments](./environments.mdx)
|