src/App.test.js no Create React App.Se você chegou aqui, não tenho dúvidas que você sabe o que são testes unitários e sua importância, sendo assim, vou te deixar com dois parágrafos muito bons sobre testes automatizados para aplicações em React e logo em seguida vamos pro código.
Quando escrevemos testes automatizados para aplicações em React, provavelmente uma grande parte dos nossos testes será sobre algum componente de UI e não apenas funções de regras de negócio. Por isso, precisamos de uma biblioteca que nos auxilie a interagir com o DOM, renderizando e encontrando os elementos que precisamos verificar nos testes.
A React Testing Library surgiu com uma abordagem centrada no usuário e com padrões para enfatizar boas práticas de semântica e acessibilidade. E hoje já faz parte do pacote padrão de uma aplicação feita com o Create React App. - Eduarda Scharnhorst em React: Automatizando os testes em aplicações front-end.
Imagine que você acabou de gerar uma aplicação com o CLI: Create React App.
Se você não sabe como fazer isso, visite a documentação clicando aqui.
A aplicação terá um arquivo src/App.js com a seguinte estrutura HTML(JSX):
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
E já terá um teste dentro do arquivo src/App.test.js. É importante explicar aqui que o nome do componente + .test dentro do mesmo diretório é uma convenção/boa prática pois a localização do teste fica mais intuitiva e não temos problemas de paths enormes em nossos imports.
Exemplificando, se você tem uma pasta chamada UI e dentro dela o componente Header.js seu teste será Header.test.js.
Outro uso comum seria ter uma pasta chamada Header e dentro dela o arquivo index.js, nesse caso seu arquivo de teste continuaria sendo Header.test.js, só mudaria o caminho do import;
Vamos dar uma olhada no código inicial dentro de src/App.test.js.
import { render, screen } from "@testing-library/react";
import App from "./App";
test("renders learn react link", () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});
import { render, screen } from '@testing-library/react';
Estamos importando os métodos render e screen.
render é o método que permitirá renderizarmos nosso componente.
Imagine que você tem uma página vazia, logo, qualquer comando de teste rodado vai dar erro, correto?
Então, quando o render é chamado, ele renderiza o componente dentro desta página e estamos prontos para iniciar o teste.
screen é um método que possui queries dentro dele.
Isso quer dizer que usaremos funções/métodos que estão dentro de screen para capturar as informações que queremos.
Já vamos chegar lá nas próximas linhas.
import App from './App';
Importando nosso componente. Sem novidades.
test('renders learn react link', () => {
test - que também pode ser encontrado como it -, é o método que nos permite escrever um texto descrevendo o que um teste bem sucedido deve fazer. No nosso exemplo, renderiza o link "learn react"
render(<App />);
Renderizando o componente App.
const linkElement = screen.getByText(/learn react/i);
Atribuindo à constante linkElement a query(método) getByText que deve encontrar o elemento que possui o texto /learn react/i.
O trecho /learn react/i é um padrão regex que desabilita o case-sensitive, ou seja, ignora a diferença entre letras maiúsculas e minúsculas. Puro Javascript.
Lembrando que para selecionar elementos você pode continuar utilizando o bom e velho querySelector, por exemplo: const foo = container.querySelector('[data-foo="bar"]').
expect(linkElement).toBeInTheDocument();
expect é um comando que faz asserções. O que é isso?
Uma asserção pega um valor booleano (true || false) e sempre espera que o retorno seja true. Se o evento retornar falso, o teste falha.
Para exemplificar melhor, a linha acima também poderia ser escrita assim:
expect(screen.getByText(/learn react/i)).toBeInTheDocument();
toBeInTheDocument() é um matcher. O que é isso?
É uma função cujo valor resultante deve ser true em relação ao que está testando do expect. Neste caso é estarNoDocumento. Existe inclusive uma lista de matchers e você pode encontrá-la aqui.
Vamos realizar algumas alterações para podermos abordar outros métodos e discutir:
import { render, screen } from "@testing-library/react";
import App from "./App";
describe("Componente App", () => {
it("renders learn react link", () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});
it("renders learn react link as anchor", () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toHaveAttribute("href");
});
});
describe é um método opcional que você pode utilizar para envelopar um conjunto de testes. Aqui estamos utilizando para delimitar os testes do nosso componente App e a resposta ao rodar os testes fica da seguinte maneira:

it, como falamos anteriormente está substituindo o test e pela minha experiência pessoal é o método mais utilizado no mercado.
it('renders learn react link as anchor', () => {
renders learn react link as anchor, novo teste, dessa vez, testaremos se o elemento é um link
expect(linkElement).toHaveAttribute('href');
toHaveAttribute('href'), conferindo se o elemento tem um href.
O teste vai passar com qualquer elemento que tenha um href, por exemplo, se for uma div o teste vai retornar com sucesso.
O correto seria:
it("renders learn react link as anchor", () => {
render(<App />);
// adicionando `.closest('a')`
const linkElement = screen.getByText(/learn react/i).closest("a");
expect(linkElement).toHaveAttribute("href");
});
Então esse último tópico foi gratuito só para chamar atenção em como você realiza seus testes e mostrar que 100% de cobertura não quer dizer uma aplicação sem bugs. :)