Overview
The Supertest harness (located in dapp/e2e/supertest) exercises the public-facing API routes using Vitest + Supertest. It currently ships four suites:
api.test.ts— covers the token gate surfaces (/api/openapi,/api/token-status/:tokenId,/api/nonce,/api/gate-access,/api/form-submission-gate) with both happy/sad wallet scenarios and optional OpenAPI validation.jwt.test.ts— drills into JWT issuance/consumption, SIWE vs legacy branches, payload shape, and abuse cases.pinecone.test.ts— runs the MCP JSON-RPC bridge (/api/mcp) includingtools/list,tools/call, JWT gating, and Pinecone vector searches.zz-rateLimit.test.ts— intentionally exhausts the/api/gate-accesslimiter and runs last to avoid consuming limits needed by the other suites.
Every suite imports the shared validateSupertestEnv helper (env.schema.ts) so test runs fail fast when required configuration is missing.
Environment & Configuration
Environment resolution is centralized in vitest.config.supertest.ts:
- Start with
process.env(CI/job variables win). - Overlay
.env.supertestif it exists indapp/. - Fall back to
.envonly when.env.supertestis absent. - Validate the merged object with
supertestEnvSchema.
Key variables (see dapp/.env.supertest.example):
| Variable | Purpose |
|---|---|
TEST_BASE_URL | Target origin (default http://localhost:3000). |
PRIVATE_KEY / TOKEN_ID / CHAIN_ID | Test wallet + token that owns a Colored Key on the configured chain. |
NEXT_PUBLIC_ENABLE_STATE_WORKER | Logged for visibility; tests still probe /api/nonce to detect SIWE vs legacy. |
NEXT_PUBLIC_AI_CHAT_REQUIRES_JWT | Tells MCP tests whether a JWT is mandatory. |
MCP_ENDPOINT | Path to the MCP JSON-RPC bridge (defaults to /api/mcp). |
setup.ts logs the resolved values (with masked secrets) before the first test so you can confirm the harness picked up the right environment.
Running the suites
pnpm vitest --config dapp/e2e/supertest/vitest.config.supertest.tsTips:
- Suites run sequentially (
fileParallelism: false) because they share IP-based rate limits. - Keep
zz-rateLimit.test.tslast so it can safely exhaust thegateAccesslimiter without impacting earlier suites. - The harness attempts to load
public/openapi.json. If the file is missing in a given deployment, the OpenAPI validator quietly disables itself and tests continue. - Output includes a summarized OpenAPI validation report plus JWT payload snippets to help debug server responses.
What each suite covers
api.test.ts
- OpenAPI surface — Fetches
/api/openapi, asserts version3.0.3, and (when available) validates the response against the generated schema viaopenapi-validator.ts. - Token lifecycle — Runs
describe.eachhappy/sad cases to hit/api/token-status/:tokenId(existing vs bogus token IDs) and/api/nonce(expects 200 with nonce when SIWE is enabled or 501 with RFC7807 payload otherwise). - Gate access — Exercises
/api/gate-accessthrough SIWE or legacy envelopes depending on runtime config (detected via/api/nonce). Successful paths store any returned JWTs for reuse tests. - JWT reuse edge cases — Sends valid/invalid/mismatched Bearer headers, tokenId body overrides, malformed headers, and concurrent requests to ensure the handler enforces strict matching.
- Form submission — Posts to
/api/form-submission-gatewith a properly signed legacy envelope, tolerating rate limits or backend 500s but asserting success/authorization codes otherwise. - Global assertions — Waits between tests, prints structured logs, and emits the OpenAPI validation report in
afterAll.
jwt.test.ts
- JWT minting — Verifies that a successful SIWE or legacy gate access call returns an
accessTokenwhen the server is configured to issue JWTs. - Payload inspection — Uses
jwtAssertionsto checksub,tokenId,kind,scopes, timestamp claims, SIWE projection (siwe.*), and the deterministicsiwe_hash. - Authenticated reuse — Replays stored tokens against
/api/gate-accesswith/withouttokenIdin the body, expecting success or precise failures (401 on mismatched IDs, 403 when already used). - Bearer permutations — Validates lower/upper/missing space variants as well as outright malformed tokens, mock JWTs, and invalid formats defined in
jwtScenarios. - Rate limiting & uniqueness — Drives bursts of Bearer calls to detect 429s and confirms new authentications mint unique JWT IDs (
jti) and timestamps. - Introspection — Parses TTL to ensure it falls within the expected 5 minutes–24 hours window and logs helpful debug information when a server declines to issue tokens.
pinecone.test.ts
- Protocol guards — Ensures
/api/mcprejects GET (405), invalid JSON (400), and missing JWTs whenNEXT_PUBLIC_AI_CHAT_REQUIRES_JWTis true. - Tool discovery — Calls
tools/list, asserts the response containspinecone_search, and inspects the tool’s schema. - Vector searches — Issues multiple
tools/callrequests covering default topK, custom topK, metadata toggles, invalid index/namespace, missing params, empty query strings, and concurrent invocations. - JWT handling — Acquires a JWT up front (via SIWE or legacy gate access) when required, then reuses it for the MCP calls; also checks invalid tokens and malformed Bearer headers return 401s.
- Diagnostics — Logs the JWT payload (when present) plus Pinecone content to simplify debugging remote responses.
zz-rateLimit.test.ts
- Limiter exhaustion — Sends a burst of
/api/gate-accessrequests to trigger 429 responses after the configuredgateAccesslimit. - Non-fatal behavior — Logs when rate limiting is disabled and avoids failing the suite in that case.
- Ordering — Prefixed with
zz-so it runs after the other suites.
Coverage map
| Endpoint / Surface | Supertest file | Notes |
|---|---|---|
GET /api/openapi | api.test.ts | Validates status, schema shape, and (optionally) OpenAPI compliance. |
GET /api/token-status/:tokenId | api.test.ts | Happy/sad token IDs plus OpenAPI response validation. |
GET /api/nonce | api.test.ts | Covers SIWE-enabled (200) and disabled (501 ProblemDetails) responses. |
POST /api/gate-access | api.test.ts, jwt.test.ts, zz-rateLimit.test.ts | Legacy + SIWE auth, JWT minting, Bearer reuse, malformed headers, and explicit limiter exhaustion. |
POST /api/form-submission-gate | api.test.ts | Legacy envelope validation, success/error handling, tolerates 429/500 noise. |
POST /api/mcp (JSON-RPC) | pinecone.test.ts | GET guard, invalid JSON, JWT requirements, tools/list, tools/call permutations. |
/api/chat and /api/quota-reset do not have Supertest coverage yet; they rely on unit tests and manual verification. Additions here should be tracked as follow-up work.
Extending the harness
- Share helpers via
jwt.helpers.tsor new modules instead of duplicating logic inside a test file. - Keep rate-limit coverage isolated and running last (prefix with
zz-) so it doesn’t burn limits needed by other suites. - When you add a new endpoint to the tests, update this page (and the relevant API doc) so readers always know which specs are backed by automated coverage.
- If you introduce another OpenAPI slice, register its schema in
openapi-validator.tsor extend the validator to support multiple specs.