Recentemente escrevi diversos tutoriais a respeito de testes aqui no blog, com técnicas como unit testing, integration testing, mocking (geral, BD, AWS e de URL), etc; mas sempre abordando sob a ótica de testar bibliotecas e web APIs. Aliás, esse já é um disclaimer: você deve ter conhecimento de testes antes de avançar neste tutorial. Os links que citei acima são um bom começo.
Mas e a interface, o front-end, estaria sempre relegado a testes manuais?
De forma alguma.
Especialmente em aplicações onde front-end e back-end são construídos de forma completamente separadas, como no caso de React, React Native e outros, o trabalho dos profissionais de front deve sim ser testado, e da mesma forma que temos vários tipos de testes diferentes no back-end, no front também é possível ter.
Em tutorial recente, eu introduzi o funcionamento do Storybook, uma poderosa ferramenta para auxiliar na construção de interfaces. Não apenas isso, o Storybook te permite fazer testes manuais dos componentes isoladamente, o que ajuda e muito nos testes manuais pois uma vez que tenham uma boa biblioteca de stories para nossos componentes, fica muito mais fácil de correr o olho por eles e achar inconsistências depois de uma modificação em um ou mais componentes.
Neste tutorial, nós vamos além dos testes manuais, mostrando como juntar o Storybook com o Jest, uma biblioteca de testes muito popular para Node.js. Conhecimento básico em ambas ferramentas é necessário antes de avançar.
Além disso, usarei os fontes do projeto anterior para escrever nossos testes. Embora não seja obrigatório, é recomendado que baixe o projeto para acompanhar melhor. Tem um formulário no final desta página para você baixar.
#1 – Configurando o Projeto
Parto do pressuposto aqui que você tem um projeto de front React já criado, podendo ser inclusive com create-react-app se quiser. Apenas certifique-se de ter um ou mais componentes nele. Eu vou usar o projeto do tutorial anterior, onde tenho um componente ListItem.js como abaixo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
import React from 'react'; import styled from 'styled-components'; const ItemContainer = styled.div` border-radius: 4px; background-color: #fff; height: 120px; width: 262px; color: #29303b; margin-bottom: 10px; margin-right: 10px; padding: 10px; `; const Thumbnail = styled.img` width: auto; height: 100%; border: 0; vertical-align: middle; float: left; margin-right: 10px; `; const TitlePane = styled.div` font-weight: 700; margin-bottom: 5px; `; const PricePane = styled.div` margin-bottom: 5px; `; const ItemLink = styled.a` text-decoration: none; `; function ListItem(props) { console.log(props); return ( <ItemLink href={props.url} title="Clique para comprar"> <ItemContainer> <Thumbnail src={props.image} /> <TitlePane>{props.title}</TitlePane> <PricePane>R$ {props.price}</PricePane> </ItemContainer> </ItemLink> ); } export default ListItem; |
Repare que uso a dependência do Styled Components, além de outras que você não vê nestes fontes mas que estão presentes no projeto original, como o React Bootstrap e o Bootstrap em si.
Neste mesmo projeto, espero que você já tenha instalado o Storybook. Caso ainda não tenha feito, acompanhe a documentação oficial ou meu tutorial anterior. Certifique-se de ter ao menos uma história nele, para um de seus componentes, a fim de termos o quê testar.
No meu caso as histórias que possuo para o componente ListItem.js citado antes estão declaradas em um arquivo ListItem.stories.js como abaixo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
import 'bootstrap/dist/css/bootstrap.min.css'; import React from 'react'; import ListItem from '../components/ListItem'; export default { title: 'ListItem', component: ListItem, }; const Template = (args) => <ListItem {...args} />; export const NodeMongoBook = Template.bind({}); NodeMongoBook.args = { title: 'Programação Web com Node.js', image: 'https://m.media-amazon.com/images/I/4110e7iseFL.jpg', price: 14.99, url: "https://www.luiztools.com.br/livro-nodejs-amazon" }; export const NodeMySQLBook = Template.bind({}); NodeMySQLBook.args = { title: 'Programação Web com Node.js (MySQL)', image: 'https://m.media-amazon.com/images/I/71+5-qGBkcL._AC_UL640_FMwebp_QL65_.jpg', price: 14.99, url: "https://www.luiztools.com.br/livro-node-mysql-amazon" }; export const MicroservicesBook = Template.bind({}); MicroservicesBook.args = { title: 'Node.js e Microservices', image: 'https://m.media-amazon.com/images/I/41CUCsnLPML.jpg', price: 14.99, url: "https://www.luiztools.com.br/livro-node-ii-amazon" }; |
Sendo que a aparência deste componente, quando visualizado no Storybook é essa.
Não há necessidade de instalar e configurar o Jest se você criou o projeto com create-react-app, pois ele já vem com a React Testing Library. Se não conhece essa bblioteca, basta você saber que rodando o comando ‘npm test’, tudo vai funcionar como funcionaria com o Jest. Caso não tenha usado o create-react-app, instale essa lib manualmente seguindo as instruções do link acima.
E para finalizar esta primeira parte de setup, crie uma pasta tests dentro de src para guardamos nossos scripts de teste.
#2 – Criando Unit Tests
O princípio básico de Unit Tests de componentes funcionais é que, dada uma entrada única, a saída esperada deve ser sempre a mesma. Ou seja, se eu passar argumentos a, b e c para um componente, ele deve SEMPRE renderizar da mesma forma. Mas se eu passar x, y e z, ele deve renderizar de outro jeito. Entende?
Vamos começar criando um arquivo ListItem.test.js para escrever os unit tests do nosso componente ListItem.js.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
//ListItem.test.js import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom/extend-expect'; import { NodeMongoBook } from '../stories/ListItem.stories'; it('Renders the Node+Mongo book', () => { render(<NodeMongoBook {...NodeMongoBook.args} />); expect(screen.getByText(/\$/)).toHaveTextContent(NodeMongoBook.args.price); }); |
Repare que além dos imports necessários para testes de front, eu importei as histórias do meu componente, que por sua vez importam o componente em si.
Com as histórias eu consigo fazer a renderização do mesmo usando a função render e fazer as asserções usando uma série de funções específicas para interface. No exemplo, eu procurei o elemento da tela com o texto $ (usei uma Regular Expression) e verifiquei se ele possuía dentro o preço que foi passado por parâmetro ao componente.
As informações completas das funções existentes para testes de interface na Testing Library pode ser encontrada neste link.
#3 – Criando Visual Tests
Unit Tests são legais, mas eles podem se tornar um problemão conforme o número de componentes e estados aumenta e você faça modificações no layout deles, o que pode quebrar uma série de unit tests sem de fato ter quebrado o componente ou uma regra de negócio, entende?
Sendo assim, o Storybook nos permite outra categoria de testes que são os Visual Tests ou Testes Visuais. Ao contrário do que o nome possa sugerir, não são feitos por humanos, olhando os componentes também são automatizados assim como os unit tests e seu funcionamento consiste em tirar screenshots das histórias e depois confrontar elas com o resultado da bateria de testes.
Ou seja, Visual Tests são comparações automáticas de imagens de “antes” e “depois” dos testes, como mostrado no gif abaixo.
Mas indo ao que interessa, como podemos escrever Visual Tests para nosso componente ListItem?
Para fazer isso, vamos usar um serviço dos criadores do Storybook, o Chromatic. Este é um serviço em nuvem que vai testar e registrar a aparência dos seus componentes na nuvem. Para isso, acesse o site oficial e use a sua conta do GitHub para se logar.
Uma vez autorizado, escolha um projeto do GitHub e o Chromatic vai te dizer para instalar a dependência dele no seu projeto, com o comando abaixo.
1 2 3 |
yarn add --dev chromatic |
E depois de instalado, é hora de buildar o seu Storybook. Recomendo que faça isso antes de publicar no Chromatic pois tive problemas fazendo com que ele próprio fizesse o build pra mim. Rodar o build do Storybook é muito simples, basta usar o comando abaixo.
1 2 3 |
yarn run storybook-build |
Quando terminar, você terá um caminho para a pasta do seu build, guarde essa informação consigo pois agora você deve usá-la para que o Chromatic publique o seu Storybook na nuvem com o comando abaixo, mas note que o project-token deve ser o seu, omiti o meu no trecho de código por razões óbvias.
1 2 3 |
npx chromatic --project-token=xxxx -d /seu/caminho/do-build/storybook-static |
Vai demorar um bocado para ele publicar seu Storybook, pois depois da publicação ele faz os snapshots ainda. Com tudo finalizado com sucesso, ele perguntará se você deseja adicionar um script chromatic no seu package.json, o que é muito útil para publicações posteriores.
Você só conseguirá avançar na tela de setup do Chromatic depois da publicação encerrar. Quando terminar, você poderá avançar e conseguirá ver um resumo da publicação, como esse.
Agora, sempre que fizer uma mudança nos seus componentes e quiser ver se os screenshots do seu Storybook ainda estão batendo com os snapshots do Chromatic, pode rodá-lo novamente.
Faça uma alteração qualquer, como por exemplo uma mudança de padding no ListItem.js
1 2 3 4 5 6 |
const ItemLink = styled.a` text-decoration: none; padding: 5px; `; |
E antes de rodar novamente a publicação, vamos editar o script chromatic no package.json para que ele faça o build antes da publicação e aponte para o diretório corretamente com -d.
1 2 3 |
"chromatic": "yarn run build-storybook && npx chromatic -d /Users/luizfduartejr/NodeProjects/react-list-search/storybook-static --project-token 5791b80ecf50" |
Agora rode o script chromatic para que seja validado se as alterações recentes mudaram a interface ou não.
1 2 3 |
yarn run chromatic |
O resultado é bem interessante, pois o Chromatic vai detectar que tiveram alterações, mesmo sendo apenas um padding pequeno.
Se você acessar aquele link informado ao final do build, você conseguirá ver exatamente o que rolou de diferente, como na imagem abaixo indicando espaço extra que foi adicionado.
Para cada alteração, você pode aprovar ou não a mudança (Review Changes), por dentro da própria plataforma web da Chromatic. É importante ressaltar que os primeiros 5.000 testes de snapshot por mês são gratuitos, o que deve ser o suficiente para projetos não muito grandes e depois disso a plataforma cobra e cobra bem, então leve isso em consideração.
Curtiu o tutorial? Conheça a minha formação completa em Web FullStack JS clicando no banner abaixo!
Olá, tudo bem?
O que você achou deste conteúdo? Conte nos comentários.