Pular para o conteúdo principal

Simulando dados para o Storybook

O Storybook é uma ótima ferramenta para desenvolvimento e testes isolados, podendo acelerar bastante o tempo de desenvolvimento.

O <MockResolver /> permite carregar com facilidade fixtures ou interceptors para ver como diferentes respostas de rede podem se parecer. Ele pode ser aninhado, composto e até usado para fetches imperativos, geralmente usados com endpoints que têm efeitos colaterais, como getList.push e update.

Configuração​

ArticleResource.ts
export class Article extends Entity {
id: number | undefined = undefined;
content = '';
author: number | null = null;
contributors: number[] = [];

static key = 'Article';
}
export const ArticleResource = resource({
urlPrefix: 'http://test.com',
path: '/article/:id',
schema: Article,
searchParams: {} as { maxResults: number },
});

export let ArticleFixtures: Record<string, Fixture[]> = {};

Fixtures​

Vamos testar três casos com nossos fixtures e interceptors: alguns resultados interessantes na lista, uma lista vazia e dados inexistentes, de modo que o fallback de carregamento seja exibido.

ArticleResource.ts
// leave out in production so we don't bloat the bundle
if (process.env.NODE_ENV !== 'production') {
ArticleFixtures = {
full: [
{
endpoint: ArticleResource.getList,
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,
response: ({ id }, body) => ({
...body,
id,
}),
},
],
empty: [
{
endpoint: ArticleResource.getList,
args: [{ maxResults: 10 }] as const,
response: [],
},
],
error: [
{
endpoint: ArticleResource.getList,
args: [{ maxResults: 10 }] as const,
response: {
message: 'Bad request',
status: 400,
name: 'Not Found',
},
error: true,
},
],
loading: [],
};
}

Decorators​

Você precisará adicionar os decorators globais apropriados para estabelecer o contexto correto.

Isso deve se parecer com o que você adicionou na configuração inicial

.storybook/preview.tsx
import { Suspense } from 'react';
import { DataProvider, AsyncBoundary } from '@data-client/react';

export const decorators = [
Story => (
<DataProvider>
<AsyncBoundary>
<Story />
</AsyncBoundary>
</DataProvider>
),
];

Story​

Envolver nosso componente com o <MockResolver /> nos permite controlar de forma declarativa como os fetches do Reactive Data Client são resolvidos.

Aqui selecionamos quais fixtures devem ser usados pelos controles do storybook.

ArticleList.stories.tsx
import { type StoryObj } from '@storybook/react';
import { MockResolver } from '@data-client/test';
import type { Fixture } from '@data-client/test';

import ArticleList from 'ArticleList';
import { ArticleFixtures } from 'resources/ArticleResource';

export default {
title: 'Pages/ArticleList',
component: ArticleList,
argTypes: {
result: {
description: 'Results',
defaultValue: 'full',
control: {
type: 'select',
options: Object.keys(ArticleFixtures),
},
},
},
};

export const FullArticleList: StoryObj<{ result: keyof typeof ArticleFixtures }> =
{
render: ({ result }) => (
<MockResolver fixtures={ArticleFixtures[result]}>
<ArticleList maxResults={10} />
</MockResolver>
),
args: { result: 'full' },
};