Diego Betto
Foto di Nguyen Dang Hoang Nhu su Unsplash

Diego Betto · 22 settembre 2026 · 4 min di lettura

Vitest: cos'è, come si installa e come usarlo con React 19

Guida pratica a Vitest: installazione, configurazione, come testare componenti React 19 (incluso useActionState), mock con vi, coverage e confronto con Jest e node:test.

Condividi:XLinkedInFacebookWhatsApp

Vitest è il test runner sviluppato dal team di Vite, pensato per condividere la stessa pipeline di trasformazione del bundler: stesso vite.config.ts, stessi plugin, stessi alias, niente configurazione parallela da mantenere. L’API è deliberatamente compatibile con quella di Jest (describe, it, expect), quindi la migrazione da un progetto Jest esistente è quasi sempre un cambio di importazioni, non una riscrittura.

Installazione

npm install -D vitest

Per progetti React serve anche un ambiente DOM e le utility di testing:

npm install -D jsdom @testing-library/react @testing-library/jest-dom @testing-library/user-event

La configurazione va nello stesso file di Vite (o in un vitest.config.ts separato, se preferisci tenerla isolata dal build):

// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [react()],
  test: {
    environment: "jsdom",
    globals: true,
    setupFiles: "./vitest.setup.ts",
  },
});
// vitest.setup.ts
import "@testing-library/jest-dom/vitest";

globals: true evita di dover importare describe/it/expect in ogni file (stesso comportamento a cui è abituato chi arriva da Jest).

Un primo test

// somma.test.js
import { expect, test } from "vitest";
import { somma } from "./somma.js";

test("somma due numeri positivi", () => {
  expect(somma(2, 3)).toBe(5);
});
npx vitest

Di default parte in watch mode e riesegue solo i test toccati dai file modificati, sfruttando lo stesso grafo di dipendenze che Vite usa per l’HMR — è la differenza pratica più evidente rispetto a Jest: qui non c’è un transform separato da ricalcolare, i file già trasformati restano in cache.

Testare un componente React 19

Esempio con useActionState, l’hook introdotto in React 19 per gestire lo stato derivato da una form action:

// LikeButton.tsx
import { useActionState } from "react";

async function likeAction(prevState: number) {
  await new Promise((resolve) => setTimeout(resolve, 50));
  return prevState + 1;
}

export function LikeButton() {
  const [likes, formAction, isPending] = useActionState(likeAction, 0);

  return (
    <form action={formAction}>
      <button type="submit" disabled={isPending}>
        {isPending ? "..." : `Mi piace (${likes})`}
      </button>
    </form>
  );
}
// LikeButton.test.tsx
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { expect, test } from "vitest";
import { LikeButton } from "./LikeButton";

test("incrementa i like dopo il submit", async () => {
  const user = userEvent.setup();
  render(<LikeButton />);

  await user.click(screen.getByRole("button"));

  expect(await screen.findByText("Mi piace (1)")).toBeInTheDocument();
});

findByText è necessario perché formAction è asincrona: il bottone passa prima per lo stato isPending, e serve aspettare il re-render finale invece di leggere subito il DOM con getByText. Per approfondire le altre novità dell’hook system in React 19 (incluso use()), c’è l’articolo su use vs useContext.

Mock con vi

import { vi, test, expect } from "vitest";
import { registraUtente } from "./registraUtente.js";

test("chiama il servizio email con i parametri giusti", () => {
  const inviaEmail = vi.fn(() => true);

  registraUtente({ email: "[email protected]" }, { inviaEmail });

  expect(inviaEmail).toHaveBeenCalledWith("[email protected]");
});

vi.spyOn() sostituisce temporaneamente un metodo su un oggetto esistente, vi.mock() sostituisce un intero modulo (utile per isolare chiamate fetch o client HTTP) — stessa superficie concettuale di jest.fn/jest.spyOn/jest.mock, nomi diversi.

💡 Consiglio

npx vitest --ui apre una dashboard nel browser con l’elenco dei test, i risultati e un timeline dei singoli assert — utile per debuggare una suite grande senza leggere output di terminale. Richiede il pacchetto separato @vitest/ui.

Coverage

npm install -D @vitest/coverage-v8
npx vitest run --coverage

Il coverage usa la stessa strumentazione V8 di Node, con report testuale in console e HTML navigabile generato in coverage/ — pronto all’uso, senza configurare istanbul/nyc a parte.

Vitest vs Jest vs node:test

Vitest Jest node:test
Config condivisa col build Sì (stesso vite.config.ts) No (config separata) N/A
TypeScript/JSX senza setup extra Serve ts-jest/babel-jest Serve loader esterno
Ambiente DOM (jsdom) Sì, con un flag Sì, con un flag Manuale
Snapshot testing No
Dipendenze Vite + eventuali plugin Nessuna extra (ma ecosistema Babel spesso presente) Zero
Watch mode basato su Grafo di dipendenze Vite (HMR) File system polling File system

Jest resta la scelta più matura per progetti non basati su Vite, con anni di plugin ed estensioni editor. node:test è l’opzione a costo zero per librerie senza dipendenze DOM, ma manca di snapshot testing e ambiente jsdom integrato — l’ho confrontato più in dettaglio nell’articolo su node:test vs Jest. Vitest si posiziona nel mezzo: per progetti già su Vite, Astro, Next.js (in modalità Vite) o qualsiasi setup React/TypeScript moderno, è quasi sempre la scelta con meno attrito, perché riusa configurazione e velocità del bundler che il progetto ha già.

Quando ha senso sceglierlo

Se il progetto usa già Vite (o un framework basato su Vite), Vitest evita di mantenere due pipeline di build separate e parte più veloce grazie al transform condiviso. Per progetti legacy su Webpack con una suite Jest grande e stabile, la migrazione raramente vale il tempo che costa — a meno che la lentezza dei test in CI sia già un problema concreto da risolvere.

Condividi:XLinkedInFacebookWhatsApp
Diego Betto

Scritto da

Diego Betto

Co-Fondatore & CTO presso PAPION. Senior full-stack engineer specializzato in React, TypeScript, Node.js e sicurezza applicativa.