API Mocking & Contract Testing
Mock APIs at the network level with MSW, generate contract tests with Pact, and create realistic test fixtures for reliable front-end development.
API mocking decouples frontend development and testing from backend availability. MSW (Mock Service Worker) intercepts requests at the network layer - the same mock code works in tests, Storybook, and the browser, with no changes to application code.
Use MSW as your primary mocking tool - it intercepts at the network level so your app code is identical in test and production. Use Pact for consumer-driven contracts to detect API breakage without end-to-end tests. Generate realistic data with faker.js factories.
Workflow
- Set up MSW for browser and Node environmentsOne handler definition works in Jest, Vitest, Storybook, and the browser - DRY mocking.
- Write realistic handlers with request inspectionHandlers that always return the same response don't test conditional logic.
- Build fixture factories with faker.jsHardcoded test data misses edge cases; faker generates realistic, varied data automatically.
- Implement Pact consumer-driven contract testsTraditional API tests break silently when the API changes. Pact publishes contracts that providers must verify - catching breaking changes before deployment.
- Use MSW in Storybook for UI developmentStories with real-looking data from MSW enable UI development without a running backend.
Output Format
MSW handlers covering all API endpoints, Pact consumer tests for critical integrations, faker.js factories for test data, Storybook stories with MSW integration.
Examples
MSW handler: `http.post("/api/login", async ({ request }) => { const { email } = await request.json(); return email === "admin@test.com" ? HttpResponse.json({ token: "fake-jwt" }) : HttpResponse.json({ error: "Invalid credentials" }, { status: 401 }) })`Faker factory: `const createProduct = (overrides = {}) => ({ id: faker.string.uuid(), name: faker.commerce.productName(), price: parseFloat(faker.commerce.price({ min: 5, max: 500 })), ...overrides })`Test override: `it("shows empty state", () => { server.use(http.get("/api/items", () => HttpResponse.json([]))); render(<ItemList />); expect(screen.getByText("No items found")).toBeInTheDocument(); })`Edge Cases & Gotchas
- MSW and third-party SDKs: SDKs that bypass fetch (e.g., WebSocket, XHR in legacy code) need additional MSW setup or different mocking strategies
- Pact version compatibility: consumer and provider must agree on the pact specification version; enforce this in Pact Broker settings
- Streaming APIs: MSW supports ReadableStream for streaming responses; test SSE and streaming fetch with `new ReadableStream(...)` in HttpResponse
When to Break These Rules
- For pure unit tests of isolated functions that don't make HTTP calls, MSW adds unnecessary setup complexity - mock at the module level instead.
Reference Files
MSW docs: https://mswjs.io/Pact Foundation: https://docs.pact.io/Faker.js: https://fakerjs.dev/MSW Storybook addon: https://storybook.js.org/addons/msw-storybook-addon