Mocking network requests
For components that make network requests (e.g. fetching data from a REST or GraphQL API), you can mock those requests using a tool like Mock Service Worker (MSW). MSW is an API mocking library, which relies on service workers to capture network requests and provides mocked data in response.
The MSW addon brings this functionality into Storybook, allowing you to mock API requests in your stories. Below is an overview of how to set up and use the addon.
The instructions and snippets here are for v3 of the MSW addon. If you're using v2, please refer to an older version of this page for guidance.
After updating msw-storybook-addon to v3, you can migrate your configuration and stories from v2 to v3 automatically using the codemod:
npx msw-storybook-migrateFor more information, see the MSW migration guide.
Set up the MSW addon
First, if necessary, run this command to install MSW and the MSW addon:
npm install msw msw-storybook-addon --save-devIf you're not already using MSW, generate the service worker file necessary for MSW to work:
npx msw init ./public --saveThen ensure the staticDirs property in your Storybook configuration will include the generated service worker file (in /public, by default):
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
import type { StorybookConfig } from '@storybook/your-framework';
const config: StorybookConfig = {
framework: '@storybook/your-framework',
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
staticDirs: ['../public', '../static'],
};
export default config;Finally, initialize the addon and register it for all stories with a project-level loader (if using CSF 3) or by adding the addon to preview.ts (if using CSF Next):
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
import type { Preview } from '@storybook/your-framework';
import { mswLoader } from 'msw-storybook-addon/csf3';
const preview: Preview = {
/*
* Register the MSW loader for all stories
* See https://github.com/mswjs/msw-storybook-addon#csf-30
* to learn how to customize it
*/
loaders: [mswLoader()],
};
export default preview;Mocking REST requests
If your component fetches data from a REST API, you can use MSW to mock those requests in Storybook. As an example, consider this document screen component:
import React, { useState, useEffect } from 'react';
import { PageLayout } from './PageLayout';
import { DocumentHeader } from './DocumentHeader';
import { DocumentList } from './DocumentList';
// Example hook to retrieve data from an external endpoint
function useFetchData() {
const [status, setStatus] = useState<string>('idle');
const [data, setData] = useState<any[]>([]);
useEffect(() => {
setStatus('loading');
fetch('https://your-restful-endpoint')
.then((res) => {
if (!res.ok) {
throw new Error(res.statusText);
}
return res;
})
.then((res) => res.json())
.then((data) => {
setStatus('success');
setData(data);
})
.catch(() => {
setStatus('error');
});
}, []);
return {
status,
data,
};
}
export function DocumentScreen() {
const { status, data } = useFetchData();
const { user, document, subdocuments } = data;
if (status === 'loading') {
return <p>Loading...</p>;
}
if (status === 'error') {
return <p>There was an error fetching the data!</p>;
}
return (
<PageLayout user={user}>
<DocumentHeader document={document} />
<DocumentList documents={subdocuments} />
</PageLayout>
);
}With the MSW addon, we can write stories that use MSW to mock the REST requests. Here's an example of two stories for the document screen component: one that fetches data successfully and another that fails.
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, vue3-vite, etc.
import type { Meta, StoryObj } from '@storybook/your-framework';
import { http, HttpResponse, delay } from 'msw';
import { DocumentScreen } from './YourPage';
const meta = {
component: DocumentScreen,
} satisfies Meta<typeof DocumentScreen>;
export default meta;
type Story = StoryObj<typeof meta>;
// 👇 The mocked data that will be used in the story
const TestData = {
user: {
userID: 1,
name: 'Someone',
},
document: {
id: 1,
userID: 1,
title: 'Something',
brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
status: 'approved',
},
subdocuments: [
{
id: 1,
userID: 1,
title: 'Something',
content:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
status: 'approved',
},
],
};
export const MockedSuccess: Story = {
beforeEach({ msw }) {
msw.use(
http.get('https://your-restful-endpoint/', () => {
return HttpResponse.json(TestData);
}),
);
},
};
export const MockedError: Story = {
beforeEach({ msw }) {
msw.use(
http.get('https://your-restful-endpoint', async () => {
await delay(800);
return new HttpResponse(null, {
status: 403,
});
}),
);
},
};Mocking GraphQL requests
GraphQL is another common way to fetch data in components. You can use MSW to mock GraphQL requests in Storybook. Here's an example of a document screen component that fetches data from a GraphQL API:
import { useQuery, gql } from '@apollo/client';
import { PageLayout } from './PageLayout';
import { DocumentHeader } from './DocumentHeader';
import { DocumentList } from './DocumentList';
const AllInfoQuery = gql`
query AllInfo {
user {
userID
name
}
document {
id
userID
title
brief
status
}
subdocuments {
id
userID
title
content
status
}
}
`;
interface Data {
allInfo: {
user: {
userID: number;
name: string;
opening_crawl: boolean;
};
document: {
id: number;
userID: number;
title: string;
brief: string;
status: string;
};
subdocuments: {
id: number;
userID: number;
title: string;
content: string;
status: string;
};
};
}
function useFetchInfo() {
const { loading, error, data } = useQuery<Data>(AllInfoQuery);
return { loading, error, data };
}
export function DocumentScreen() {
const { loading, error, data } = useFetchInfo();
if (loading) {
return <p>Loading...</p>;
}
if (error) {
return <p>There was an error fetching the data!</p>;
}
return (
<PageLayout user={data.user}>
<DocumentHeader document={data.document} />
<DocumentList documents={data.subdocuments} />
</PageLayout>
);
}This example uses GraphQL with Apollo Client to make network requests. If you're using a different library (e.g. URQL or React Query), you can apply the same principles to mock network requests in Storybook.
The MSW addon allows you to write stories that use MSW to mock the GraphQL requests. Here's an example demonstrating two stories for the document screen component. The first story fetches data successfully, while the second story fails.
import * as React from 'react';
import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client';
import { graphql, HttpResponse, delay } from 'msw';
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.
import type { Meta, StoryObj } from '@storybook/your-framework';
import { DocumentScreen } from './YourPage';
const mockedClient = new ApolloClient({
uri: 'https://your-graphql-endpoint',
cache: new InMemoryCache(),
defaultOptions: {
watchQuery: {
fetchPolicy: 'no-cache',
errorPolicy: 'all',
},
query: {
fetchPolicy: 'no-cache',
errorPolicy: 'all',
},
},
});
//👇The mocked data that will be used in the story
const TestData = {
user: {
userID: 1,
name: 'Someone',
},
document: {
id: 1,
userID: 1,
title: 'Something',
brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
status: 'approved',
},
subdocuments: [
{
id: 1,
userID: 1,
title: 'Something',
content:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
status: 'approved',
},
],
};
const meta = {
component: DocumentScreen,
decorators: [
(Story) => (
<ApolloProvider client={mockedClient}>
<Story />
</ApolloProvider>
),
],
} satisfies Meta<typeof DocumentScreen>;
export default meta;
type Story = StoryObj<typeof meta>;
export const MockedSuccess: Story = {
beforeEach({ msw }) {
msw.use(
graphql.query('AllInfoQuery', () => {
return HttpResponse.json({
data: {
allInfo: {
...TestData,
},
},
});
}),
);
},
};
export const MockedError: Story = {
beforeEach({ msw }) {
msw.use(
graphql.query('AllInfoQuery', async () => {
await delay(800);
return HttpResponse.json({
errors: [
{
message: 'Access denied',
},
],
});
}),
);
},
};Configuring MSW for stories
In the examples above, note how each story is configured using beforeEach on the stories to define the request handlers for the mock server. You can also use beforeEach at the component (meta) level to apply handlers to all stories in that file or at the project level (in preview.ts) to apply them to all stories in the project.
If using CSF 3, you can also use the msw parameter to define handlers for a story, component, or project. See the older version of this page for examples of using the msw parameter.
