Aller au contenu principal

Jest 30 : Plus rapide, plus léger, meilleur

· 13 min de lecture
Svyatoslav Zaytsev
Svyatoslav Zaytsev
Traduction Bêta Non Officielle

Cette page a été traduite par PageTurner AI (bêta). Non approuvée officiellement par le projet. Vous avez trouvé une erreur ? Signaler un problème →

Nous sommes heureux d'annoncer aujourd'hui la sortie de Jest 30. Cette version comprend un nombre substantiel de changements, correctifs et améliorations. Bien qu'il s'agisse de l'une des majeures les plus importantes de Jest à ce jour, nous reconnaissons qu'un intervalle de trois ans entre deux versions majeures est trop long. À l'avenir, nous prévoyons de publier des majeures plus fréquemment pour maintenir Jest au top pendant la prochaine décennie.

Si vous souhaitez passer directement à l'action, exécutez npm install jest@^30.0.0 et suivez le guide de migration : Migration de Jest 29 vers Jest 30.

Quoi de neuf ?

Jest 30 est nettement plus rapide, consomme moins de mémoire et propose des tonnes de nouvelles fonctionnalités. Commençons par examiner les changements cassants :

Changements cassants

  • Jest 30 abandonne la prise en charge de Node 14, 16, 19 et 21.

  • jest-environment-jsdom a été mis à niveau de jsdom 21 à 26.

  • La version minimale compatible de TypeScript est désormais la 5.4.

  • Plusieurs alias d'expect ont été supprimés. eslint-plugin-jest propose un autofix que vous pouvez exécuter pour mettre à jour automatiquement votre codebase.

  • Les propriétés non énumérables des objets sont désormais exclues par défaut des comparateurs comme toEqual.

  • Jest prend désormais en charge nativement les fichiers .mts et .cts.

  • --testPathPattern a été renommé en --testPathPatterns.

  • Jest gère désormais correctement les promesses d'abord rejetées puis rattrapées pour éviter des échecs de tests faux positifs.

  • Nous avons apporté diverses améliorations à l'affichage des snapshots dans Jest, ce qui pourrait nécessiter une mise à jour de vos snapshots. Google a abandonné les liens goo.gl que nous utilisions dans les snapshots. Nous le déplorons aussi, mais vous devrez mettre à jour tous vos snapshots.

  • Jest est désormais regroupé dans un seul fichier par package. Cela améliore les performances, mais pourrait poser problème si vous avez développé des outils accédant aux internes de Jest.

Ce ne sont là que quelques points forts. La liste complète des changements cassants est disponible dans le CHANGELOG et le guide de migration vers Jest 30.

Améliorations des performances et de la mémoire

Jest 30 offre des gains de performance tangibles grâce à de nombreuses optimisations, notamment concernant la résolution de modules, l'utilisation mémoire et l'isolation des tests. En s'appuyant sur le nouveau unrs-resolver, la résolution de modules dans Jest est devenue plus riche en fonctionnalités, plus conforme aux standards et plus rapide. Merci à @JounQin pour cette migration. Selon votre projet, vous pourriez constater des exécutions de tests significativement plus rapides et une consommation mémoire réduite. Par exemple, une grande application TypeScript avec client et serveur a observé une accélération de 37% des tests et une réduction de 77% de l'utilisation mémoire dans une partie de son codebase :

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 est rapide, mais en raison de son isolation des tests, du code utilisateur lent exacerbe souvent les problèmes de performance et entraîne des exécutions de tests lentes. Lorsque les tests laissent des handles ouverts comme des minuteries non fermées ou des connexions à d'autres services, Jest peut se bloquer ou ralentir. Jest 30 détecte et signale mieux ces problèmes, ce qui vous aide à identifier et corriger plus facilement les tests lents ou problématiques. Par exemple, les tests chez Happo ont été accélérés de 50%, passant de 14 minutes à 9 minutes, en nettoyant les handles ouverts et en migrant vers Jest 30.

Si vous utilisez des fichiers qui regroupent les exports de plusieurs modules dans un seul fichier (appelés "barrel files"), nous recommandons d'utiliser des outils comme babel-jest-boost, babel-plugin-transform-barrels ou no-barrel-file pour éviter de charger de grandes quantités de code applicatif pour chaque fichier de test. Cela peut entraîner des améliorations de performance allant jusqu'à 100 fois.

Nettoyage des variables globales entre les fichiers de test

Jest assure l'isolation des tests entre les fichiers en exécutant chaque test dans un contexte VM distinct, offrant ainsi à chaque fichier un environnement global vierge. Cependant, si votre code ne nettoie pas les variables globales après chaque fichier de test, cela peut provoquer des fuites de mémoire dans Jest et ralentir l'exécution de vos tests. Jest 30 introduit une nouvelle fonctionnalité qui vous avertit des variables globales non correctement nettoyées après une exécution de test.

À l'avenir, Jest nettoiera automatiquement les variables globales après chaque exécution de test. Si vous ne recevez aucun avertissement concernant des variables globales non nettoyées avec Jest 30, vous pouvez dès à présent activer pleinement cette fonctionnalité en réglant le mode de nettoyage sur "on", ce qui vous permettra de bénéficier d'économies de mémoire significatives et d'améliorations de performances :

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

La valeur par défaut dans Jest est globalsCleanup: 'soft'. Pour désactiver cette fonctionnalité, vous pouvez la régler sur off. Si vous devez protéger des objets globaux spécifiques contre le nettoyage - par exemple des utilitaires partagés ou des caches - vous pouvez les marquer comme protégés en utilisant jest-util :

import {protectProperties} from 'jest-util';

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

Merci à @eyalroth d'avoir implémenté cette fonctionnalité !

Nouvelles fonctionnalités

