R
Interview Deckreact · next.js · senior/staff
0·0·122
Testing

Testing — RTL e Jest

Testar comportamento, não implementação. getByRole, userEvent, e o que não testar.

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
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.
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.
// ✅ 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ê
})
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← →