Build a Next.js app in Storybook with React Server Components and Mock Service Worker
Storybook 8 (our next major release) brings React Server Component (RSC) compatibility to Storybook for the very first time, letting you build, test and document Next.js server applications in isolation.
In our first demo, we used Storybook to develop a contact card RSC, which accessed contact data both asynchronously and from a file system while simulating server code through module mocks.
When Chuck Norris builds frontend applications, the UI tests itself!
Next, we’ll explore how to build an entire app in isolation with the Next.js App Router, by rebuilding the Hacker Next example in Storybook with the help of Mock Service Worker.
Why build pages in isolation?
It’s amazing how much UI fits into just two pages. Consider the data states your pages need. Then, multiply them by responsive layouts, logged-in views, themes, browsers, locales, and accessibility. It doesn’t take much for a handful of pages to become hundreds of variants.
Storybook solves this complexity by letting you teleport to any UI state by isolating it as a story! If you’re new to Storybook, here’s how stories work.
Interested in taking your Storybook tests even further? Storybook 8 now supports native automated visual tests, so you can catch unexpected visual changes across your entire application in a single button click. Learn more about getting started with the Visual Tests addon.
Writing stories for Hacker Next
First, install Storybook in your Next.js project:
Then, add the experimentalRSC flag to Storybook’s main.ts, and point it to the new stories we’re about to write:
Now, let’s write stories for Hacker Next’s two components: the news homepage and the item page! Here’s what a simple story could look like for the news page:
Though this works, you’ll notice that it’s missing styling. We can fix that by adding a decorator to our .storybook/preview.tsx:
That’s more like it! Now, try doing this for app/item/[id]/(comments)/page.tsx. If you get stuck, check our repo.
Mock ‘n’ roll with Mock Service Worker
Rather than using real data, we want to be able to control the data. This lets us test different states and generate consistent results.
Hacker Next fetches data from a network API, so we’ll mock its requests with Mock Service Worker (MSW).
💡If you follow the space closely, you might ask, ‘Isn’t MSW currently incompatible with Next.js app directory?’ This is true. However, since we’re running it in the browser rather than in Next.js, there’s no problem using MSW with Storybook.
First, let’s add Storybook’s MSW addon to our project. We’ll use the canary version that supports MSW 2.0’s dramatically improved API.
Next, update .storybook/preview.tsx to initialize MSW with the onUnhandledRequest option. This ensures our existing story continues to work.
Now, let’s create a story for Hacker Next’s homepage, featuring a single post:
By mocking two REST API requests from the frontend and hard-coding the responses, we get the following story:
MSW data factories
Hard-coded API responses are difficult to scale. So, let’s write a story that controls page content with a higher level argument! We’ll need to:
Build a simplified in-memory database
Create MSW handlers that read from the database and generate the desired network responses
Write stories to populate the database with test cases
Step 1: Build the database
First, let’s create the database using @mswjs/data (MSW’s data factory library) and Faker.js.
This lets you specify the posts exactly as you want them to appear. When we leave any data unspecified, Faker fills in the gaps. This way, you can create tens or hundreds of posts with minimal code!
Step 2: Create MSW handlers
Next, we’ll update .storybook/preview.tsx with MSW handlers that read from the database. These handlers are available across all your stories and read whatever’s in the database. This means a story’s only job is to fill the database with useful data!
Step 3: Write stories
Finally, we’ll write stories for our new setup.
First, replace your existing Mocked story with a new version using a loader (a function that runs before a story renders). This loader calls our createPost helper function, which 1) instantiates a post and 2) adds it to the in-memory database.
This scheme really shines when you need to create a lot of data at once. To demonstrate this, let’s create a homepage showing 30 posts. And to make it even more powerful, we can allow the number of posts to be controlled interactively in Storybook’s UI:
It’s time to test
Congratulations! You’ve built Hacker Next in Storybook with data that you can customize for different tests. Alternatively, view a demo Storybook (shared via Chromatic) or our repo.
0:00 /0:21 1×
As well as bringing your UI into one place, you’re able to test Hacker Next in ways you couldn’t otherwise.
For example, you can write stories for Hacker Next’s upvote and collapsing comment states by using Storybook’s play function. This is a code snippet that simulates user interactions and runs immediately after a story renders. It can interact with the DOM using Testing-Library and assert using Vitest’s expect and spies.
Here’s a story that uses a play function to upvote the first post on the homepage:
0:00 /0:13 1×
Bringing it all together
In this exercise, we’ve cataloged the key UI states of a Next.js application. Once we have this all in Storybook, we can:
Develop against mocked data even if our backend is under development
Develop hard-to-reach UI states such as a ‘credit card expired’ screen
Instantly run visual regression and a11y tests on every screen, testing across browsers and different resolutions
View production stories next to their design files to ensure smooth handoff
Onboard new developers with living and comprehensive documentation of the entire frontend architecture
Learn more about using Next.js with Storybook
Storybook revolutionized the development of reusable components. Now, you can apply those same benefits to the pages of your applications.
In our next RSC post, we’ll explore module mocking to handle real-world cases where it’s impossible or impractical to mock network requests.
Storybook 8 (our next major release) brings React Server Components support to Storybook!
In our new tutorial, learn how to build, document and test an RSC app in isolation with @nextjs, Storybook, and @ApiMocking ≫https://t.co/SVZ3TNJw1I
— Storybook (@storybookjs) January 18, 2024
Credits
Thanks to Artem Zakharchenko (MSW’s core maintainer) and the Next.js team for their review and guidance!