Testes Unitários com Jest e RTS no ReactJS

Testes Unitários com Jest e RTS no ReactJS

Olá leitor, seja bem vindo a mais uma lição da jornada do desenvolvedor ReactJS do Portal da Micilini 😄

Hoje nos iremos aprender um dos assuntos mais negligênciados pelos desenvolvedores, e quem vem se tornando bastante vital nesse mundo do desenvolvimento, OS TESTES UNITÁRIOS.

Mas você sabe o que é um teste unitário?

O que é um teste unitário?

Um testes unitário, ou também conhecido como testes unitários, são na verdade uma prática de desenvolvimento de software, onde partes indivividuais de uma aplicação, são testadas de forma a garantir que essas mesmas partes retornem ou funcionem conforme o esperado.

Essas partes individuais são chamadas de unidades, que por sua vez, podem ser funções ou métodos de uma classe do Javascript.

O objetivo desses testes é primeiro: isolar cada lógica do código de modo a verificar se ela produz os resultados esperados, e segundo: facilita pra caramba a vida do desenvolvedor e também na identificação de erros que podem ocorrer durante a execução da sua aplicação.

Porque imagina você tendo que testar cada classe ou função presente no seu código de forma manual, a fim de verificar se esta tudo certo?

Era exatamente dessa forma que nós desenvolvedores faziamos quando não tinhamos esse conceito de testes unitários bem definidos.

Antigamente (e até hoje), você adiciona uma nova funcionalidade na aplicação e testa para ver se ela funciona corretamente (bem, pelo menos é isso que os stakeholders esperam... que você teste!).

Só que, na maioria das vezes, aquela famosa frase "Na minha máquina funciona", vem se tornando cada vez mais presente no cotidiano dos desenvolvedores.

Por vezes, um comando que funciona em ambiente local, acabando gerando dores de cabeça em um ambiente de produção.

E foi pensando nisso que os testes unitários também foram criados, pois antes de você subir uma aplicação, por de baixo dos panos, bibliotecas estariam testando cada aspecto da sua lógica, de forma garantir que tudo funcione corretamente.

E se algo der errado... pois bem... a sua aplicação não deveria subir para a produção!

É assim que funciona um teste unitário!

Basicamente, você faz uso de uma biblioteca a sua escolha, na qual se comunique diretamente com o arquivo pretendido (função ou classe), para posteriormente simular uma operação (fetch de dados, abertura de uma rota, clique em um botão...), de modo a verificar se está tudo dentro dos conformes 🐥

Testes Unitários e o ReactJS

No contexto de aplicações feitas com ReactJS, podemos aplicar testes unitários em diferentes partes da nossa aplicação.

  • Componentes em ReactJS: cada componente pode ser testado individualmente para garantir que renderize corretamente, e que interaja de acordo com diferentes estados e props.
  • Funções auxiliares: funções que realizam tarefas específicas, como formatação de dados ou cálculos, podem ser testadas para verificar se retornam os resultados esperados para diferentes entradas.
  • Hooks personalizados: se você criou hooks personalizados para gerenciar estado ou efeitos em seus componentes, é possível testá-los para assegurar que funcionem corretamente em diferentes cenários.
  • Integração com APIs: se sua aplicação se comunica com APIs externas, é possível simular chamadas de API e testar como os componentes reagem aos dados retornados.
  • Eventos e interações: testar como os componentes reagem a eventos do usuário, como cliques e teclas pressionadas.
  • Estado da aplicação: Verificar como os componentes respondem às mudanças de estado ao longo do ciclo de vida da aplicação.

Às ferramentas mais comuns de testes unitários em ReactJS incluem o Jest (Framework de Testes) e o React Testing Library (RTS) (biblioteca de testes de componentes do ReactJS).

Jest e React Testing Library são a mesma coisa?

Não, no caso do Jest e também do React Testing Library, eles não são a mesma coisa, mas são frequentemente utilizados em conjunto para testar aplicações feitas com ReactJS.

