Aprenda / Frontend — Tailwind & Next.js

IntermediárioAula 17 de 2016 min0% da trilha

Testando componentes com Testing Library

Testar 'como o componente foi implementado' quebra a cada refatoração; testar o que o usuário vê e faz não.

Um erro comum ao testar componente é testar detalhe de implementação — acessar estado interno, checar se uma função específica foi chamada por dentro. Esse tipo de teste quebra toda vez que você refatora o componente, mesmo sem mudar nada do que o usuário vê. Testing Library evita isso de propósito: ela só te dá acesso ao que aparece na tela e ao que o usuário consegue fazer.

O que testar

Em vez de "a função handleSubmit foi chamada", teste comportamento visível: "quando eu clico em Salvar com os campos preenchidos, a mensagem de sucesso aparece na tela". Se você conseguir reescrever o componente inteiro por dentro e o teste continuar passando sem mudar uma linha, o teste está no nível certo.

render, screen e userEvent

Estrutura básica de um teste
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { LoginForm } from "./login-form";

test("mostra erro quando o e-mail é inválido", async () => {
  render(<LoginForm />);
  const user = userEvent.setup();

  await user.type(screen.getByLabelText("E-mail"), "nao-e-um-email");
  await user.click(screen.getByRole("button", { name: "Entrar" }));

  expect(await screen.findByText("E-mail inválido")).toBeInTheDocument();
});

render monta o componente num DOM virtual; screen é onde você busca elementos — getByRole, getByLabelText — sempre preferindo a forma como um usuário real encontraria aquele elemento (por texto do botão, por label do campo), não por um seletor de CSS interno. userEvent simula interação real: digitar, clicar, disparando os mesmos eventos que uma interação de verdade dispararia.

Um exemplo completo

contador-de-likes.test.tsx
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { ContadorDeLikes } from "./contador-de-likes";

test("incrementa o contador ao clicar", async () => {
  render(<ContadorDeLikes inicial={3} />);
  const user = userEvent.setup();

  expect(screen.getByText("❤ 3")).toBeInTheDocument();

  await user.click(screen.getByRole("button"));

  expect(screen.getByText("❤ 4")).toBeInTheDocument();
});

Repare que o teste não sabe (nem precisa saber) que existe um useState por trás — ele só sabe que, depois do clique, o texto na tela mudou de ❤ 3 pra ❤ 4.

Exercício

Escreva um teste pro componente ContadorDeLikes (da lição de Server vs. Client Components) que verifica que ele começa mostrando o valor de inicial, sem clicar em nada ainda.

Quiz rápido

Qual é a diferença central entre testar comportamento e testar detalhe de implementação?
Pra que serve userEvent.click(button) num teste com Testing Library?