DEV Community

Cover image for Testando Componentes com React Hook Form + Zod
Vitor Rios
Vitor Rios

Posted on

Testando Componentes com React Hook Form + Zod

A combinação entre React Hook Form (RHF) e Zod tem se tornado cada vez mais comum em projetos modernos. Ela proporciona uma forma simples, rápida e tipada de lidar com formulários e validações — mas como garantir que tudo isso está funcionando corretamente?

Neste artigo, vamos aprender como testar formulários que usam RHF + Zod, cobrindo:

  • Validação de campos
  • Submissão bem-sucedida
  • Mensagens de erro
  • Testes automatizados com Jest + Testing Library

🎯 O que vamos testar?

Vamos usar como base um formulário simples de login:

// LoginForm.tsx import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; const schema = z.object({ email: z.string().email(), password: z.string().min(6), }); type FormData = z.infer<typeof schema>; export function LoginForm({ onSubmit }: { onSubmit: (data: FormData) => void }) { const { register, handleSubmit, formState: { errors }, } = useForm<FormData>({ resolver: zodResolver(schema), }); return ( <form onSubmit={handleSubmit(onSubmit)}> <input placeholder="Email" {...register('email')} /> {errors.email && <span>{errors.email.message}</span>} <input type="password" placeholder="Password" {...register('password')} /> {errors.password && <span>{errors.password.message}</span>} <button type="submit">Login</button> </form> ); } 
Enter fullscreen mode Exit fullscreen mode

🧪 Testes com @testing-library/react

Agora, vamos aos testes:

// LoginForm.test.tsx import { render, screen, fireEvent } from '@testing-library/react'; import { LoginForm } from './LoginForm'; describe('LoginForm', () => { it('shows validation errors when submitting empty form', async () => { const handleSubmit = jest.fn(); render(<LoginForm onSubmit={handleSubmit} />); fireEvent.click(screen.getByRole('button', { name: /login/i })); expect(await screen.findByText(/invalid email/i)).toBeInTheDocument(); expect(await screen.findByText(/at least 6 characters/i)).toBeInTheDocument(); expect(handleSubmit).not.toHaveBeenCalled(); }); it('submits successfully with valid data', async () => { const handleSubmit = jest.fn(); render(<LoginForm onSubmit={handleSubmit} />); fireEvent.input(screen.getByPlaceholderText(/email/i), { target: { value: 'test@example.com' }, }); fireEvent.input(screen.getByPlaceholderText(/password/i), { target: { value: '123456' }, }); fireEvent.click(screen.getByRole('button', { name: /login/i })); await screen.findByRole('button'); // espera render do submit expect(handleSubmit).toHaveBeenCalledWith({ email: 'test@example.com', password: '123456', }); }); }); 
Enter fullscreen mode Exit fullscreen mode

✅ O que estamos validando aqui?

  • Que os erros de validação aparecem corretamente ao submeter o formulário vazio
  • Que a função onSubmit só é chamada quando os dados são válidos
  • Que o componente está de fato validando com base no schema Zod

🧠 Dicas extras

  • Para campos dinâmicos (como arrays ou steps), use useFieldArray + testes com múltiplos steps.
  • Utilize renderWithProviders() se seu formulário estiver dentro de Providers como Theme ou QueryClient.
  • Teste os campos com screen.getByPlaceholderText, getByLabelText, ou getByRole, e evite getByTestId a menos que não tenha alternativa.

🏁 Conclusão

Testar formulários com React Hook Form e Zod é simples quando você entende como os erros e validações são exibidos. Usar @testing-library/react junto com mocks como jest.fn() torna tudo mais previsível e confiável — e ainda te protege contra regressões no futuro.

Aposte nesse combo em seus projetos e garanta que os formulários estejam funcionando como esperado.

Top comments (0)