Jest: é um framework de testes de JavaScript mantido pelo Facebook. Ele é conhecido por ser fácil de configurar e usar, e vem com muitos recursos úteis embutidos, como suporte para testes de unidades, integração e snapshots.

o Jest é comumente utilizado para escrever e executar testes para código JavaScript, e isso incluí tambéms os códigos que criamos com ReactJS.

React Testing Library: é uma biblioteca de testes específica para ReactJS, projetada para testar componentes ReactJS da maneira como eles são usados em uma aplicação real. 

Sendo assim, enquanto o Jest fornece a estrutura de execução e assertiva para os testes JavaScript em geral, o React Testing Library é especialzado para testar componentes em ReactJS de uma maneira que enfatiza o comportamento e a usabilidade da aplicação.

Muitas vezes, você verá projetos usando Jest como o executor de testes e React Testing Library para testar componentes específicos do ReactJS dentro desses testes.

Agora, vamos aprender o funcionamento de ambas ferramentas em conjunto 🙂

Herdando seu projeto de testes

Antes de começarmos, dessa vez nós vamos fazer algo um pouco diferente, nós iremos herdar um pequeno projeto que já está pronto, e publicado lá no github da Micilini: Lição 25 - Versão 1.

Quando você for fazer o clone desse projeto para a sua máquina local, não se esqueça de mudar para a versão 1 do commit, pois ela ainda não contém os testes unitários.

Esse projeto representa uma pequena aplicação feita com a biblioteca do React Router DOM.

Após o clone, partiu aplicar testes unitários nesse projeto 😄

O que é o JEST?

O JEST é uma biblioteca de testes unitários que podemos utilizar nas nossas aplicações em ReactJS.

É importante ressaltar que você não precisa configurar ou instalar nenhuma biblioteca nova no seu projeto, pois pelo simples fato do nosso projeto já ter sido criado comando create-react-app, isso é mais do que o suficiente para o JEST vir instalado junto com ele 😊

Agora, caso você não tenha criado a sua aplicação usando o create-react-app, talvez seja necessário dar uma olhada na documentação da biblioteca antes de seguir em frente.

No caso do JEST, essa biblioteca te fornece um ambiente onde você pode realizar os seus testes unitários. E quando eu falo de ambiente, eu me refiro a uma pequena aplicação interna, na qual você pode chamar via prompt de comando para rodar esses testes.

Feito essa pequena introdução ao JEST, partiu colocar a mão na massa!

Usando o JEST no nosso projeto de testes (<Menu />)

Inicialmente nós vamos criar um teste unitário para o nosso componente Menu que existe dentro da pasta components:

Que representa aquele nosso Menu principal:

Tudo o que queremos fazer nesse teste unitário é: Verificar se os componentes da tela estão sendo mostrados com sucesso.

Então vamos lá, dentro da pasta Menu, nós iremos criar um novo arquivo chamado de menu.spec.js:

Quando criamos arquivos com a extenção:

  • .spec.js (indica um arquivo Javascript)
  • .spec.ts (indica um arquivo Typescript)
  • .test.js (indica um arquivo Javascript)
  • .test.ts (indica um arquivo Typescript)

A biblioteca do JEST já reconhece esses arquivos (não importanto o quão profundo e espalhados eles estejam dentro da sua aplicação), abrindo cada um deles de forma automática, a fim de executar os testes.

Pois bem, dentro do menu.spec.js, vamos fazer uma verificação para ver o texto "Minha Aplicação" está presente na tela ou não:

Menu > menu.spec.js:

import '@testing-library/jest-dom';//Estamos importando o pacote @testing-library/jest-dom.
import { render, screen } from "@testing-library/react";//Estamos importando a função render do pacote @testing-library/react.
import Menu from "./index";//Estamos importando o componente Menu.
import { BrowserRouter } from "react-router-dom";
 
