← Recipes

阅读中文版本

Capture HTTP Replay Fixtures for Deterministic Tests

Record real HTTP responses into version-controlled fixtures, redact secrets, and replay them in tests so the suite never hits the network and stays deterministic.

~40 mintestinghttpfixtures

Task

Record a set of HTTP interactions as fixtures and replay them in the test suite so tests pass offline and without rate limits.

When to use this

The integration tests call a third-party API that rate-limits and occasionally returns flaky 503s. CI is green locally and red on the agent because the network is the variable. The team wants the network out of the loop.

Prerequisites

  • Node.js 20 LTS with vitest or jest
  • A recorded session of the HTTP calls the tests make
  • A redaction list for headers and body fields that carry secrets

Steps

1. Install a record-and-replay proxy that writes fixtures in a format your test runner can consume.

pnpm add -D @mswjs/interceptors

Expected output: The interceptor library is in devDependencies and can intercept fetch and axios in the test process.

2. Record a session by running the tests once with recording enabled and the real network available.

const interceptor = new MockInterceptor();
await interceptor.record({ file: "fixtures/api.json" });

Expected output: A fixtures/api.json file appears with one entry per request, including method, URL, status, headers, and body.

3. Redact secrets from the recorded fixtures before committing them.

node tools/redact-fixtures.mjs fixtures/api.json

Expected output: Authorization headers and token fields are replaced with REDACTED and the file diff is safe to commit.

4. Replay the fixtures in CI by starting the interceptor in mock mode before the tests run.

await interceptor.mock({ file: "fixtures/api.json" });

Expected output: The test suite passes with the network cable unplugged, in the same order and with the same assertions.

Troubleshooting

Problem

A test makes a new request not in the fixture

Solution

The interceptor fails the test with a clear unmatched-request error; re-record the fixture or add the missing interaction by hand.

Problem

Timestamps in the replayed body break assertions

Solution

Use a response transformer to freeze dynamic fields, or assert on shape with a schema rather than on exact values.

Limitations

  • Fixtures go stale when the API contract changes; re-record on contract drift, not on a schedule.
  • Replay cannot reproduce server-side state transitions, so tests that depend on write-then-read ordering still need an in-memory stub.

Record once, replay many

A record-and-replay proxy captures the real HTTP responses the first time the tests run, then serves them from disk on every subsequent run. The suite becomes deterministic: the same fixtures produce the same assertions, with no network and no rate limits.

const interceptor = new MockInterceptor();
await interceptor.record({ file: 'fixtures/api.json' });

Redact before you commit

Fixtures live in version control, so strip every secret before they land in the repo. Replace Authorization headers and token fields with a placeholder, and fail CI if a fixture contains a string that matches a known secret pattern.

node tools/redact-fixtures.mjs fixtures/api.json

Expected outcome

The test suite passes with the network unplugged, an unmatched request fails immediately with a clear error, and the committed fixtures contain no secrets. Re-record when the API contract changes, not on every run.