| name | MSW API Mocking |
| description | Mock Service Worker v2 patterns - http and graphql request handlers, setupServer for Node test runs, setupWorker for the browser, per-test handler overrides, and strict unhandled-request policies. |
| version | 1.0.0 |
| author | thetestingacademy |
| license | MIT |
| tags | ["msw","mocking","api-mocking","service-worker","jest","vitest","react","graphql","network"] |
| testingTypes | ["unit","integration","api"] |
| frameworks | ["jest","vitest"] |
| languages | ["typescript"] |
| domains | ["web","api"] |
| agents | ["claude-code","cursor","github-copilot","windsurf","codex","aider","continue","cline","zed","bolt","gemini-cli","amp"] |
MSW API Mocking
This skill makes an AI agent mock HTTP and GraphQL APIs at the network level with Mock Service Worker v2: one set of request handlers shared between Vitest/Jest (via setupServer) and the browser (via setupWorker), per-test overrides with server.use, and an onUnhandledRequest: 'error' policy that catches drift. Trigger it when components or services call fetch/axios in tests, when msw appears in package.json, or when the user is stubbing global.fetch by hand and suffering for it.
Core Principles
- Mock the network, not the module.
vi.mock('./api-client') couples tests to an import path and skips serialization, query strings, and status handling. MSW intercepts actual requests, so the entire client stack (interceptors, retries, parsing) stays under test.
- One
handlers.ts is the contract. Define happy-path handlers once; tests, Storybook, and local dev all consume the same array. When the real API changes, you update one file and every consumer notices.
- Happy path in global handlers, failures per test. The default handlers return realistic success responses. Error cases (
500, 422, timeouts) are declared inside the test that needs them via server.use(...), which prepends a one-off override.
onUnhandledRequest: 'error' always. Any request without a handler should fail the test loudly. Silent passthrough is how a "unit" test ends up hitting production from CI.
- Reset handlers after every test.
server.resetHandlers() in afterEach removes per-test overrides; without it, test order starts to matter and the suite rots.
- Respond with realistic shapes and status codes. Use the same field names, casing, pagination envelopes, and error bodies the real API returns; mocks that drift teach your code to handle an API that does not exist.
Setup
npm install --save-dev msw
npx msw init public/ --save
Shared handlers
import { http, HttpResponse, delay } ;
{
: ;
: ;
: | ;
}
handlers = [
http.(, {
.<>({
: (params.),
: ,
: ,
});
}),
http.(, {
url = (request.);
page = (url..() ?? );
.({
: [{ : , : }],
page,
: ,
});
}),
http.(, ({ request }) => {
body = ( request.()) { ?: ; ?: };
(!body.) {
.({ : }, { : });
}
();
.({ : , ...body }, { : });
}),
];