describe("Menu", () => {//Estamos descrevendo um caso de teste chamado de Menu, que vai englobar todos os testes relacionados ao componente Menu.

 //Para iniciar os testes, podemos usar tanto o it() quanto o test():

 it("Deve renderizar sem erros", () => {//Estamos descrevendo um teste que verifica se o componente Menu renderiza sem erros.
 render(
 <BrowserRouter>
 <Menu />
 </BrowserRouter>
 );//Estamos renderizando o componente Menu dentro do ambiente do JEST.

 expect(screen.getByText("Minha Aplicação")).toBeInTheDocument();//Esperamos que o texto "Minha Aplicação" esteja na tela.
 });
 
})//Estamos descrevendo um caso de teste chamado de Menu, que vai englobar todos os testes relacionados ao componente Menu.

Apesar do código já estar bem explicado, vamos detalhá-lo ainda mais:

import '@testing-library/jest-dom';
// Estamos importando o pacote @testing-library/jest-dom.

Aqui, estamos importando o pacote @testing-library/jest-dom. Este pacote fornece utilidades de teste que são úteis ao usar Jest para testar aplicações React. Ele inclui funções como toBeInTheDocument, que é usada para verificar se um elemento está presente no DOM.

import { render, screen } from "@testing-library/react";
// Estamos importando a função render do pacote @testing-library/react.

Estamos importando as funções render e screen do pacote @testing-library/react. render é usada para renderizar componentes ReactJS para o DOM simulado pelo Jest durante os testes. screen é uma interface que fornece métodos para consultar elementos renderizados, como getByText, getByRole, entre outros.

import Menu from "./index";
// Estamos importando o componente Menu.

stamos importando o componente Menu que está localizado no arquivo index.js ou index.jsx no mesmo diretório que este arquivo de teste. Ele se faz essêncial pois iremos utilizá-lo para realizar nossos testes.

import { BrowserRouter } from "react-router-dom";
// Estamos importando BrowserRouter do pacote react-router-dom.

Estamos importando o componente BrowserRouter do pacote react-router-dom, que é usado para fornecer a funcionalidade de roteamento para a aplicação ReactJS. Ele se faz essêncial, pois como estamos utilizando o roteamento, é importante que o componente <Menu /> seja chamada em conjunto com o <BrowserRouter /> pois se não, não funciona.

describe("Menu", () => {
 // Estamos descrevendo um caso de teste chamado de Menu, que vai englobar todos os testes relacionados ao componente Menu.

 it("Deve renderizar sem erros", () => {
 // Estamos descrevendo um teste que verifica se o componente Menu renderiza sem erros.
 render(
 <BrowserRouter>
 <Menu />
 </BrowserRouter>
 );
 // Estamos renderizando o componente Menu dentro do ambiente do JEST.

 expect(screen.getByText("Minha Aplicação")).toBeInTheDocument();
 // Esperamos que o texto "Minha Aplicação" esteja na tela.
 });
});

describe("Menu", () => { ... }): define um grupo de testes utilizando o Jest. Todos os testes dentro deste bloco estão relacionados ao componente Menu.

it("Deve renderizar sem erros", () => { ... }): define um teste específico dentro do grupo describe. Este teste verifica se o componente Menu renderiza corretamente sem erros.

render(<BrowserRouter><Menu /></BrowserRouter>): renderiza o componente Menu dentro de um componente BrowserRouter, simulando o ambiente ReactJS onde o roteamento está ativo.

expect(screen.getByText("Minha Aplicação")).toBeInTheDocument();: utiliza a função expect para verificar se o texto "Minha Aplicação" está presente na tela renderizada pelo componente Menu. A função getByText é uma das funções fornecidas pelo screen para consultar elementos renderizados.

Simples, não? Para executar esse teste basta abrir o terminal dentro da pasta raíz da sua aplicação e executar o seguinte comando:

npm run test

Após isso, automaticamente o JEST iniciará os testes na sua aplicação, e se tudo estiver OK, você receberá a mensagem 1 passed, 1 total:

Para simular um erro, você pode modificar o texto do getByText() da seguinte forma:

expect(screen.getByText("Minha Aplicação 2")).toBeInTheDocument();

Como não existe nenhum elemento chamado "Minha Aplicação 2", quando você executar seus testes (npm run test), o JEST não passará no teste e mostrará a seguinte mensagem de erro:

Realizando mais testes utilizando o JEST (<Menu />)

