Skip to main content
Version: 6.1

Mocking data for Storybook

Storybook is a great utility to do isolated development and testing, potentially speeding up development time greatly.

<MockResolver /> enables easy loading of fixtures to see what different network responses might look like. It can be layered, composed, and even used for imperative fetches like create and update.

Setup#

export default class ArticleResource extends Resource {  readonly id: number | undefined = undefined;  readonly content: string = '';  readonly author: number | null = null;  readonly contributors: number[] = [];
  pk() {    return this.id?.toString();  }  static urlRoot = 'http://test.com/article/';}

Fixtures#

We'll test three cases: some interesting results in the list, an empty list, and data not existing so loading fallback is shown.

fixtures.ts
export default {  full: [    {      endpoint: ArticleResource.list(),      args: [{ maxResults: 10 }] as const,      response: [        {          id: 5,          content: 'have a merry christmas',          author: 2,          contributors: [],        },        {          id: 532,          content: 'never again',          author: 23,          contributors: [5],        },      ],    },    {      endpoint: ArticleResource.update(),      args: [{ id: 532 }] as const,      response: {        id: 532,        content: 'updated "never again"',        author: 23,        contributors: [5],      },    },  ],  empty: [    {      endpoint: ArticleResource.list(),      args: [{ maxResults: 10 }] as const,      response: [],    },  ],  error: [    {      endpoint: ArticleResource.list(),      args: [{ maxResults: 10 }] as const,      response: { message: 'Bad request', status: 400, name: 'Not Found' },      error: true,    },  ],  loading: [],};

Decorators#

You'll need to add the appropriate global decorators to establish the correct context.

This should resemble what you have added in initial setup

.storybook/preview.tsx#

import { Suspense } from 'react';import { CacheProvider, NetworkErrorBoundary } from 'rest-hooks';
export const decorators = [  Story => (    <CacheProvider>      <Suspense fallback="loading">        <NetworkErrorBoundary>          <Story />        </NetworkErrorBoundary>      </Suspense>    </CacheProvider>  ),];

Story#

Wrapping our component with \

enables us to declaratively control how Rest Hooks' fetches are resolved.

Here we select which fixtures should be used by storybook controls.

ArticleList.stories.tsx#

import { MockResolver } from '@rest-hooks/test';import type { Fixture } from '@rest-hooks/test';import { Story } from '@storybook/react/types-6-0';
import ArticleList from 'ArticleList';import options from './fixtures';
export default {  title: 'Pages/ArticleList',  component: ArticleList,  argTypes: {    result: {      description: 'Results',      defaultValue: 'full',      control: {        type: 'select',        options: Object.keys(options),      },    },  },};
const Template: Story<{ result: keyof typeof options }> = ({ result }) => (  <MockResolver fixtures={options[result]}>    <ArticleList maxResults={10} />  </MockResolver>);
export const FullArticleList = Template.bind({});
FullArticleList.args = {  result: 'full',};