Saltare al contenuto principale

Test di unità Jest: La guida pratica per gli squadre di JavaScript

Impara l'unit testing con Jest da setup a CI. Tutorial pratico che copre i mock, TypeScript, copertura e le migliori pratiche per JavaScript e applicazioni Capacitor.

Test Unitario con Jest: La Guida Pratica per gli Equipe di JavaScript

Una versione Capacitor può superare le sue verifiche end-to-end e ancora inviare una fattura di calcolo rotto, una bandiera di feature obsoleta o una branca specifica della piattaforma. La falla spesso inizia prima: un test unitario ancora riflette il comportamento vecchio, un mock nasconde una dipendenza cambiata o i CI eseguono un ambiente diverso dalla macchina del developer. Al momento in cui il bug raggiunge un telefono o un desktop Electron, il set di test ha fornito fiducia senza fornire protezione.

Per questo motivo L'unit testing con Jest è meglio trattato come una decisione di workflow in continua evoluzione, non solo come un comando di esecuzione. Le domande utili sono pratiche: quanto velocemente un developer può fidarsi di una falla, quali confini dovrebbero rimanere isolati, quale copertura appartiene ai CI e se Jest ancora si adatta al sistema di moduli e alle aspettative di feedback del progetto? Questa guida si concentra su quelle decisioni in servizi Node, applicazioni web, progetti Capacitor e applicazioni Electron. Per un contesto più ampio su dove le verifiche automatizzate si inseriscono nella consegna, vedere le verifiche automatizzate nei flussi di lavoro software moderni.

Un infographic intitolato Perché Jest Ancora Importa, che descrive le decisioni di workflow, i bug di test obsoleti e le strategie di testing moderne.

Tavola dei Contenuti

Perché i Test Unitari di Jest sono ancora importanti nel 2026

Jest rimane rilevante perché risolve più di sintassi di asserzione. Dà ai team un posto ripetibile per verificare la logica commerciale, controllare i confini delle dipendenze, applicare le aspettative di copertura e eseguire i controlli prima che un pacchetto mobile o desktop raggiunga gli utenti. Quel workflow è importante quando lo stesso comportamento JavaScript viene eseguito in una shell del browser, un WebView Capacitor, un renderer di Electron e un processo Node con API di piattaforma diverse.

La sua adozione ha anche un peso storico. Facebook lo ha creato in 2011 per una riscrittura del chat in JavaScript, l'abbiamo reso open-source 2014, e la OpenJS Foundation ha riferito che aveva superato 38.000 GitHub stelle e 17 milioni di download settimanali nel 2022, salendo a più di 43.000 stelle e 21 milioni di download settimanali nel 2024 (La storia del progetto Jest di OpenJS Foundation). Questi dati non dimostrano che Jest sia adatto per ogni nuovo repository, ma spiegano perché gli squadre spesso ereditano un ecosistema maturo, convenzioni familiari e una grande riserva di esempi esistenti.

Saltare i test unitari a favore di una copertura end-to-end sembra più economico fino a quando ogni piccola falla richiede un lancio completo dell'applicazione, la configurazione del dispositivo, il percorso di rete e la diagnosi specifica della piattaforma. I test E2E sono preziosi per i percorsi critici di rilascio. Sono un cattivo sostituto per controlli veloci e focalizzati sui calcoli fiscali, le manifestazioni di aggiornamento, le decisioni sui permessi, gli adattatori di archiviazione e la mappatura degli errori.

Regola pratica: Tieni Jest quando il suo ecosistema riduce il rischio di migrazione e il tuo insieme di test fornisce ai developer feedback affidabili. Considera un altro esecutore quando l'esecutore stesso è diventato il punto di bottiglia quotidiano.

Il resto di questa guida segue quel workflow. Configurerai Jest in diversi ambienti, scriverai test comportamentali, sceglierai mock che rimangono mantenibili, collegherai i controlli al CI e alla copertura, ridurrai la fluttuazione a livello di scala e farai una scelta deliberata di mantenere o sostituire.

Installazione e Configurazione di Jest in Ambienti diversi

