Vai al contenuto principale

Jest 30: Più veloce, più leggero, migliore

· 13 min di lettura
Svyatoslav Zaytsev
Svyatoslav Zaytsev
Traduzione Beta Non Ufficiale

Questa pagina è stata tradotta da PageTurner AI (beta). Non ufficialmente approvata dal progetto. Hai trovato un errore? Segnala problema →

Oggi siamo lieti di annunciare il rilascio di Jest 30. Questa versione include un numero sostanziale di modifiche, correzioni e miglioramenti. Pur trattandosi di uno dei maggiori rilasci principali di Jest mai realizzati, riconosciamo che tre anni per una major release sono troppi. In futuro, miriamo a rilasciare major version più frequentemente per mantenere Jest eccellente nel prossimo decennio.

Se vuoi saltare tutte le novità e iniziare subito, esegui npm install jest@^30.0.0 e segui la guida alla migrazione: Aggiornamento da Jest 29 a Jest 30.

Novità

Jest 30 è notevolmente più veloce, utilizza meno memoria e include tantissime nuove funzionalità. Per prima cosa, diamo un'occhiata ai breaking change:

Modifiche di Rottura

  • Jest 30 rimuove il supporto per Node 14, 16, 19 e 21.

  • jest-environment-jsdom è stato aggiornato da jsdom 21 a 26.

  • La versione minima compatibile di TypeScript è ora la 5.4.

  • Sono stati rimossi vari alias di expect. eslint-plugin-jest include un autofixer che puoi eseguire per aggiornare automaticamente il tuo codice.

  • Le proprietà non enumerabili degli oggetti sono ora escluse per impostazione predefinita dai matcher come toEqual.

  • Jest supporta ora per impostazione predefinita i file .mts e .cts.

  • --testPathPattern è stato rinominato in --testPathPatterns.

  • Jest gestisce ora correttamente le promise che vengono prima respinte e poi catturate, evitando falsi positivi nei test.

  • Abbiamo apportato vari miglioramenti alla stampa degli snapshot che potrebbero richiedere il loro aggiornamento. Google ha deprecato i link goo.gl che utilizzavamo negli snapshot. Nemmeno a noi piace, ma dovrai aggiornare tutti i tuoi snapshot.

  • Jest stesso è ora incluso in un singolo file per pacchetto. Questo migliora le prestazioni, ma potrebbe causare problemi se hai creato strumenti che accedono agli interni di Jest.

Queste sono solo alcune delle novità principali. L'elenco completo dei breaking change è disponibile nel CHANGELOG e nella guida alla migrazione per Jest 30.

Miglioramenti delle prestazioni e della memoria

Jest 30 offre miglioramenti delle prestazioni nel mondo reale grazie a numerose ottimizzazioni, specialmente nella risoluzione dei moduli, utilizzo della memoria e isolamento dei test. Basandosi sul nuovo unrs-resolver, la risoluzione dei moduli in Jest è diventata più ricca di funzionalità, conforme agli standard e più veloce. Un ringraziamento a @JounQin per la migrazione. A seconda del tuo progetto, potresti osservare esecuzioni dei test significativamente più veloci e un consumo di memoria ridotto. Ad esempio, una grande applicazione TypeScript con client e server ha osservato esecuzioni dei test più veloci del 37% e un utilizzo della memoria inferiore del 77% in una parte del loro codice base:

Jest 29Jest 30
Server tests~1350s / 7.8 GB max~850s / 1.8 GB max
Client tests~49s / 1.0 GB max~44s / 0.8 GB max

Jest è veloce, ma a causa dell'isolamento dei test di Jest, il codice utente lento spesso peggiora i problemi di prestazioni e rallenta l'esecuzione dei test. Quando i test lasciano handle aperti come timer non chiusi o connessioni ad altri servizi, Jest potrebbe bloccarsi o rallentare. Jest 30 è migliorato nel rilevare e segnalare questi problemi, aiutandoti a identificare e correggere più facilmente test lenti o problematici. Ad esempio, i test su Happo sono stati accelerati del 50% passando da 14 a 9 minuti grazie alla pulizia degli handle aperti e all'aggiornamento a Jest 30.

Se utilizzi file che consolidano le esportazioni di più moduli in un singolo file (detti "barrel files"), ti consigliamo di usare strumenti come babel-jest-boost, babel-plugin-transform-barrels o no-barrel-file per evitare di caricare grandi quantità di codice dell'applicazione per ogni file di test. Questo può portare a miglioramenti delle prestazioni fino a 100 volte.

Pulizia delle variabili globali tra i file di test

Jest ottiene l'isolamento dei test tra i file eseguendo ogni test in un contesto VM separato, fornendo a ogni file un ambiente globale pulito. Tuttavia, se il tuo codice non pulisce le variabili globali dopo ogni file di test, ciò può causare perdite di memoria in Jest e rallentare l'esecuzione dei test. Jest 30 introduce una nuova funzionalità che ti avvisa delle variabili globali non pulite correttamente dopo l'esecuzione di un test.

