Testing — RTL e Jest
Testar comportamento, não implementação. getByRole, userEvent, e o que não testar.
Definição
React Testing Library testa o que o usuário vê e faz, não internals do componente. Queries por role/label/text (acessíveis) em vez de class/id (frágeis). userEvent simula interação real (tipo, clica, tabula). Jest para asserções e mocks. Regra de ouro: se você refatorar sem mudar comportamento, os testes não devem quebrar.
Problema → Solução
Problema
Testes que testam implementação: `expect(wrapper.state('count')).toBe(1)`. Quebram a cada refatoração mesmo sem bug. Ou testes que só testam se o componente renderiza sem erro — não têm valor.Solução
Testar pelo ponto de vista do usuário: renderizar, interagir como o usuário faria, assertar o que o usuário vê. Queries de prioridade: getByRole > getByLabelText > getByPlaceholderText > getByText > getByTestId.Dica de entrevista
Tip
Se você só consegue testar usando getByTestId, é um sinal que o componente não tem semântica acessível. data-testid é o último recurso — geralmente indica falta de role ou label.Código
// ✅ Testar comportamento, não implementação
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { LoginForm } from './LoginForm'
test('mostra erro ao submeter vazio', async () => {
const user = userEvent.setup()
render(<LoginForm onLogin={jest.fn()} />)
await user.click(screen.getByRole('button', { name: /entrar/i }))
expect(screen.getByRole('alert')).toHaveTextContent('Preencha todos os campos')
})
test('chama onLogin com credenciais corretas', async () => {
const user = userEvent.setup()
const onLogin = jest.fn()
render(<LoginForm onLogin={onLogin} />)
await user.type(screen.getByLabelText(/email/i), 'user@test.com')
await user.type(screen.getByLabelText(/senha/i), 'secret')
await user.click(screen.getByRole('button', { name: /entrar/i }))
expect(onLogin).toHaveBeenCalledWith({
email: 'user@test.com', password: 'secret'
})
})
// ❌ Evitar: testa implementação
test('estado muda ao digitar', () => {
const { rerender } = render(<LoginForm />)
// Não acesse state interno — teste o que o usuário vê
})Perguntas de entrevista
Q.getByRole vs getByTestId — qual usar?▾
A.getByRole é sempre preferível: testa acessibilidade junto com funcionalidade, é mais resiliente a refatorações, e força semântica HTML correta. getByTestId só quando não há alternativa (componente de terceiro sem role semântico). Hierarquia: Role > LabelText > PlaceholderText > Text > TestId.
Q.Como testar um form submit?▾
A.Preencher campos com userEvent.type(), submeter com userEvent.click() no botão ou userEvent.keyboard('{Enter}'). Assertar o que acontece: mensagem de sucesso aparece, campo de erro aparece, função de callback foi chamada com os valores corretos.
Q.O que NÃO testar com RTL?▾
A.Internals do componente (state, métodos privados), props que não afetam a UI visível, detalhes de implementação do CSS. Deixar para testes unitários puros: lógica de negócio pura, helpers, reducers — sem React, só Jest.
72/122← →