# Testare un form react-hook-form

Un form react-hook-form si testa dal DOM: digita con userEvent, clicca il submit e attendi l'errore con findByText. Non mockare la libreria.

> Pagina: https://ui.eneawork.it/blog/test-form-react-hook-form
> Markdown: https://ui.eneawork.it/blog/test-form-react-hook-form.md

*2026-11-01*

Un form react-hook-form si testa dal DOM: digita con userEvent, clicca il submit e attendi il messaggio con findByText. Mockare la libreria toglie proprio la parte da verificare.

Il catalogo EneUI conta 111.985 componenti, 1.556 blocchi e 12.808 icone da 1.472 librerie, misurati da /api/stats il 1 novembre 2026. La cifra viene da una query all'endpoint, non da una stima, e vale per il catalogo pubblicato in quella data.

## La regola di base

react-hook-form, con licenza MIT, registra gli input e valida al submit o al blur. Il messaggio d'errore compare dopo una microtask, quindi un getByText sincrono fallisce quasi sempre.

## Il test che vale come modello

import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; test("rifiuta l'email vuota", async () => { const onSubmit = vi.fn(); render(); await userEvent.click(screen.getByRole("button", { name: "Crea account" })); expect(await screen.findByText("Email obbligatoria")).toBeInTheDocument(); expect(onSubmit).not.toHaveBeenCalled(); });

Il test non tocca register né handleSubmit: clicca il pulsante reale e verifica due cose, la callback non chiamata e il messaggio visibile.

## I quattro casi che bastano

## Setup

npm i -D vitest jsdom @testing-library/react @testing-library/user-event react-hook-form npx vitest run --environment jsdom

Tutto MIT, tutto in locale: react-hook-form non fa chiamate di rete e il test non ha bisogno di un browser.

## Record vivi nel catalogo

Tre form su cui provare i quattro casi: login-form, credit-card-form e otp-input. Per esplorare per categoria parti da 111.985 componenti.

## La limitazione

userEvent digita carattere per carattere, quindi un campo lungo rallenta la suite: si usa paste quando il testo non è il punto del test. In jsdom, inoltre, autofill e gestori di password non esistono, e quei bug restano fuori.

## Dove continuare

Il form con shadcn è in form con react-hook-form; controllato contro non controllato è in input controllati; il modello di test è in Testing Library: cinque test; il confronto misurato fra librerie è in librerie React 2026.

## FAQ

### Devo mockare react-hook-form?

No. Il mock spegne validazione e stato, cioè la logica da verificare: si testa il form renderizzato.

### Come invio il form in un test?

Con un clic sul pulsante di submit trovato per ruolo. submit() sull'elemento salta i gestori legati al clic.

### Perché il messaggio di errore non compare?

Perché la validazione è asincrona: serve await findByText, non getByText subito dopo il clic.

### Come testo un campo con maschera?

Digiti il valore finale e verifichi il testo mostrato; la sequenza dei tasti è un dettaglio dell'implementazione.

### Il test copre anche la validazione lato server?

No, copre solo la risposta simulata. La regola vera resta sul server ed è quella che conta.
