Loading states with Storybook and Mock Service Worker
Tags: react, storybook, graphql, testing
Published: 2020-12-05 19:31:53

So there I am wanting to make [Storybook](https://storybook.js.org/) stories for four states of a component that fetches its own data by way of an [Apollo  Client](https://www.apollographql.com/docs/react/) hook.

The four states are:

* Loading 🐌
* Error 🚨
* No data 📭
* Data 😊

I have [Mock Service Worker (MSW)](https://mswjs.io/) set up to intercept network calls. It's pretty straight forward to set up the mocks for the two data states (empty and present) with MSW's [`context.data`](https://mswjs.io/docs/api/context/data) and the error state with [`context.errors`](https://mswjs.io/docs/api/context/errors).

But how do I render a component in its loading state indefinitely for the purpose of viewing it in a Storybook demo?

I didn't find anything existing on the usual suspects of Stack Overflow, GitHub issues, and or here on DEV, so I went back to the MSW docs and found the perfect solution:

[**`context.delay`**](https://mswjs.io/docs/api/context/delay)

I tried using `Infinity` as the duration at first, but to no avail. I figure one hour is more than enough to adequately work on or review the loading state UI.

Here is my final implementation:

```tsx
graphql.query<GetTagsQuery, GetTagsQueryVariables>(
  "GetTags",
  (_req, res, ctx) => {
    // 1 hour delay to view the loading state
    return res(
      ctx.delay(1000 * 60 * 60 * 60), 
      ctx.data(newGetTagsData({}))
    );
  }
)
```

And here is all of the relevant story code:

```tsx
import * as React from "react";
import { Flex, Heading } from "@chakra-ui/react";
import { Meta, Story } from "@storybook/react";
import { worker } from "mocks/browser";
import { graphql } from "msw";

import { GetTagsQuery, GetTagsQueryVariables, newGetTagsData } from "api";

import ViewTags from ".";

export default {
  title: "Features/View Tags",
  component: ViewTags,
  decorators: [
    (story) => (
      <Flex py="20" flex="1" direction="column" justify="center" align="center">
        <Heading mb={4} fontSize="6xl">
          Avett Rx
        </Heading>
        {story()}
      </Flex>
    ),
  ],
} as Meta;

const Template: Story = () => <ViewTags />;

export const Loading: Story = Template.bind({});
Loading.decorators = [
  (story) => {
    worker.use(
      graphql.query<GetTagsQuery, GetTagsQueryVariables>(
        "GetTags",
        (_req, res, ctx) => {
          // 1 hour delay to view the loading state
          return res(
            ctx.delay(1000 * 60 * 60 * 60), 
            ctx.data(newGetTagsData({}))
          );
        }
      )
    );
    return story();
  },
];

```

{% youtube T8vs13sT-04 %}

This use case comes from an article I'm publishing soon that outlines setting up a project with all of my favorite tools for React development in 2020:

* [Next.js](https://nextjs.org/)
* [TypeScript](https://www.typescriptlang.org/)
* [Vercel](https://vercel.com/)
* [Prettier](https://prettier.io/)
* [ESlint](https://eslint.org/)
* [Lint Staged](https://github.com/okonet/lint-staged)
* [Husky](https://typicode.github.io/husky/#/)
* [TypeScript ESLint](https://github.com/typescript-eslint/typescript-eslint)
* [Chakra UI](https://chakra-ui.com/)
* [Fauna](https://fauna.com/)
* [GraphQL Code Generator](https://graphql-code-generator.com/)
* [Apollo Client](https://www.apollographql.com/docs/react/)
* [Storybook](https://storybook.js.org/)
* [Jest](https://jestjs.io/)
* [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/)
* [Cypress](https://www.cypress.io/)
* [Mock Service Worker](https://mswjs.io/)
* [GitHub Actions](https://github.com/features/actions)

👀 Keep an eye out for it! 👀