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← →