Half of "flaky" integration tests are really environment-dependency tests: they fail when a downstream service is slow, redeploying, or returning yesterday's schema. Contract-accurate mocks generated from the OpenAPI spec or from recorded traffic kill that class of flake at the source — if you keep the mocks honest.
Tier: Core · Workflow area: Test data & environments
This playbook takes you from an API spec (or a captured request/response log) to a running WireMock or MSW mock layer, with AI doing the tedious translation and a drift check that stops the mocks from quietly lying about the real service.
Start with Prism to see what "free" gets you. Prism serves a mock straight from the spec, with generated examples:
npx @stoplight/prism-cli mock payments-v2.yaml --port 4010
curl -s localhost:4010/v2/charges/ch_123 | head -5
{ "id": "string", "amount": 0, "currency": "string", "status": "succeeded" }
Spec-generated values are schema-valid but semantically useless ("currency": "string"). Prism is your smoke layer; authored stubs are where the value is.
Have the assistant author realistic stubs from the spec. Paste the relevant paths and schemas, not the whole 9,000-line file:
Here are the /v2/charges paths and Charge/Error schemas from our payments
OpenAPI spec. Generate WireMock stub mappings (JSON) for:
- POST /v2/charges happy path: realistic field values, ISO currency, unix timestamps.
- 402 card_declined and 429 rate_limited using the Error schema exactly.
- A 200 whose body is valid JSON but MISSING the optional "receipt_url" field.
Use response templating for the id field. Do not invent fields that are not
in the schema. If the schema is ambiguous, ask before guessing.
The "do not invent fields" line matters: assistants pad responses with plausible-looking extras, and your client code may start depending on fields the real API never sends.
For recorded traffic, capture then sanitize. WireMock's record mode proxies real calls and writes mappings:
java -jar wiremock-standalone.jar --port 8080 \
--proxy-all="https://api.partner.example" --record-mappings
Then hand the recorded mappings to the assistant with one job: "Replace every real account id, email, token, and card fragment with obviously fake but format-valid values. Change nothing else — not status codes, not headers, not field order." Diff its output against the original before committing; the diff should touch only the values you asked about.
Ask for the edge cases the spec implies but the traffic never showed. Recorded traffic is a survey of the happy path. Prompt: "Given this schema, list response shapes a robust client must tolerate that do not appear in these recordings — nulls in optional fields, empty arrays, maximum-length strings, unknown enum values." Turn the plausible ones into stubs; discard the ones the contract genuinely forbids.
Wire the mocks into tests explicitly, not ambiently. MSW example for a front-end suite:
server.use(
http.post('*/v2/charges', () =>
HttpResponse.json(cardDeclined402, { status: 402 })
)
);
Each test states the world it runs in. A global "everything is mocked" setup file is how teams forget which behavior is real.
Install the drift check. Mocks rot the day the provider ships v2.1. Add a scheduled CI job that replays each stub's request against the real sandbox (or validates stubs against the latest spec with Prism's --errors mode) and fails on shape mismatch. When it fails, regenerate the affected stubs — same prompts, new spec — rather than patching by hand.
A mock is a cached claim about another team's service. The generation step is cheap and repeatable; the drift check is what makes the claim trustworthy six months later.
openapi-schema-validator in CI).{"error": "..."} the assistant improvised.created_by, metadata, or camelCase twins of snake_case fields. Schema validation catches this; eyeballs do not.Keep the generation prompt in the repo next to the stubs (stubs/PROMPT.md). When the spec changes, anyone can regenerate in two minutes instead of reverse-engineering what the last person asked for — the prompt is the source; the stubs are build artifacts.