Agora, nós vamos adicionar mais um pouco de complexidade no nosso arquivo menu.spec.js:

Menu > menu.spec.js:

import '@testing-library/jest-dom';//Estamos importando o pacote @testing-library/jest-dom.
import { render, screen } from "@testing-library/react";//Estamos importando a função render do pacote @testing-library/react.
import Menu from "./index";//Estamos importando o componente Menu.
import { BrowserRouter } from "react-router-dom";
 
describe("Menu", () => {//Estamos descrevendo um caso de teste chamado de Menu, que vai englobar todos os testes relacionados ao componente Menu.

 //Para iniciar os testes, podemos usar tanto o it() quanto o test():

 it("Deve renderizar sem erros", () => {//Estamos descrevendo um teste que verifica se o componente Menu renderiza sem erros.
 render(
 <BrowserRouter>
 <Menu />
 </BrowserRouter>
 );//Estamos renderizando o componente Menu dentro do ambiente do JEST.

 expect(screen.getByText("Minha Aplicação")).toBeInTheDocument();//Esperamos que o texto "Minha Aplicação" esteja na tela.
 expect(screen.getByText("Home")).toBeInTheDocument();//Esperamos que o texto "HOME" esteja na tela.
 expect(screen.getByText("Contato")).toBeInTheDocument();//Esperamos que o texto "CONTATO" esteja na tela.
 expect(screen.getByText("Serviços")).toBeInTheDocument();//Esperamos que o texto "SERVICOS" esteja na tela.
 expect(screen.getByText("Clientes")).toBeInTheDocument();//Esperamos que o texto "CLIENTES" esteja na tela.
 });

 test("Deve conter 4 links de navegação", () => {//Estamos descrevendo um teste que verifica se o componente Menu contém 4 links de navegação.
 render(
 <BrowserRouter>
 <Menu />
 </BrowserRouter>
 );//Estamos renderizando o componente Menu dentro do ambiente do JEST.
 const links = screen.getAllByRole("link");//Estamos buscando todos os elementos que são links.
 expect(links).toHaveLength(4);//Esperamos que a quantidade de links seja igual a 4.
 });

 it("Deve conter um link para a Home", () => {//Estamos descrevendo um teste que verifica se o componente Menu contém um link para a Home.
 render(
 <BrowserRouter>
 <Menu />
 </BrowserRouter>
 );//Estamos renderizando o componente Menu dentro do ambiente do JEST.
 const linkHome = screen.getByRole("link", { name: /home/i });//Estamos buscando um link que contenha a palavra Home.
 expect(linkHome).toBeInTheDocument();//Esperamos que o linkHome esteja na tela.
 });

 it("Deve conter um link para a Contato", () => {//Estamos descrevendo um teste que verifica se o componente Menu contém um link para o Contato.
 render(
 <BrowserRouter>
 <Menu />
 </BrowserRouter>
 );//Estamos renderizando o componente Menu dentro do ambiente do JEST.
 const linkContato = screen.getByRole("link", { name: /contato/i });//Estamos buscando um link que contenha a palavra Contato.
 expect(linkContato).toBeInTheDocument();//Esperamos que o linkContato esteja na tela.
 });

 it("Deve conter um link para a Serviços", () => {//Estamos descrevendo um teste que verifica se o componente Menu contém um link para Serviços.
 render(
 <BrowserRouter>
 <Menu />
 </BrowserRouter>
 );//Estamos renderizando o componente Menu dentro do ambiente do JEST.
 const linkServicos = screen.getByRole("link", { name: /serviços/i });//Estamos buscando um link que contenha a palavra Serviços.
 expect(linkServicos).toBeInTheDocument();//Esperamos que o linkServicos esteja na tela.
 });

 it("Deve conter um link para a Clientes", () => {//Estamos descrevendo um teste que verifica se o componente Menu contém um link para Clientes.
 render(
 <BrowserRouter>
 <Menu />
 </BrowserRouter>
 );//Estamos renderizando o componente Menu dentro do ambiente do JEST.
 const linkClientes = screen.getByRole("link", { name: /clientes/i });//Estamos buscando um link que contenha a palavra Clientes.
 expect(linkClientes).toBeInTheDocument();//Esperamos que o linkClientes esteja na tela.
 });
 
})//Estamos descrevendo um caso de teste chamado de Menu, que vai englobar todos os testes relacionados ao componente Menu.