In futuro, Jest pulirà automaticamente le variabili globali dopo ogni esecuzione di test. Se non ricevi alcun avviso riguardo a variabili globali non pulite con Jest 30, puoi già impostare la modalità di pulizia delle globali su 'on' per abilitare completamente questa funzionalità e beneficiare di importanti risparmi di memoria e miglioramenti delle prestazioni:

export default {
testEnvironmentOptions: {
globalsCleanup: 'on',
},
};

L'impostazione predefinita in Jest è globalsCleanup: 'soft'. Per disabilitare questa funzionalità puoi impostarla su off. Se devi proteggere oggetti globali specifici dalla pulizia - ad esempio utility condivise o cache - puoi contrassegnarli come protetti usando jest-util:

import {protectProperties} from 'jest-util';

protectProperties(globalThis['my-property']);

Ringraziamo @eyalroth per aver implementato questa funzionalità!

Nuove funzionalità

Migliorato il supporto per ECMAScript Module e TypeScript

È stato aggiunto il supporto per import.meta.* e file:// quando si utilizza ESM nativo con Jest. Inoltre, ora puoi scrivere i tuoi file di configurazione di Jest in TypeScript, e i file .mts e .cts sono supportati nativamente senza necessità di configurazione aggiuntiva. Se utilizzi la funzionalità nativa di Node per la rimozione dei tipi TypeScript, non carichiamo più il transformer TypeScript per rimuovere i tipi, portando a esecuzioni di test più veloci.

Spy e la parola chiave using

Ora puoi utilizzare la nuova sintassi di gestione esplicita delle risorse di JavaScript (using) con gli spy di Jest. Se il tuo ambiente lo supporta, scrivere using jest.spyOn(obj, 'method') ripristinerà automaticamente lo spy al termine del blocco, quindi non dovrai pulire manualmente.

test('logs a warning', () => {
using spy = jest.spyOn(console, 'warn');
doSomeThingWarnWorthy();
expect(spy).toHaveBeenCalled();
});

Documentazione

expect.arrayOf

Jest 30 introduce un nuovo matcher asimmetrico, expect.arrayOf, che ti permette di validare ogni elemento di un array rispetto a una condizione o tipo. Ad esempio, puoi verificare che un array contenga solo numeri assicurandoti che tutti gli elementi siano numeri:

expect(someArray).toEqual(expect.arrayOf(expect.any(Number)));

Documentazione

Nuovo segnaposto per test.each: %$

Se utilizzi test basati sui dati con test.each, ora puoi includere un segnaposto speciale %$ nei titoli dei test per inserire il numero del caso di test. Ad esempio:

test.each(cases)('Case %$ works as expected', () => {});

sostituirà %$ con il numero progressivo del test.

Documentazione

jest.advanceTimersToNextFrame()

@sinonjs/fake-timers è stato aggiornato alla versione 13, aggiungendo jest.advanceTimersToNextFrame(). Questa nuova funzione ti permette di avanzare tutte le callback requestAnimationFrame in attesa al limite del frame successivo, semplificando il test di animazioni o codice che si basa su requestAnimationFrame senza dover indovinare la durata in millisecondi.

Documentazione

Tentativi di test configurabili

Jest 30 migliora jest.retryTimes() con nuove opzioni che ti danno il controllo sulla gestione dei tentativi. Puoi specificare un ritardo o ripetere immediatamente un test fallito senza attendere il completamento dell'intera suite di test:

// Retry failed tests up to 3 times, waiting 1 second between attempts:
jest.retryTimes(3, {waitBeforeRetry: 1000});

// Immediately retry without waiting for other tests to finish:
jest.retryTimes(3, {retryImmediately: true});

Documentazione

jest.unstable_unmockModule()

Jest 30 introduce la nuova API sperimentale jest.unstable_unmockModule() per un controllo più granulare durante la rimozione dei mock dai moduli (soprattutto con ESM nativo).

Documentazione

jest.onGenerateMock(callback)

È stato aggiunto il nuovo metodo onGenerateMock. Registra una funzione di callback che viene richiamata ogni volta che Jest genera un mock per un modulo, consentendoti di modificarlo prima che venga restituito al tuo ambiente di test:

jest.onGenerateMock((modulePath, moduleMock) => {
if (modulePath.includes('Database')) {
moduleMock.connect = jest.fn().mockImplementation(() => {
console.log('Connected to mock DB');
});
}
return moduleMock;
});

Documentazione

Altri Miglioramenti

Serializzazione personalizzata degli oggetti

Le utility di matching di Jest ora supportano la definizione di SERIALIZABLE_PROPERTIES statica sugli oggetti personalizzati. Ciò ti permette di controllare quali proprietà vengono incluse negli snapshot e nei messaggi d'errore, rendendo l'output più mirato e pertinente.

Documentazione

Supporto per configurazione asincrona

I file di test elencati in setupFilesAfterEnv possono ora esportare funzioni asincrone o usare await di primo livello, analogamente a setupFiles.