Inizia con la configurazione più piccola che corrisponde al runtime. Un servizio Node solitamente richiede l'ambiente predefinito di Jest e uno script di test. Un modulo Capacitor o Electron che si affaccia su un browser richiede globali DOM, mentre TypeScript aggiunge una decisione di trasformazione che può influire sulla gestione dei bug, sulla compatibilità dei moduli e sul comportamento di avvio.

Per un progetto Node puro, inizializza il pacchetto e installa Jest come dipendenza di sviluppo:

npm init -y
npm install --save-dev jest
npx jest --init

La configurazione generata è un punto di partenza, non un verdetto di progettazione. Verifica l'ambiente di test, le trasformazioni, gli alias dei moduli e i file di configurazione prima di commutarlo.

Scegli deliberatamente la trasformazione di TypeScript

ts-jest è comodo quando il repository già dipende dal comportamento del compilatore di TypeScript e gli sviluppatori vogliono diagnostiche familiari. @swc/jest è spesso attraente quando la velocità della transpilazione è importante e il controllo dei tipi già esegue come comando separato. Nessuna delle opzioni sostituisce un controllo dei tipi, e i pacchetti ESM pesanti possono richiedere ulteriore configurazione indipendentemente dalla trasformazione.

Opzione Node TypeScript Capacitor/Electron
Ambiente node node o progetto specifico jsdom per il front-end code
Trasforma Di solito nessuno ts-jest o @swc/jest Trasformazione TypeScript più impostazione DOM
Gestione dei moduli ESM gestione dei moduli ESM Corrispondenza del formato del pacchetto Verifica del supporto del trasformatore
Impostazione tipica Minimal jest.config.ts setupFilesAfterEnv, falsificazioni, API del browser

A configurazione TypeScript utilizzando ts-jest può avere questo aspetto:

import type { Config } from 'jest'

const config: Config = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
  clearMocks: true,
  collectCoverageFrom: ['src/**/*.{ts,tsx}'],
}

export default config

Per repository JavaScript o misti basati su Babel, mantieni esplicito il file Babel:

module.exports = {
  presets: [
    ['@babel/preset-env', { targets: { node: 'current' } }],
    '@babel/preset-typescript',
  ],
}

Aggiungi solo le shim del browser che il tuo code richiede

Capacitor e test di Electron importano frequentemente code che aspetta window.matchMedia o IntersectionObserverUn file di configurazione può fornire shim controllati senza fingere che Jest sia un dispositivo reale o un shell desktop:

Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: (query: string) => ({
    matches: false,
    media: query,
    onchange: null,
    addListener: () => {},
    removeListener: () => {},
    addEventListener: () => {},
    removeEventListener: () => {},
    dispatchEvent: () => false,
  }),
})

class MockIntersectionObserver {
  observe() {}
  unobserve() {}
  disconnect() {}
}

Object.defineProperty(window, 'IntersectionObserver', {
  writable: true,
  value: MockIntersectionObserver,
})

Se un dipendente ESM solo fallisce durante la raccolta, ispeziona transformIgnorePatterns and the package’s published format. Capacitor plugins can expose this problem when Jest ignores a dependency that still needs transformation. Jest’s newer releases have improved startup and memory behavior, but watch feedback can still trail ESM-focused alternatives in large projects (2026 Confronto tra Jest e Vitest). Treat experimentalVMModules come un meccanismo di compatibilità per testare deliberatamente, non come impostazione predefinita.

Per una guida di configurazione focalizzata su JavaScript, utilizza la guida di testing unitario di Capgo per JavaScript.. Conferma l'installazione con un comando di verifica reale:

npx jest --runInBand

Un test di fumo che passa conferma che Jest può caricare il progetto. Non conferma che i grafici dei moduli di produzione e di test si comportino identicamente, quindi mantieni un test di importazione ESM, DOM e plugin dove sono pertinenti.

Scrivere i primi test unitari affidabili