Amélioration de la prise en charge des modules ECMAScript et TypeScript

La prise en charge de import.meta.* et file:// a été ajoutée lors de l'utilisation d'ESM natif avec Jest. De plus, vous pouvez désormais écrire vos fichiers de configuration Jest en TypeScript, et les fichiers .mts et .cts sont pris en charge nativement sans configuration supplémentaire. Si vous utilisez la fonctionnalité native de suppression des types TypeScript de Node, nous ne chargeons plus le transformateur TypeScript pour supprimer les types, ce qui accélère l'exécution des tests.

Espions et mot-clé using

Vous pouvez désormais utiliser la nouvelle syntaxe de gestion explicite des ressources de JavaScript (using) avec les espions Jest. Si votre environnement le prend en charge, écrire using jest.spyOn(obj, 'method') restaurera automatiquement l'espion à la fin du bloc, vous évitant ainsi de devoir le nettoyer manuellement.

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

Documentation

expect.arrayOf

Jest 30 introduit un nouveau matcher asymétrique, expect.arrayOf, qui vous permet de valider chaque élément d'un tableau par rapport à une condition ou un type. Par exemple, vous pouvez vérifier qu'un tableau est composé de nombres en vous assurant que tous les éléments sont des nombres :

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

Documentation

Nouvel espace réservé pour test.each : %$

Si vous utilisez des tests pilotés par les données avec test.each, vous pouvez désormais inclure un espace réservé spécial %$ dans les titres de vos tests pour y injecter le numéro du cas de test. Par exemple :

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

remplacera %$ par le numéro de séquence du test.

Documentation

jest.advanceTimersToNextFrame()

@sinonjs/fake-timers a été mis à niveau vers la v13, ajoutant jest.advanceTimersToNextFrame(). Cette nouvelle fonction vous permet d'avancer toutes les callbacks requestAnimationFrame en attente à la limite de l'image suivante, facilitant ainsi le test d'animations ou de code reposant sur requestAnimationFrame sans avoir à deviner des durées en millisecondes.

Documentation

Tentatives de test configurables

Jest 30 améliore jest.retryTimes() avec de nouvelles options vous donnant un contrôle précis sur la gestion des nouvelles tentatives. Vous pouvez spécifier un délai ou relancer immédiatement un test en échec sans attendre la fin de toute la suite de tests :

// 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});

Documentation

jest.unstable_unmockModule()

Jest 30 introduit une nouvelle API expérimentale jest.unstable_unmockModule() pour un contrôle plus fin lors de la suppression du mockage des modules (particulièrement utile avec les modules ESM natifs).

Documentation

jest.onGenerateMock(callback)

Une nouvelle méthode onGenerateMock a été ajoutée. Elle enregistre une fonction de rappel invoquée à chaque génération de mock par Jest. Ce callback vous permet de modifier un mock avant son injection dans l'environnement de test :

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

Documentation

Autres améliorations

Sérialisation d'objets personnalisés

Les utilitaires de matchers de Jest prennent désormais en charge la définition d'une propriété statique SERIALIZABLE_PROPERTIES sur les objets personnalisés. Cela permet de contrôler quelles propriétés sont incluses dans les snapshots et messages d'erreur, rendant les sorties plus ciblées :

Documentation

Support de l'initialisation asynchrone

Les fichiers de test listés dans setupFilesAfterEnv peuvent désormais exporter une fonction asynchrone ou utiliser await au niveau supérieur, à l'instar de setupFiles.

Et bien plus encore…

Consultez le CHANGELOG complet pour découvrir toutes les modifications, améliorations et nouvelles fonctionnalités.

Problèmes connus

jsdom a évolué pour mieux respecter les spécifications. Cela peut impacter certains cas d'usage, notamment le mock de window.location dans les tests. Jest fournit désormais @jest/environment-jsdom-abstract pour faciliter la création d'environnements de test personnalisés basés sur jsdom. Pour appliquer un correctif ponctuel à jsdom, utilisez ce patch jsdom dans votre projet. À terme, nous envisageons une alternative à jsdom mieux adaptée aux tests.

Perspectives futures

Jest demeure le framework de test JavaScript le plus populaire depuis dix ans, utilisé par des millions de développeurs sur des projets allant des petites librairies aux plus grosses bases de code mondiales. Cette longévité a engendré une dette technique : certaines fonctionnalités peu utilisées coexistent avec des limitations délibérées pour éviter les ruptures. Certaines capacités devraient être externalisées du cœur de Jest, tandis que d'autres encouragent des anti-patterns de test. Combiné aux départs de contributeurs clés, cela a ralenti le rythme des versions. Notre feuille de route :

  • Performance/Dette technique : Alléger le cœur de Jest pour plus de performance. Supprimer les fonctionnalités marginales et concentrer l'effort sur l'essentiel.

  • Cycles de publication réguliers : Adopter un calendrier de versions majeures plus prévisible avec une politique claire de dépréciation.

  • Transparence : Développer en open source avec une feuille de route publique. Faciliter l'intégration de nouveaux contributeurs.

  • Soyez Audacieux : En tant qu'équipe Jest, nous devons faire preuve de plus d'audace. Plusieurs éléments freinent Jest et l'empêchent d'atteindre son plein potentiel. Il est temps de passer à l'action.

La bonne nouvelle, c'est que Jest a toujours été bien conçu pour respecter ces principes, depuis que nous avons construit le framework comme un système modulaire avec une séparation claire des responsabilités. Maintenant, il est temps d'exécuter ces plans. Plus de détails à venir bientôt !

Remerciements

Cette version n'aurait pas été possible sans le travail acharné de notre communauté. Merci.

@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 merci tout particulier à toutes les personnes qui ont fait leur première contribution à Jest dans cette version. Merci de rendre Jest meilleur pour tous !

@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