Diego Betto's Blog
Foto di Jakub Żerdzicki su Unsplash

Diego Betto · 4 settembre 2026 · 3 min di lettura

Il test runner nativo di Node.js: vale la pena lasciare Jest?

Guida pratica a node:test, il test runner integrato in Node.js: setup senza dipendenze, sintassi base, mock, coverage e cosa manca ancora rispetto a Jest.

Condividi:XLinkedInFacebookWhatsApp

Node.js ha un test runner integrato dalla versione 18 (stabile dalla 20), ma la stragrande maggioranza dei progetti continua a installare Jest o Vitest per default, spesso senza chiedersi se serva davvero. Il modulo node:test è maturato abbastanza da essere un’alternativa concreta per una buona fetta di progetti — non per tutti.

Setup: zero dipendenze

Non serve installare nulla. node:test fa parte del runtime:

// somma.test.js
import { test } from "node:test";
import assert from "node:assert/strict";
import { somma } from "./somma.js";

test("somma due numeri positivi", () => {
  assert.strictEqual(somma(2, 3), 5);
});

test("somma con un negativo", () => {
  assert.strictEqual(somma(5, -2), 3);
});
node --test

Nessun file di configurazione, nessun transform da configurare per ESM — node --test cerca automaticamente i file che matchano pattern comuni (*.test.js, *.spec.js, cartelle test/) ed esegue tutto in parallelo per default.

describe/it, hook e test asincroni

La sintassi è deliberatamente vicina a quella di Jest/Mocha, per rendere la migrazione meno dolorosa:

import { describe, it, before, after } from "node:test";
import assert from "node:assert/strict";

describe("UtenteRepository", () => {
  let repo;

  before(() => {
    repo = new UtenteRepository();
  });

  after(async () => {
    await repo.chiudi();
  });

  it("trova un utente per id", async () => {
    const utente = await repo.trovaPerId(1);
    assert.equal(utente.nome, "Diego");
  });

  it("lancia se l'id non esiste", async () => {
    await assert.rejects(() => repo.trovaPerId(999), /non trovato/);
  });
});

assert.rejects/assert.doesNotReject coprono i casi async che in Jest richiedono expect(...).rejects.toThrow() — l’API è più verbosa in alcuni punti, ma copre gli stessi scenari.

Mock integrati, senza librerie esterne

Dalla 20 in poi, node:test include un sistema di mock nativo (t.mock), che copre buona parte di quello per cui prima serviva jest.fn() o sinon:

import { test } from "node:test";
import assert from "node:assert/strict";

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

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

  assert.strictEqual(invia.mock.callCount(), 1);
  assert.deepEqual(invia.mock.calls[0].arguments, ["[email protected]"]);
});

t.mock.method() permette anche di sostituire temporaneamente un metodo su un oggetto esistente (l’equivalente di jest.spyOn), e viene ripristinato automaticamente alla fine del test.

💡 Consiglio

node --test --watch riesegue solo i test dei file modificati, con lo stesso spirito di jest --watch. Utile durante lo sviluppo, anche se il feedback su quali test sono stati re-triggerati è più essenziale rispetto all’interfaccia di Jest.

Coverage senza pacchetti aggiuntivi

node --test --experimental-test-coverage

Il coverage è generato internamente (usa la strumentazione V8, non istanbul/nyc), stampato in console per default. Per un report HTML navigabile serve comunque configurare un reporter esterno — qui Jest, con --coverage pronto all’uso e integrazioni editor mature, resta più comodo.

Cosa manca ancora rispetto a Jest

  • Snapshot testing: node:test non ha un equivalente nativo di toMatchSnapshot(). Per progetti che si affidano molto agli snapshot (tipicamente componenti UI), è un’assenza che pesa.
  • Ambiente DOM/jsdom integrato: Jest configura jsdom con un flag; con node:test va aggiunto manualmente. Per testare componenti React/Vue è un lavoro in più che Jest (o Vitest) risparmiano.
  • Matcher espressivi: assert.strictEqual/assert.deepEqual coprono i casi comuni, ma l’ecosistema di matcher di expect (toBeCloseTo, toContainEqual, matcher custom) è più ricco e leggibile per asserzioni complesse.
  • Ecosistema di plugin ed editor integration: Jest (e Vitest) hanno anni di plugin, estensioni VS Code e integrazioni CI mature. node:test è più recente e la superficie di tooling attorno è ancora più piccola.

Quando ha senso migrare

Per librerie e pacchetti Node.js senza dipendenze da DOM — utility, client HTTP, logica di business pura, script CLI — node:test è spesso sufficiente e rimuove una dipendenza intera dal progetto, con avvio più veloce (nessun transform da caricare) e zero configurazione da mantenere. Per progetti frontend con componenti da renderizzare e snapshot da confrontare, o suite di test già grandi e stabili su Jest, la migrazione raramente vale il tempo che costa: il beneficio principale di node:test è partire senza dipendenze, non convertire quello che già funziona.

Per il resto dell’ecosistema Node lato sicurezza e manutenzione, vale la pena tenere d’occhio anche gli aggiornamenti descritti nell’articolo sulle security release di Node.js.

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.