E molto altro ancora…

Consulta il CHANGELOG completo per tutti i cambiamenti, miglioramenti e nuove funzionalità.

Problemi noti

jsdom ha apportato modifiche per maggiore conformità alle specifiche. Ciò potrebbe interrompere alcuni casi d'uso, in particolare il mocking di window.location nei test. Jest ora include @jest/environment-jsdom-abstract per semplificare la creazione di ambienti di test personalizzati basati su jsdom. Se vuoi solo applicare una patch a jsdom, puoi usare questa patch jsdom per il tuo progetto. In futuro potremmo valutare alternative a jsdom più adatte al testing.

Prossimi passi

Jest è il framework di testing JavaScript più popolare da un decennio, usato da milioni di sviluppatori su progetti che vanno da piccole librerie ai codebase più grandi al mondo. Sebbene sia stato costantemente migliorato, come tutti i progetti software di lunga durata abbiamo accumulato debito tecnico. Supportiamo funzionalità usate da pochi, mantenendo le breaking change minime per non disturbare gli utenti. Alcune funzionalità dovrebbero essere possibili senza far parte del core, altre promuovono pratiche di testing inadeguate. Alcuni membri del team hanno cambiato ruolo, rallentando i progressi. Ecco come affronteremo queste sfide:

  • Prestazioni/Debito tecnico: Snellire il core di Jest rendendolo più leggero e performante, rimuovendo funzionalità poco usate e focalizzandoci sull'essenza di Jest.

  • Cicli di rilascio coerenti: Garantiremo maggiore regolarità nei cicli di rilascio e nelle politiche di deprecazione.

  • Trasparenza: Costruiremo tutto pubblicamente, comunicando chiaramente i piani. Creeremo più opportunità di contributo per aumentare i collaboratori.

  • Siate audaci: Come team di Jest, dovremmo essere più coraggiosi. Ci sono molti fattori che limitano il potenziale completo di Jest. È il momento di agire.

La buona notizia è che Jest è sempre stato impostato perfettamente per rispettare questi principi, fin da quando abbiamo creato il framework come sistema modulare con una chiara separazione delle responsabilità. Ora è il momento di eseguire. Altro su tutto questo a breve!

Ringraziamenti

Questa release non sarebbe stata possibile senza il duro lavoro della nostra comunità. Grazie.

@SimenB, @mrazauskas, @Connormiha, @liuxingbaoyu, @k-rajat19, @G-Rath, @charpeni, @dubzzz, @stekycz, @yinm, @lencioni, @phawxby, @lukeapage, @robhogan, @fisker, @k-rajat19, @connectdotz, @alesmenzel, @rickhanlonii, @mbelsky, @brunocabral88, @brandon-leapyear, @nicolo-ribaudo, @dj-stormtrooper, @eryue0220

Un ringraziamento speciale a tutti coloro che hanno contribuito per la prima volta a Jest in questa release. Grazie per aver reso Jest migliore per tutti!

@eyalroth, @KhaledElmorsy, @mohammednumaan, @bensternthal, @BondarenkoAlex, @phryneas, @jayvdb, @brandonchinn178, @latin-1, @rmartine-ias, @fa93hws, @Dunqing, @gustav0d, @noritaka1166, @andreibereczki, @Dreamsorcerer, @satanTime, @icholy, @ecraig12345, @cgm-16, @sebastiancarlos, @dancer1325, @loganrosen, @zakingslayerv22, @dev-intj, @tez3998, @anbnyc, @pengqiseven, @thypon, @co63oc, @danielrentz, @jonasongg, @andrew-the-drawer, @phryneas, @hyperupcall, @tonyd33, @madcapnmckay, @dongwa, @gagan-bhullar-tech, @ikonst, @ZuBB, @jzaefferer, @brandonnorsworthy, @henny1105, @DmitryMakhnev, @askoufis, @RahulARanger, @Jon-Biz, @fynsta, @KonnorRogers, @BondarenkoAlex, @mouadhbb, @kemuridama, @Avi-E-Koenig, @davidroeca, @akwodkiewicz, @mukul-turing, @dnicolson, @colinacassidy, @ofekm97, @haze, @Vadimchesh, @peterdenham, @ShuZhong, @manoraj, @nicolo-ribaudo, @georgekaran, @MathieuFedrigo, @hkdobrev, @Germandrummer92, @CheadleCheadle, @notaphplover, @danbeam, @arescrimson, @yepitschunked, @JimminiKin, @DerTimonius, @vkml, @ginabethrussell, @jeremiah-snee-openx, @WillianAgostini, @casey-lentz, @faizanu94, @someone635, @rafaelrabelos, @RayBrokeSomething, @DaniAcu, @mattkubej, @tr1ckydev, @shresthasurav, @the-ress, @Mutesa-Cedric, @nolddor, @alexreardon, @Peeja, @verycosy, @mknight-atl, @maro1993, @Eric-Tyrrell22