Un test unitario utile descrive un comportamento osservabile in un contesto controllato. Il pattern Arrange, Act, Assert mantiene quella intenzione visibile: prepara gli input e le dipendenze, chiama la funzione pubblica, quindi verifica il risultato o l'effetto visibile esternamente.

Supponga che un modulo di fattura esporti questa funzione:

export function calculateInvoiceTotal(
  subtotal: number,
  taxRate: number,
  discountRate: number,
): number {
  const discounted = subtotal * (1 - discountRate)
  return Math.round(discounted * (1 + taxRate) * 100) / 100
}

Il test dovrebbe concentrarsi sul comportamento finanziario, non sulla variabile locale denominata discounted:

import { calculateInvoiceTotal } from './calculateInvoiceTotal'

describe('calculateInvoiceTotal', () => {
  it('applies percentage discount before tax', () => {
    const subtotal = 100
    const taxRate = 0.2
    const discountRate = 0.1

    const total = calculateInvoiceTotal(subtotal, taxRate, discountRate)

    expect(total).toBe(108)
  })

  it('rounds the final amount to currency precision', () => {
    const total = calculateInvoiceTotal(19.99, 0.2, 0)

    expect(total).toBe(23.99)
  })
})

Ogni it nome una comportamento. Se un successivo rifacimento cambia la calcolazione interna ma preserva il contratto, questi test dovrebbero rimanere utili.

Una lista grafica che illustra i quattro passaggi essenziali per scrivere test unitari affidabili nel software di sviluppo.

I test asincroni hanno la stessa disciplina. Jest's resolves e rejects rendere esplicito l'outcome della promessa attesa:

it('returns an invoice from the API', async () => {
  await expect(fetchInvoice('invoice-123')).resolves.toMatchObject({
    id: 'invoice-123',
  })
})

it('rejects when the invoice is missing', async () => {
  await expect(fetchInvoice('missing')).rejects.toThrow('Invoice not found')
})

