Mock API requests in Storybook with Mock Service Worker.
npm i msw-storybook-addon -DMake sure you have
msw@2.xinstalled as a peer dependency.
Next, use the MSW CLI to generate a worker script at the given path:
npx msw init ./public --saveReplace
./publicwith the path to your static directory of Storybook.
The loader API for CSF 3.0 is deprecated. Please consider using the CSF Next API instead.
// .storybook/main.ts
export default {
addons: ['msw-storybook-addon'],
}// .storybook/preview.ts
import { mswLoader } from 'msw-storybook-addon/csf3'
export default {
loaders: [mswLoader()],
parameters: {
msw: [...initialHandlers]
}
}If you are using the CSF Next syntax (also known as CSF Factories), it's enough to import and call the addon function in preview.ts:
// .storybook/preview.ts
import addonMsw from 'msw-storybook-addon'
export default definePreview({
addons: [addonMsw()],
})
parameters.mswis not supported in CSF Next. It is preserved only for CSF 3.0 to make migration easier — use thebeforeEachhook instead.
The addon types context.msw (and, for CSF 3.0, parameters.msw) through module augmentation. That augmentation ships with every entrypoint of the addon, so it is applied to any TypeScript program that imports the addon.
CSF Next: nothing to do. Your stories import preview, and preview imports the addon, so the types reach every story automatically.
CSF 3.0, or any setup where the stories are compiled without .storybook/preview.ts (e.g. a tsconfig.json whose include doesn't cover the .storybook directory): reference the types explicitly in your tsconfig.json:
{
"compilerOptions": {
"types": ["msw-storybook-addon/types"]
}
}In CSF 3.0, reference
msw-storybook-addon/csf3instead — it typesparameters.mswas well.
By default, the addon creates and starts the worker for you: it starts quietly and ignores common asset and Storybook-internal requests. To customize that behavior (e.g. worker.start() options or initial handlers), provide a setup function that creates the worker, starts it, and returns it.
In CSF 3.0, pass it to mswLoader:
// .storybook/preview.ts
import { setupWorker } from 'msw/browser'
import { mswLoader } from 'msw-storybook-addon/csf3'
export default {
loaders: [
mswLoader(async () => {
const worker = setupWorker()
await worker.start({ onUnhandledRequest: 'bypass' })
return worker
})
]
}In CSF Next, pass it to addonMsw:
// .storybook/preview.ts
import { setupWorker } from 'msw/browser'
import addonMsw from 'msw-storybook-addon'
export default definePreview({
addons: [
addonMsw(async () => {
const worker = setupWorker()
await worker.start({ onUnhandledRequest: 'bypass' })
return worker
})
],
})Handlers passed to
setupWorker()act as initial handlers and survive the automatic handler reset between stories.
If you have correctly installed and configured this addon, it will extend your story context with the msw property. Use that reference to control API mocking in your stories, e.g. by adding request handler overrides via msw.use().
Provide request handlers in preview.ts to define the network behaviors that affect all your stories.
// .storybook/preview.ts
import { http, HttpResponse } from 'msw'
export default {
beforeEach({ msw }) {
msw.use(
http.get('https://api.acme.com/user', () => {
return HttpResponse.json({ name: 'John Maverick' })
}),
)
},
}To describe network behaviors on a story basis, add them in the beforeEach hook of the respective story.
export const UserProfileNetworkError: Story = {
beforeEach({ msw }) {
msw.use(
http.get('https://api.acme.com/user', () => {
return HttpResponse.error()
}),
)
},
}