How to Mock Storybook Data Fetching Requests With MSW
Mocking fetch requests on Storybook.
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
This lesson preview is part of the Storybook for React Apps course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Storybook for React Apps, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

[00:00 - 00:13] In the previous lesson, we used conditional logic to change the API code so that it serves stub data when running Storybook. However, this means making changes to the application code, which might not be preferred by some developers.
[00:14 - 00:34] We can use yet another approach to deal with data fetching, which is buying marking requests. With this approach, we can keep the original code both from the component and the API, and we now add a marking layer, which will proxy the requests and we'll decide whether the requests go to the backend, or take a turn instead and serve mock responses .
[00:35 - 00:45] This way, you get the tinker with the behavior of the server rather than making changes in the client code. The mocking tool we're going to be using in this course is called mock service worker or MSW for short.
[00:46 - 00:52] One of the best tools out there. Mock service worker also allows us to completely tinker with the requests and change whatever we want in the response.
[00:53 - 01:02] For instance, if you have one error scenarios, you can return a different status code, or if you want a loading scenario, you can force an infinite timeout. There are many, many possibilities.
[01:03 - 01:14] And the other great thing about mock service worker is that once you set up the mock, you can reuse them on Storybook, unit tests, end-to-end tests, and even development . And mock service worker supports both REST and GraphQL APIs.
[01:15 - 01:19] Thankfully, there is an official Storybook add-on from the maintainers. It's called MSW Storybook add-on.
[01:20 - 01:27] Let's add it to our project. So the first thing we do is to make sure to undo the changes from the previous lesson, because we don't want them anymore.
[01:28 - 01:37] So we just change the import from condition logic to index in the hooks file under API folder. Next, we need to kill Storybook and install the new dependencies.
[01:38 - 01:51] So we do yarn add MSW, as well as MSW Storybook add-on -g to save as dev dependency. The next step is to generate a service worker file in the public folder of our application.
[01:52 - 02:00] We run the following command in the root of the project. NPX, MSW, init, and then we define the folder which we want, which is called public.
[02:01 - 02:07] And we say yes to the prompt. The mock service worker should now be added in under the public folder over here.
[02:08 - 02:20] And we need to make sure that Storybook serves the public folder so that the mock service worker will be available once requested by the add-on. In order to do so, we go to our main.ds file and then we add a new configuration.
[02:21 - 02:30] It's called static.dirs. And then it's an array of paths that we define to Storybook which are the static folders that Storybook should host as assets.
[02:31 - 02:42] And over here, relative to the Storybook folder, so one level above, we add the public folder. And the last step is to go to our decorators file and register the decorator coming from the mock service worker add-on.
[02:43 - 02:52] So over here, we import two things from MSW Storybook add-on. The first one is called initialize.
[02:53 - 03:04] And that's essentially a function which will initialize the service worker every time that Storybook runs. And the second is the mock service worker decorator which will allow every story to contain the mock configuration.
[03:05 - 03:13] So we have to make sure to call the initialize function in the very beginning. And we just add the mock service worker decorator over here.
[03:14 - 03:24] And because it's a global decorator, it will be applied to every single story and that should be enough to get us started. So let's run Storybook again by typing our own Storybook.
[03:25 - 03:34] And we should see that our story is still making a fetch request. If we open the console and we refresh the browser, we will see that mock service worker is enabled.
[03:35 - 03:49] So this basically means that whenever there are any fetch requests being done by any part of Storybook, they will be intercepted by mock service worker. And you can see here that there were actually some requests made using this URL which they were not captured by mock service worker.
[03:50 - 04:01] So the add-on actually tells you whether there are requests which you should or should not be mocking. So in order to actually mock those requests from our story, all we have to do is to add a MSW parameter to our story.
[04:02 - 04:12] So let's go back to the restaurants section, stories file. And in order to add a mock service worker configuration, you need to add a MSW parameter.
[04:13 - 04:19] So let's do that. And then the MSW parameter has a property called handlers, which could be an array or an object.
[04:20 - 04:24] And in this case, we just want to put an array of requests. And to build that, we need a couple of things.
[04:25 - 04:44] We need to import first of all a REST from mock service worker, which is the operator which will allow us to construct a request handler. We also need to import the base URL, which is available under the four levels above the API.
[04:45 - 05:04] And it's just called base URL, which is used to fetch restaurant data as well as the stubs, also from four levels above, under stub restaurants, because we also want the stub data to be used here. So once we have all of that, we go to the handlers over here, and then we define it this way.
[05:05 - 05:11] So it's called rest dot, and then the time that you want. And in this case, the component is making a get request.
[05:12 - 05:27] And then you define the path which we have, which is the base URL. And then the second one is a callback that contains a request, the response, a context object, which allows you to respond with a JSON using context.json.
[05:28 - 05:36] And then over here, you define what you want this to be responded with, which in this case is going to be the restaurants data that we have defined from the top. And that's it.
[05:37 - 05:51] Now, when we check the story and we see the network panel, if we switch between stories, you will see that the request is still being done by the component. However, if we look into the details, you will see that the response is actually being served from the service worker.
[05:52 - 05:59] And that's just great. So if we can do the success state in the service worker, we can also do a loading state over here.
[06:00 - 06:10] Now more service worker can simulate loading states by manipulating the requests, essentially just making it so that it will never be resolved. So what we can do here is just, you know, copy paste this story.
[06:11 - 06:20] And then instead of using default, we call this loading. And instead of using the arcs from here, we just destructured the arcs from default.
[06:21 - 06:28] In case we ever update this, this will also be updated. And in the mock service worker parameter, instead of resolving with context.
[06:29 - 06:40] json and the mock data, we will just call this context.delay. And then over here, we can pass infinite, which will tell mock service worker to basically never resolve this request.
[06:41 - 06:49] So when we're back to Storybook, we see that there's a new loading story. And once we click on it, we see that there is a request being made, but it's just going to be pending forever.
[06:50 - 06:58] And with that, we conclude the usage of MSW in our story. We managed to achieve the states we wanted while the component still fetches data just like it's done in production.
[06:59 - 07:03] But with the values being proxied and mocked by mock service worker. Isn't that awesome?
[07:04 - 07:11] For the rest of this course, the chosen approach to handling data fetching components will be in mock service worker. But then again, are there any downsides to this approach?
[07:12 - 07:24] While depending on your code base, there might be already other server marking tools, like Mirage.js for instance, so you might as well use those instead. Also, some people might consider a downside to add more dependencies to a project, as it can add to the maintenance burden.
[07:25 - 07:34] So after we learned all of these different ways to handle data fetching, just keep in mind that there are no absolute correct answers. Pick whatever approach works best for you and your project.
[07:35 - 07:43] Just make sure that your components in Storybook are not doing requests, so your Storybook is always 100% reliable. So I really hope you enjoyed this module because it was a lot of fun, and I will see you in