L'errore pericoloso è creare un'aspettativa rifiutata senza attendere o restituirlo. La guida focalizzata su Jest identifica gli errori dimenticati await o return false positivi a causa di dichiarazioni e test che passano senza una chiara avvertenza ("Testare aiuti privati:Una prova che non aspetta mai la sua asserzione non ha verificato il percorso di fallimento.

Evita tre abitudini che producono una fiducia fragile:

  • Testare aiuti privati: Verifica il comportamento esportato a meno che il helper non rappresenti un confine pubblico significativo.
  • Assertare lo stato interno: Preferisci i valori restituiti, gli eventi emessi, i record persistiti o l'output visibile.
  • Sfruttare troppo le affermazioni di chiamata: toHaveBeenCalled() solo dice poco. Controlla gli argomenti pertinenti e il comportamento risultante.

Un checklist di PR può rimanere breve:

  • Ciascun test copre un comportamento?
  • Il test segue l'ordine di disposizione, azione e affermazione?
  • Le aspettative asincrone sono state attendute?
  • Le dipendenze sono state mockate solo a un confine chiaro?
  • Il test sopravvivrebbe a un rifacimento interno?

Per esempi specifici di componenti, Capgo’s guida di testing unitario React applica i medesimi principi di comportamento per l'output visualizzato e le interazioni con l'utente.

Strategie di Mocking che Funzionano

Mockare diventa difficile quando un insieme cresce perché ogni scorciatoia crea un obbligo di manutenzione. Una scrittura a mano jest.fn() Considera un validatore di pagamento che chiama un SDK Stripe, registra un evento di audit e raggiunge un servizio di rischio HTTP. Un test unitario focalizzato potrebbe spiare sul logger, sostituire il pagamento __CAPGO_KEEP_1__ e intercettare la richiesta di rischio. Ogni tecnica controlla un confine diverso.

Consider a payment validator that calls a Stripe SDK, records an audit event, and reaches an HTTP risk service. A focused unit test might spy on the logger, replace the payment SDK, and intercept the risk request. Each technique controls a different boundary.

Strategy Fedelta Fidelity Miglior adatto o
jest.fn() o jest.spyOn() Basso Focalizzato Basso quando locale Callback, logger, servizi iniettati
jest.mock() Medio Basso a medio Può crescere rapidamente SDK, moduli con effetti collaterali costosi
MSW Medio Più alto al confine HTTP Centralizzato Comportamento delle richieste, errori, contratti di risposta

Spie manuali per decisioni locali

Usa una spia quando il dipendente è già iniettato e il test ha bisogno di osservare o controllare un'interazione:

const audit = {
  record: jest.fn(),
}

const result = await validatePayment(input, {
  paymentClient,
  audit,
})

expect(audit.record).toHaveBeenCalledWith(
  expect.objectContaining({ event: 'payment.validated' }),
)
expect(result.status).toBe('approved')

Riprista stato tra i casi. Lo stato condiviso è una fonte comune di fallimenti Jest instabili, e si raccomanda di combinare beforeEach con mock per prevenire il conteggio delle chiamate e la fuoriuscita di stato ("Maestria del testing unitario Jest).

Mock dei moduli per SDK pesanti

Un modulo Stripe o nativo esegue spesso la configurazione non appena carica. Sostituisci quel modulo quando il caricamento dell'implementazione di produzione introdurrebbe credenziali, legami nativi o comportamento irrilevante:

jest.mock('stripe', () => ({
  payments: {
    authorize: jest.fn(),
  },
}))

La richiesta del test dovrebbe ancora affermare il valore restituito dall'applicazione. Un chiamata di SDK di passaggio senza un risultato significativo può dimostrare solo che la mock è stata configurata.

MSW per le giunzioni HTTP

Per code che gestisce la costruzione delle richieste, l'analisi delle risposte, le ripetizioni o la traduzione degli errori, MSW può intercettare il layer HTTP mantenendo la path della richiesta.

server.use(
  http.post('/risk/check', async () => {
    return HttpResponse.json({ decision: 'review' })
  }),
)

Questo dà spesso una maggiore fiducia rispetto al mockaggio di un livello basso fetch chiamare in ogni test. Ciò rende anche le scenari di risposta più facili da nominare e riutilizzare in Node e ambienti browser-like.

Suddividi al centro, non il centro stesso.

L'eccessiva mockatura crea test che passano mentre la connessione di integrazione è rotta. La sottomockatura porta reti reali, filesystem, orologi o database nei test di unità e produce suite lente e non deterministiche. Tenere la logica pura libera da tutte le I/O, quindi spostare la verifica dei confini nei test di contratto o di integrazione dove l'interfaccia conta.

Integrare Jest con CI e Porte di Copertura

La CI dovrebbe rispondere a due domande diverse. In primo luogo, il suite di unità veloce rifiuta un cambiamento pericoloso? In secondo luogo, le verifiche di integrazione più lente confermano che i confini importanti ancora funzionano? Mettere ogni test in un comando indifferenziato rende più difficile la feedback e incoraggia i sviluppatori a bypassare la suite.

Un flusso di lavoro di GitHub Actions può bloccare il runtime Node, utilizzare il file lock per il caching delle dipendenze e eseguire controlli unitari con il modo CI di Jest.

name: test

on:
  pull_request:
  push:

jobs:
  unit:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node: [20, 22]
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
          cache: npm
          cache-dependency-path: package-lock.json

      - run: npm ci
      - run: npm run test:unit, --ci --coverage

      - uses: actions/upload-artifact@v4
        with:
          name: coverage-${{ matrix.node }}
          path: coverage/

Lo script del pacchetto può separare i test veloci dalle attività di integrazione:

{
  "scripts": {
    "test:unit": "jest --runInBand tests/unit",
    "test:integration": "jest --runInBand tests/integration"
  }
}

Utilizzare un livello di copertura che rifletta il rischio piuttosto che selezionare un numero universale per abitudine:

module.exports = {
  collectCoverageFrom: ['src/**/*.{js,ts,tsx}'],
  coverageThreshold: {
    global: {
      branches: 70,
      functions: 80,
      lines: 80,
      statements: 80
    }
  }
}

Quei valori sono esempi di configurazione, non standard dell'industria verificati. Impostare il livello effettivo dal punto di riferimento corrente del repository, quindi aumentarlo quando il team aggiunge copertura significativa. Una porta di sicurezza stretta può bloccare un riparo urgente se misura generato o a basso rischio code. Una porta di sicurezza lenta può lasciare che i percorsi critici decadano inosservati.

Ecco una screenshot da https://docs.github.com/assets/images/help/repository/actions-illustration.png

Per repository grandi, utilizzare la shardizzazione basata su matrice solo dopo aver isolato i test. Ogni shard deve avere una chiara proprietà del suo rapporto, e lo stato finale deve rendere visibili le fallite nella richiesta di pull anziché nasconderle nei log. Le squadre possono anche caricare la copertura HTML come artefatto e pubblicare lcov dati a Codecov o Coveralls, a condizione che il servizio sia configurato per unire i rapporti correttamente.

Leggi disciplina operativa CI insieme al tuo design di workflow, soprattutto se più applicazioni condividono un repository. Capgo’s Integrazione di testing per CI/CD è utile quando lo stato di test deve connettersi all'automazione di build e rilascio mobile.

Mantenere le prove di unità Jest affidabili su larga scala

A large Jest suite can pass consistently while testing the wrong things. Trust declines when tests depend on implementation details, snapshots grow beyond useful review, or shared mocks alter behavior far from the test that configured them.

Snapshots need deliberate ownership. They work well when rendered structure is a real contract, such as a stable component or serialized message. They create noise when developers approve broad updates without inspecting the output. Regenerate them intentionally, review the diff, and remove files that no longer protect meaningful behavior.

Usa layer anziché costringere Jest a gestire tutto

Assegna a ogni layer di testing un compito ristretto:

  • Test unitari puri: Verifica calcoli deterministici, parser, riduttori, decisioni di politica e mapping degli errori senza accesso a rete o filesystem.
  • Test di contratto: Controlla i confini dei moduli, le forme degli adapter, i carichi dei richieste e il comportamento dei plugin.
  • Copertura E2E sottile: Esercita un piccolo insieme di percorsi di utente reali attraverso il web, Capacitor, o shell di Electron.

Questa disposizione mantiene i test unitari veloci mentre controlla i confini dove i mock possono fermarsi di rappresentare la produzione. Inoltre evita un comune modo di fallimento mobile: testare un'intera aggiornamento nativo o un flusso di autorizzazione attraverso un percorso di interfaccia utente costoso invece di isolare la logica di decisione JavaScript.

Tenere una sola comportamento per it() così le fallite rimangono diagnosticabili. L'ordine delle chiamate di asserzione deve essere verificato solo quando l'ordine appartiene al contratto. Un falso queryabile, come un repository in memoria con metodi che espongono i record archiviati, fornisce di solito una maggiore feedback rispetto ai valori di ritorno hardcoded che copiano semplicemente l'implementazione attuale.

Un test che passa dovrebbe spiegare cosa gli utenti o i moduli vicini possono contare su, non come oggi code è attualmente organizzato.

Programma recensioni di salute dei test a cadenza ricorrente. Recensisci i test fluttuanti, le snapshot obsolete, lo setup ridondante e i mock che non corrispondono più al comportamento di produzione. Eliminare un test di basso valore può essere più sicuro che aggiungere un'altra asserzione a un test che già nasconde troppo.

Segnalare instabilità nei dashboard CI. Se un test fallisce senza una code modifica, conserva le prove di fallimento, isolare lo stato condiviso, controllare il tempo e la casualità, e ridurre la pressione sui lavoratori quando il runner è sovraccarico. Impostare i limiti dei lavoratori dalle misurazioni sulle macchine CI, perché l'eccessiva parallelità può aumentare la concorrenza e rendere il set più lento. Conservare la configurazione del lavoratore documentata con la configurazione del runner per future modifiche rimanere intenzionali.

Quadro di decisione e passaggi successivi per il tuo team

Jest rimane un buon default quando un repository già ha un insieme stabile di test, trasformazioni e mock, e un team che valuta la sicurezza della migrazione sopra l'esplorazione del runner. Confrontare alternative quando un nuovo progetto è ESM-first, la feedback nativa è una priorità, o i ripetuti avvii in modalità watch interrompono lo sviluppo. I risultati delle misure possono variare notevolmente in base all'architettura del repository e al lavoro del trasformatore, quindi trattare le comparazioni pubblicate come direzionali piuttosto che promesse.

Utilizzare quattro criteri:

  1. Strumentazione esistente: Conservare Jest quando la configurazione, le utility di test e le convenzioni CI funzionano già.
  2. Formato dei moduli: Riconsiderare il runner quando le dipendenze ESM-only richiedono ripetutamente eccezioni o workaround personalizzati.
  3. Aspettative di feedback: Misurare i cambiamenti watch rappresentativi nel repository reale, non in un progetto demo vuoto.
  4. Capacità del team: Un runner familiare che il team può configurare e debug può produrre risultati migliori di un tool più veloce utilizzato male.

Vitest, il test runner integrato di Node, e Playwright soddisfano esigenze diverse. Playwright appartiene principalmente alla copertura E2E del browser. Il runner di Node può essere adatto a servizi Node focalizzati. Vitest si adatta spesso a progetti ESM e Vite-oriented. Jest si adatta ancora a team che dipendono da mock mature, trasformazioni e convenzioni CI esistenti. Scegliere il runner che preserva confini affidabili mentre mantiene feedback utilizzabile.

Un reset pratico di 90 giorni

Un mese, effettua un audit della suite. Assegna un proprietario per catalogare test flaccidi, snapshot morti, affermazioni legate all'implementazione e test che eseguono I/O reali. L'output dovrebbe essere una lista scritta di rimozioni, riparazioni e confini che richiedono copertura di integrazione.

Un mese, standardizza il design. Aggiungi utilità di test condivise, documenta convenzioni di mocking e introduce la segnalazione di copertura per pacchetti importanti. Registra quali pacchetti hanno porte e quali comportamenti mancano ancora di test focalizzati, in modo che la base rimanga revisionabile.

Un mese, stabilizza la consegna. Regola i lavoratori CI, separa i lavori di unità e integrazione, stabilisci un tetto di copertura basato sul rischio e documenta le convenzioni in un documento vivente. TESTING.md. Il pipeline dovrebbe segnalare fallimenti azionabili, mentre nuovi test seguono gli stessi confini e regole di mocking.

Verifica la suite su un orario ricorrente. Elimina le snapshot obsolete, lo setup ridondante e i mock che non corrispondono più al comportamento di produzione. Un test di basso valore può essere più sicuro da eliminare che da rafforzare con un'altra asserzione. Traccia le fallite fluttuanti nel CI, preserva la prova, isolare lo stato condiviso, controlla il tempo e la casualità e riduci la pressione dei lavoratori quando compare la contesa. Imposta i limiti dei lavoratori dalle misurazioni sulle macchine del CI e tienili documentate con la configurazione del runner.

Queste pratiche appartengono insieme a una maggiore buone pratiche di sviluppo software. For a tested JavaScript fix targeting Capacitor or Electron users, Capgo can deliver signed JavaScript, CSS, configuration, and asset bundles through targeted channels, with rollback protection and release observability, without requiring a store review for every web-layer correction.

Se il tuo team distribuisce applicazioni Capacitor o Electron, visita Capgo to assess how live JavaScript updates fit controlled channels, staged rollouts, and rollback protection. Start by documenting Jest boundaries and CI gates, then define where Capgo belongs in the recovery path for fixes that need prompt delivery.

Aggiornamenti in tempo reale per le app Capacitor

Quando un bug di layer web è attivo, invia la correzione attraverso Capgo invece di attendere giorni per l'approvazione della store. Gli utenti ricevono l'aggiornamento in background mentre le modifiche native rimangono nel normale percorso di revisione.

Sostegno umano da parte di Martin

Inizia subito

Ultimi articoli dal nostro Blog

Capgo ti offre le migliori informazioni che ti servono per creare un'app mobile davvero professionale.