Introdução ao Storybook: um exemplo prático com Angular

Vanessa Ortega
5 min readMar 28, 2024

--

O elemento mais importante dentro de todo o ecossistema Angular é o componente. Temos diversos outros artefatos mas é sobre o componente que a aplicação é construída. Os componentes da interface do usuário (em algumas abordagens chamados de dumb ou presentational components), no mundo ideal, deveriam ser blocos totalmente independentes e reutilizáveis. E é para tentar atingir este cenário, no mundo real, que existe o Storybook.

Photo by S O C I A L . C U T on Unsplash

O Storybook é uma ferramenta para construir, testar e documentar componentes da interface do usuário de forma isolada. Ele é open source, free e utilizado por umas empresas grandes e famosas que conhecemos. Ele usa uma abordagem chamada component driven user interface que nos encoraja a criar uma biblioteca testada e documentada de pequenos componentes independentes reutilizáveis.

Photo by https://storybook.js.org/

Setup do projeto

Vou adicionar o Storybook a uma aplicação Angular que acabei de criar com ng new. Na aplicação, tenho somente um componente de UI que é um card. Recomendo criar uma pasta separada para manter apenas os componentes de UI que serão testados e documentados pelo Storybook. Na minha aplicação, será a pasta ui. Na pasta da aplicação vou, então, executar o comando abaixo (e instalar, também, o Compodoc):

npx storybook@latest init

Este comando vai:

  • instalar o Storybook (e suas dependências);
  • gerar os arquivos de configuração;
  • adicionar alguns scripts ao package.json;
  • criar algumas histórias de exemplo.

Após a instalação, o comando abaixo carregará uma instância local do Storybook, comumente na porta 6006:

npm run storybook

O que é uma história?

Antes de mais nada, não confunda com história do usuário. No contexto do Storybook, uma história é um estado (renderizado) do componente de UI. Vamos supor que temos um botão que pode estar ativo ou desabilitado. Temos 2 estados possíveis diferentes para renderizar o botão. Temos, portanto, 2 histórias no Storybook. Se um estado diferente não apresenta uma diferença visual no componente (o que não é recomendado do ponto de vista de UX, mas enfim…), então não temos uma história adicional no Storybook. Por isso reforcei que é um estado renderizado do componente. Cada componente pode, assim, ter múltiplas histórias que refletem os múltiplos estados que ele pode assumir.

Escrevendo histórias

As histórias são escritas em arquivos com sufixo stories. O Storybook precisa desse sufixo para reconhecer uma história e carregá-la no dashboard. Existem algumas abordagens com relação a onde armazenar tais arquivos mas eu recomendo que eles fiquem ao lado do componente que representam para ter o mesmo ponto de vista do componente a eventuais recursos necessários.

O componente que será testado é o CardComponente que recebe, como input, um Card:

export type Card = {
id: number;
name: string;
header: string;
subheader: string;
imageUrl: string;
text: string;
};

Vou criar um arquivo para escrever a história do componente. Minha estrutura vai ser a seguinte:

Defini dados fake como mock para testes. Então, especifiquei os metadados do componente que será testado. E, por fim, criei a história. O arquivo card.stories.ts ficou assim:

import type { Meta, StoryObj } from '@storybook/angular';
import { Card } from '../../models/card';
import { CardComponent } from './card.component';

// Criação de mock para teste
const card: Card = {
id: 1,
name: 'Card 1',
header: 'Advanced Card',
subheader: 'Card Subheader',
imageUrl: 'https://primefaces.org/cdn/primeng/images/usercard.png',
text: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore sed consequuntur error repudiandae numquam deserunt quisquam repellat libero asperiores earum nam nobis, culpa ratione quam perferendis esse, cupiditate nequequas!',
};

// Configuração dos metadados do componente. Title define como/onde o componente aparecerá no dashboard do Storybook.
const meta: Meta<CardComponent> = {
title: 'UI/Card',
component: CardComponent,
};
// Precisamos exportar as configurações do componente para que o Storybook possa renderizá-lo.
export default meta;

// Criação da história principal do componente. O argumento args é utilizado para passar dados para o componente.
export const primary: StoryObj<CardComponent> = {
args: {
card: card,
},
};

E o Storybook, a essa altura, já renderiza nosso componente na estrutura que definimos em title nos metadados da história:

Como utilizamos args para passar os dados de teste, estes dados ficam disponíveis na aba Controls no dashboard do Storyboard para edição on demand, uma boa forma de prever como determinado conteúdo será apresentado.

Este é o caso de uso mais simples que podemos ter no Storybook. Mas a ferramenta tem suporte a actions e vários addons, assuntos para um próximo artigo.

Documentação

O Storybook pode apresentar a documentação dos nossos componentes, o que é especialmente útil para descrever inputs e outputs. A documentação é extraída via Compodoc que identifica o padrão de comentários do JSDoc para compor os textos. Tais comentários devem iniciar com barra + 2 asteriscos (em vez de 1) para que a ferramenta os identifique. Exemplo:

export class CardComponent {
/**
* The card to display.
*/
@Input({ required: true }) card!: Card;
}

Feito isso, especifique na história do componente que você quer exportar a documentação dele:

const meta: Meta<CardComponent> = {
title: 'UI/Card',
component: CardComponent,
tags: ['autodocs'], // Define que a documentação será gerada automaticamente.
};

E, então, a documentação aparecerá no Storybook:

Publicação

Por fim, é possível gerar um build estático da documentação para publicá-la em algum lugar e compartilhá-la com seu time. Para isso, execute o comando:

npm run build-storybook

O build estático será gerado, por padrão, na pasta storybook-static na raiz da aplicação.

Conclusão

Esta foi apenas uma introdução para trazer um primeiro contato com o Storybook e mostrar seus fundamentos e objetivos. A documentação oficial da ferramenta tem um tutorial excelente que se aprofunda em detalhes e pode ser acessado no link abaixo. A ideia principal deste artigo é apenas despertar o desejo de escrever componentes cada vez mais independentes, modulares e documentados, o que torna a manutenção mais fácil e menos propensa a bugs. É isso!

--

--