No arquivo acima estamos realizando um total de 6 testes, como consta na imagem abaixo:

Observação: Apesar dos links dos menus estarem com letras maiúsculas, no JSX, a comparação de texto é sensível a maiúsculas e minúsculas. Portanto, "Home" e "HOME" são tratados como textos diferentes. Onde o JEST considera o resultado que está presente no componente, e não sua renderização final.

Observação 2: Se você estiver usando a biblioteca do TanStack Query, não se esqueça de chamá-la dentro do método render() assim como fez com o <BrowserRouter>.

Realizando testes nas rotas da nossa aplicação

Agora, nós iremos testar se às nossas rotas estão abrindo os componentes corretamente.

Para isso, nós podemos verificar se determinada rota abre um componente que possui algum elemento que contenha um texto.

Routes > routes.spec.js:

import React from 'react';
import '@testing-library/jest-dom';//Estamos importando o pacote @testing-library/jest-dom.
import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom'; // MemoryRouter para testes de rota
import RouterApp from './routes';

describe("RouterApp", () => {//Estamos descrevendo um caso de teste chamado de Menu, que vai englobar todos os testes relacionados ao componente Menu.

test('Renderiza Home ao acessar a rota /', () => {
 render(
 <MemoryRouter initialEntries={['/']}>
 <RouterApp />
 </MemoryRouter>
 );

 expect(screen.getByText(/Minha Aplicação/i)).toBeInTheDocument(); // Verifica se o título está presente
});

test('Renderiza Serviços ao acessar a rota /servicos', () => {
 render(
 <MemoryRouter initialEntries={['/servicos']}>
 <RouterApp />
 </MemoryRouter>
 );

 expect(screen.getByText(/Serviços/i)).toBeInTheDocument(); // Verifica se o título está presente
});

test('Renderiza Contato ao acessar a rota /contato', () => {
 render(
 <MemoryRouter initialEntries={['/contato']}>
 <RouterApp />
 </MemoryRouter>
 );

 expect(screen.getByText(/Entre em Contato/i)).toBeInTheDocument(); // Verifica se o título está presente
});

test('Renderiza Clientes ao acessar a rota /clientes', () => {
 render(
 <MemoryRouter initialEntries={['/clientes']}>
 <RouterApp />
 </MemoryRouter>
 );

 expect(screen.getByText(/Conheça nossos Clientes/i)).toBeInTheDocument(); // Verifica se o título está presente
});

test('Renderiza página de erro 404 ao acessar uma rota inexistente', () => {
 render(
 <MemoryRouter initialEntries={['/rota-inexistente']}>
 <RouterApp />
 </MemoryRouter>
 );

 expect(screen.getByText(/Error 404/i)).toBeInTheDocument(); // Verifica se o texto de erro 404 está presente
});

});

Observação: Como o componente <Cliente /> faz o uso da biblioteca Axios (por meio do componente <Nomes />), a sua aplicação pode dar erro, pois o JEST não suporta a importação usando import, somente o require do commomJS.

Para habilitar o uso do import, você precisa adicionar o comando abaixo dentro do seu package.json:

"jest": {
 "moduleNameMapper": {
 "^axios$": "axios/dist/node/axios.cjs"
 }
}

No final o seu arquivo ficaria similar a este:

{
 "name": "testes-unitarios",
 "version": "0.1.0",
 "private": true,
 "dependencies": {
 "@testing-library/jest-dom": "^5.17.0",
 "@testing-library/react": "^13.4.0",
 "@testing-library/user-event": "^13.5.0",
 "axios": "^1.7.2",
 "react": "^18.3.1",
 "react-dom": "^18.3.1",
 "react-router-dom": "^6.24.1",
 "react-scripts": "5.0.1",
 "web-vitals": "^2.1.4"
 },
 "scripts": {
 "start": "react-scripts start",
 "build": "react-scripts build",
 "test": "react-scripts test",
 "eject": "react-scripts eject"
 },
 "eslintConfig": {
 "extends": [
 "react-app",
 "react-app/jest"
 ]
 },
 "browserslist": {
 "production": [
 ">0.2%",
 "not dead",
 "not op_mini all"
 ],
 "development": [
 "last 1 chrome version",
 "last 1 firefox version",
 "last 1 safari version"
 ]
 },
 "jest": {
 "moduleNameMapper": {
 "^axios$": "axios/dist/node/axios.cjs"
 }
 }
}

Ao rodar todos os seus testes usando npm run test, ou quem sabe executando um teste existente em um arquivo específico:

npm run test -- routes.spec.js

Você verá que nossas rotas estarão funcionando perfeitamente 🤩

Realizando testes no componente <Nome />

O componente <Nome /> é responsável por fazer chamadas a uma API externa capaz de retornar nomes de forma aleatória.

Para testarmos o funcionamento deste componente é bem simples, basta apenas que você crie um novo arquivo chamado nomes.spec.js.

Components > Nomes > nomes.spec.js:

import '@testing-library/jest-dom';//Estamos importando o pacote @testing-library/jest-dom.
import React from 'react';
import { render, screen } from '@testing-library/react';
import Nomes from './index';
import axios from 'axios';

import { BrowserRouter } from "react-router-dom";
import Clientes from '../../pages/Clientes';

jest.mock('axios');

test('Renderiza nomes após a requisição', async () => {// Simula a resposta da API que será retornada pelo axios.get
 const nomesMock = [
 { id: 1, name: 'Nome 1' },
 { id: 2, name: 'Nome 2' },
 { id: 3, name: 'Nome 3' }
 ];

 axios.get.mockResolvedValue({ data: nomesMock });

 render(
 <BrowserRouter>
 <Clientes>
 <Nomes />
 </Clientes>
 </BrowserRouter>
 );//Tambme funcionaria informando somente o componente <Nome /> sem o <Clientes> e <BrowserRouter> como wrapper

 // Aguarda a renderização dos elementos
 const nomeElement1 = await screen.findByText('Nome 1');
 const nomeElement2 = screen.getByText('Nome 2');
 const nomeElement3 = screen.getByText('Nome 3');

 expect(nomeElement1).toBeInTheDocument();
 expect(nomeElement2).toBeInTheDocument();
 expect(nomeElement3).toBeInTheDocument();
});

jest.mock('axios'): configura o Jest para substituir o axios pelo seu próprio mock durante os testes. Isso evita que as requisições reais sejam feitas durante os testes, é como se estivessemos simulando um retorno.

axios.get.mockResolvedValue({ data: nomesMock }): define um valor de retorno para a função axios.get, simulando a resposta da API. Aqui, nomesMock representa os dados que você espera receber da API.

render(<Nomes />): renderiza o componente Nomes dentro do ambiente de teste.

screen.findByText e screen.getByText: métodos fornecidos pelo @testing-library/react para buscar elementos na tela renderizada. findByText espera até que o elemento seja encontrado na tela (útil para componentes que renderizam de forma assíncrona).

expect(...).toBeInTheDocument(): verifica se os elementos correspondentes aos nomes estão presentes na tela após a requisição ser concluída.

Lembrando que para rodar este teste em específico, ou você pode rodar todos de uma vez (npm run test), ou você pode rodar também o teste relacionado com o componente em específico informando o nome do arquivo da seguinte forma:

npm run test -- nomes.spec.js

Note que os testes foram executados com sucesso:

Realizando testes em um componente que envia dados para um servidor (método POST)

Agora, vamos supor que nós temos um componente responsável por enviar um formulário para um determinado endpoint de uma API.

Para isso, vamos simular a criação de um novo componente chamado de Formulario.

Formulario > index.jsx:

// src/components/Formulario.js

import React, { useState } from 'react';

