Introdução
Código React sem testes é um passivo. Você refatora um componente e algo quebra em três telas de distância. O Jest é o framework de testes que vem incluído no Create React App e se integra estreitamente com o React Testing Library. Ele cuida do executor de testes, asserções, mocks e relatórios de cobertura em um único pacote.
O que é o Jest?
Jest é um framework de testes open-source desenvolvido pelo Facebook para aplicações JavaScript. Ele exige quase nenhuma configuração para começar, o que é raro entre ferramentas de teste.
Principais Funcionalidades do Jest
- Zero Configuração: O Jest exige configuração mínima, permitindo que você comece a testar rapidamente.
- Snapshot Testing: Captura a saída renderizada de componentes React para detectar mudanças na UI.
- Testes Isolados: Cada teste roda em seu próprio sandbox para evitar interferência entre testes.
- Mocking Poderoso: Faça mock de funções, módulos e timers para controlar o comportamento do código durante os testes.
- Cobertura de Código: Gere relatórios detalhados para entender quanto do seu código está sendo testado.
Por Que Usar Jest para Testar Aplicações React?
O Jest se combina naturalmente com o React Testing Library, que permite consultar e interagir com seus componentes da forma como um usuário faria, em vez de depender de detalhes de implementação. Os testes rodam em paralelo, então mesmo suites grandes terminam rapidamente. A API de mocking é completa o suficiente para isolar qualquer dependência.
Configurando o Jest em uma Aplicação React
Pré-requisitos
Node.js e npm instalados, com familiaridade básica com React e JavaScript.
Criando um Novo App React
Crie uma nova aplicação React usando o Create React App:
npx create-react-app my-app
cd my-app
O Create React App vem com o Jest pré-configurado, então você pode começar a escrever testes imediatamente.
Aplicações React Existentes
Se você tem um projeto React existente sem Jest, instale-o:
npm install --save-dev jest babel-jest @babel/preset-env @babel/preset-react react-test-renderer
Em seguida, adicione o seguinte ao seu package.json:
"scripts": {
"test": "jest"
},
"jest": {
"setupFilesAfterEnv": ["<rootDir>/src/setupTests.js"]
}
Escrevendo Seu Primeiro Teste
Criando um Componente React
Crie um novo arquivo src/components/Greeting.js:
import React from 'react';
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}
export default Greeting;
Escrevendo um Teste para o Componente
Crie um arquivo de teste src/components/Greeting.test.js:
import React from 'react';
import { render, screen } from '@testing-library/react';
import Greeting from './Greeting';
test('renders greeting message', () => {
render(<Greeting name="World" />);
const greetingElement = screen.getByText(/Hello, World!/i);
expect(greetingElement).toBeInTheDocument();
});
Executando o Teste
npm test
O Jest encontra os arquivos de teste automaticamente e exibe os resultados no terminal.
Entendendo a Sintaxe dos Testes
O teste acima segue um padrão simples. Importe o componente, renderize-o em um DOM virtual via render(), consulte um elemento com screen.getByText() e verifique sua existência com expect().toBeInTheDocument(). A função test() envolve cada caso com uma string descritiva e um callback.
Testando Interações do Usuário
Exemplo: Evento de Clique em Botão
Suponha que temos um botão que incrementa um contador:
// Counter.js
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
export default Counter;
Escrevendo Testes para Interação do Usuário
// Counter.test.js
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import Counter from './Counter';
test('increments count on button click', () => {
render(<Counter />);
const buttonElement = screen.getByText(/Click me/i);
fireEvent.click(buttonElement);
expect(screen.getByText(/You clicked 1 times/i)).toBeInTheDocument();
});
fireEvent.click() simula um clique real e, em seguida, verificamos que o contador exibido foi atualizado. O teste falharia se o handler do onClick estivesse quebrado ou se a atualização de estado não disparasse uma re-renderização.
Snapshot Testing
O snapshot testing registra a saída renderizada de um componente e falha se ela mudar inesperadamente. É útil para detectar regressões visuais não intencionais.
Criando um Teste de Snapshot
// Greeting.test.js
import React from 'react';
import renderer from 'react-test-renderer';
import Greeting from './Greeting';
test('Greeting component matches snapshot', () => {
const tree = renderer.create(<Greeting name="World" />).toJSON();
expect(tree).toMatchSnapshot();
});
A primeira execução cria um arquivo de snapshot. Todas as execuções subsequentes comparam com ele. Quando você alterar intencionalmente a saída, atualize o snapshot com jest --updateSnapshot.
Mockando Funções e Módulos
Mockando um Módulo
Suponha que seu componente usa um módulo de API:
// api.js
export const fetchData = () => {
// fetch data from an API
};
Faça o mock nos seus testes para que chamadas de rede nunca sejam efetivamente realizadas:
jest.mock('./api', () => ({
fetchData: jest.fn(() => Promise.resolve({ data: 'mock data' })),
}));
Usando o Mock em um Teste
// DataComponent.test.js
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import DataComponent from './DataComponent';
import { fetchData } from './api';
test('displays fetched data', async () => {
fetchData.mockResolvedValueOnce({ data: 'mock data' });
render(<DataComponent />);
await waitFor(() => expect(screen.getByText(/mock data/i)).toBeInTheDocument());
});
Dicas para Testes Eficazes
- Teste seu próprio código, não bibliotecas de terceiros.
- Escreva testes determinísticos. Qualquer teste que produza resultados diferentes em execuções diferentes acabará minando a confiança na suite.
- Teste a saída que o usuário vê, não os detalhes de implementação internos. Se você refatorar os internos sem alterar o comportamento, nenhum teste deve quebrar.
- Use nomes descritivos para os testes. "increments count on button click" é mais útil do que "test 1".
Relatórios de Cobertura de Código
O Jest gera relatórios de cobertura que mostram quais linhas, branches e funções seus testes exercitam.
Habilitando a Cobertura de Código
npm test -- --coverage
Revise a saída para encontrar caminhos não testados, especialmente branches de erro que só são acionados em condições específicas.
Integração com Integração Contínua (CI)
Execute o Jest no seu pipeline de CI para que cada pull request inclua um gate de testes.
Exemplo com GitHub Actions
Crie um arquivo .github/workflows/main.yml:
name: Node.js CI
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x, 16.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js $
uses: actions/setup-node@v2
with:
node-version: $
- run: npm install
- run: npm test -- --coverage
- uses: actions/upload-artifact@v2
with:
name: coverage-report
path: coverage/
Conclusão
O Jest cobre tudo que um fluxo de trabalho de testes React precisa: um executor de testes paralelo e rápido, uma biblioteca de asserções, mocking, diff de snapshots e relatórios de cobertura. Comece com os testes de interação — eles capturam mais regressões por linha de código de teste escrito — e depois adicione snapshots para componentes de UI estáveis. Assim que os testes rodarem automaticamente no CI, você terá o loop de feedback permanente que torna a refatoração segura.