const Formulario = () => {
 const [texto, setTexto] = useState('');

 const handleSubmit = async (event) => {
 event.preventDefault();

 try {
 const response = await fetch('https://seu-endpoint-aqui', {
 method: 'POST',
 headers: {
 'Content-Type': 'application/json'
 },
 body: JSON.stringify({ texto })
 });

 if (!response.ok) {
 throw new Error('Erro ao enviar o formulário');
 }

 // Se o envio for bem-sucedido, você pode tratar a resposta aqui

 console.log('Formulário enviado com sucesso!');
 } catch (error) {
 console.error('Erro ao enviar o formulário:', error);
 }
 };

 const handleChange = (event) => {
 setTexto(event.target.value);
 };

 return (
 <form onSubmit={handleSubmit}>
 <label>
 Texto:
 <input
 type="text"
 value={texto}
 onChange={handleChange}
 required
 />
 </label>
 <button type="submit">Enviar</button>
 </form>
 );
};

export default Formulario;

Supondo que nós queiramos testar essa funcionalidade de envio, nós podemos fazer isso da seguinte forma.

Formulario > formulario.spec.js:

// src/components/Formulario.test.js

import React from 'react';
import { render, fireEvent, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect'; // Para usar os matchers do jest-dom
import Formulario from './index';

describe('Componente Formulario', () => {
 it('deve renderizar o componente corretamente', () => {
 const { getByLabelText, getByText } = render(<Formulario />);

 // Verifica se o componente de texto e o botão são renderizados
 expect(getByLabelText('Texto:')).toBeInTheDocument();
 expect(getByText('Enviar')).toBeInTheDocument();
 });

 it('deve enviar o formulário corretamente', async () => {
 // Mock da função fetch para simular o envio do formulário
 const mockFetch = jest.fn(() => Promise.resolve({ ok: true }));
 global.fetch = mockFetch;

 const { getByLabelText, getByText } = render(<Formulario />);

 // Simula a entrada de texto no input
 const input = getByLabelText('Texto:');
 fireEvent.change(input, { target: { value: 'Exemplo de texto' } });

 // Simula o envio do formulário
 fireEvent.click(getByText('Enviar'));

 // Verifica se a função fetch foi chamada corretamente
 expect(mockFetch).toHaveBeenCalledTimes(1);
 expect(mockFetch).toHaveBeenCalledWith('https://seu-endpoint-aqui', {
 method: 'POST',
 headers: {
 'Content-Type': 'application/json'
 },
 body: JSON.stringify({ texto: 'Exemplo de texto' })
 });

 // Aguarda até que o envio do formulário seja concluído
 await waitFor(() => {
 expect(input.value).toBe(''); // Verifica se o input foi limpo após o envio
 });
 });
});

No comando acima, estamos mockando a função fetch usando jest.fn() para simular o envio do formulário.

Além disso, é utilizado fireEvent.change para simular a digitação de texto no campo de texto. Em seguida, fireEvent.click é usado para simular o clique no botão "Enviar".

Após isso, é verificado se a função fetch foi chamada uma vez e com os parâmetros corretos (URL do endpoint, método POST, cabeçalhos e corpo da requisição JSON).

Por fim, usamos o comando waitFor para aguardar até que o envio do formulário seja concluído, e então verifica se o campo de texto foi limpo corretamente (input.value deve ser vazio).

Os arquivos de testes sobem junto com npm run build?

Não, pois normalmente quando fazemos deploy da nossa aplicação, os arquivos marcados como:

  • .spec.js (indica um arquivo Javascript)
  • .spec.ts (indica um arquivo Typescript)
  • .test.js (indica um arquivo Javascript)
  • .test.ts (indica um arquivo Typescript)

Geralmente não são incluídos no build de produção 😄

Arquivos da lição

Os arquivos dessa lição podem ser encontrados neste repositório do GitHub.

Conclusão

Nesta lição você aprendeu a criar testes unitários na sua aplicação usando o JEST e o React Testing Library.

Lembrando que o conhecimento sobre JEST não termina aqui, portanto não deixe de consultar a documentação quando for necessário.

Até a próxima lição 🙃