12k
All articles

Ce qui change dans Vitest 5

Découvrez les changements de Vitest 5 : gains de performance, changements incompatibles, nouveaux paramètres par défaut, chemins des rapports et étapes pour migrer vos tests et CI.

OpenReplay Team
OpenReplay Team
Ce qui change dans Vitest 5

Vitest 5.0, publiée le 3 septembre 2026, est une version majeure axée sur les performances. Elle nécessite Node.js 22.12.0+ et Vite 6.4.0+, active par défaut l’effacement de l’historique des mocks, fait échouer les assertions asynchrones non attendues (sans await) et regroupe la sortie des reporters dans un répertoire unique, .vitest/.

La plupart des échecs qui surviennent après la mise à niveau se corrigent facilement. Les plus délicats concernent les tests qui passent en local sous Vitest 4, mais échouent en CI avec une erreur qui n’en explique pas la cause.

Cet article classe les notes de version de la v5.0.0 par ordre d’impact. Il présente d’abord ce qui est réellement plus rapide. Il aborde ensuite les changements qui imposent de modifier le code, puis ceux qui déplacent discrètement des chemins ou modifient les règles de correspondance. Il se termine par une checklist de mise à niveau et un verdict.

Points clés

  • Vitest 5.0 nécessite Node.js 22.12.0 ou une version ultérieure, ainsi que Vite 6.4.0 ou une version ultérieure.
  • Selon les benchmarks de l’équipe Vitest, la plupart des configurations testées gagnent de 8 à 25 % en rapidité, et jusqu’à 53 % pour certaines configurations utilisant les pools VM. Les configurations dominées par la mise en place de l’environnement ne changent presque pas.
  • clearMocks vaut désormais true par défaut. Une assertion sur un historique d’appels enregistré dans un fichier de setup, un hook beforeAll ou un test précédent voit donc désormais zéro appel.
  • Par défaut, les rapports blob, les pièces jointes et les sorties des reporters JSON, JUnit et HTML sont désormais écrits sous .vitest/. Les étapes CI qui gèrent les artefacts doivent donc être mises à jour.
  • toThrow('') correspond désormais à n’importe quelle erreur levée. Une assertion destinée à vérifier un message vide nécessite donc un motif explicite.

Pourquoi Vitest 5 est-il plus rapide ?

D’après l’annonce de Vitest 5, la plupart des configurations testées dans les benchmarks de l’équipe Vitest gagnent de 8 à 25 % en rapidité. Les pools VM en profitent le plus, avec jusqu’à 53 % de gain dans certaines configurations.

Toutes les configurations ne s’accélèrent pas pour autant. Les exécutions où la création de l’environnement de test représente l’essentiel du temps restent à moins de 3 % de Vitest 4.1. C’est le cas, par exemple, de forks avec jsdom et l’isolation activée.

Ces chiffres proviennent de vitest-dev/benchmarks, où l’équipe a généré des applications de test de tailles variées, d’un petit package de 5 fichiers jusqu’à un monolithe de 1 280 modules. Dans le billet de lancement de VoidZero, ces résultats sont arrondis à « pools VM jusqu’à 53 % plus rapides, gain d’environ 18 % sur l’ensemble, Browser Mode compris ».

Selon les notes de version, quatre changements expliquent l’essentiel de ce gain :

  • Serveur Vite partagé. Les projets inline partagent désormais un seul serveur Vite, au lieu d’en démarrer chacun un.
  • fsModuleCache. Cette option est désormais de premier niveau. Elle enregistre les modules transformés sur le disque, ce qui permet à une nouvelle exécution ou à un autre processus Vitest d’éviter ce travail.
  • Moins d’allers-retours. Les modules déjà transformés parviennent désormais à un worker en un seul échange avec le processus principal.
  • Réutilisation dans les pools VM. Les pools vmThreads et vmForks partagent le code compilé entre les contextes et chargent le graphe de modules à l’avance.

Vitest prend également en charge le cache de compilation sur disque de Node, mais son activation reste facultative.

Quels changements de Vitest 5 nécessitent de modifier le code ?

Six changements de Vitest 5 provoquent un échec de test ou une erreur de configuration dès la première exécution. Le guide de migration détaille chacun d’eux.

ChangementSymptôme à la première exécutionCorrectif
clearMocks: true par défautLes assertions sur le nombre d’appels voient 0Déclencher les appels dans le test qui fait l’assertion, ou définir clearMocks: false
Assertion asynchrone sans awaitLe test échoueAjouter await
Appel vi hoisté hors du niveau supérieurLève une erreurLe déplacer au niveau du module
Suppression de sequentialAPI supprimée{ concurrent: false }
Plus de recherche de config dans les dossiers parentsConfiguration introuvableAjouter une config dans le dossier du package
API de bench réécriteL’ancien code de bench ne fonctionne plusMigrer vers le modèle à base de fixtures

Effacement et hoisting des mocks

Dans Vitest 5, clearMocks vaut true par défaut, si bien que vi.clearAllMocks() s’exécute avant chaque test. L’historique des appels enregistré dans un fichier de setup, un hook beforeAll ou un test précédent est effacé avant que le test suivant ne fasse son assertion. Les implémentations des mocks, en revanche, sont conservées.

// Vitest 5.0.x
const track = vi.fn()
beforeAll(() => initAnalytics(track))

it('tracks once on init', () => {
  expect(track).toHaveBeenCalledTimes(1) // now receives 0 calls
})

Le correctif consiste à déclencher l’appel dans le test qui fait l’assertion. Pendant l’audit de votre suite, vous pouvez définir clearMocks: false dans la section test de la configuration pour rétablir l’ancien comportement.

Un appel à vi.mock, ou à tout autre appel vi hoisté, situé ailleurs qu’au niveau supérieur d’un fichier lève désormais une erreur. Vitest remontait de toute façon ces appels en tête du module : le code placé dans un bloc describe ne s’exécutait donc jamais à l’endroit où il était écrit.

// Vitest 5.0.x: throws
describe('UserCard', () => {
  const fetchUser = vi.fn()
  vi.mock('./api', () => ({ fetchUser }))
})

// Vitest 5.0.x: works
const { fetchUser } = vi.hoisted(() => ({ fetchUser: vi.fn() }))
vi.mock('./api', () => ({ fetchUser }))

describe('UserCard', () => {
  it('renders the user', async () => {
    fetchUser.mockResolvedValue({ name: 'Ada' })
    // mount and assert
  })
})

Si vos suites Vue mockent leur couche API, le même principe du niveau supérieur s’applique pour mocker les appels API dans les tests Vue avec Vitest.

Assertions sans await

Un test qui laisse une assertion asynchrone sans await échoue désormais. Il suffit d’oublier await devant expect(...).resolves ou .rejects pour que le test passe au rouge.

// Vitest 5.0.x
test('loads config', async () => {
  expect(loadConfig()).resolves.toEqual({ ok: true }) // fails
  await expect(loadConfig()).resolves.toEqual({ ok: true }) // passes
})

La commande grep suivante liste les occurrences suspectes. Vous devez toutefois vérifier, pour chaque résultat, la présence d’un await en tête d’expression :

grep -rnE "expect\(.*\)\.(resolves|rejects)" src/ --include='*.test.*' --include='*.spec.*'

Concurrence, recherche de configuration et bench

Les options sequential des tests et des suites ont été supprimées. Pour désactiver la concurrence, utilisez test('example', { concurrent: false }, ...) ou describe('suite', { concurrent: false }, ...).

Vitest 5 ne recherche plus de fichier de configuration dans les dossiers parents du dossier courant. Si vous lancez vitest depuis un sous-dossier de package, ce dossier doit disposer de sa propre configuration.

L’API de bench a été réécrite. Vous n’importez plus bench en tête de fichier : vous le récupérez depuis le contexte de test, à l’intérieur d’un appel test() ordinaire dans un fichier de benchmark.

Les notes de version mentionnent d’autres changements cassants, à vérifier selon votre situation :

  • expect.poll échoue désormais lorsqu’il atteint son délai d’expiration.
  • Les points d’entrée dépréciés ont été supprimés.
  • @vitest/runner est déprécié. Par ailleurs, vitest ne dépend plus de @vitest/expect, car le code des assertions est désormais intégré directement dans vitest.
  • Le provider @vitest/browser-webdriverio a été transféré vers l’organisation vitest-community et est désormais maintenu par la communauté.
  • workerId commence désormais à 1.

toThrow('') correspond désormais à n’importe quelle erreur levée. Si vous souhaitez réellement vérifier un message vide, passez plutôt une expression régulière telle que /^$/.

Qu’est-ce qui change silencieusement dans Vitest 5 ?

Six changements de Vitest 5 ne lèvent aucune erreur. Ils modifient un chemin, un filtre ou un résultat de correspondance à l’insu de votre configuration existante.

  • Chemins de sortie. Par défaut, les rapports blob et --merge-reports utilisent .vitest/blob/. Les pièces jointes passent de .vitest-attachements/ à .vitest/attachments/. Les fichiers des reporters JSON, JUnit et HTML sont eux aussi écrits par défaut dans .vitest.
  • Filtres -t. Le séparateur des filtres par nom de test est désormais >. Vérifiez les scripts CI qui filtrent par chemin de suite.
  • Locators du navigateur. locators.exact est désormais activé par défaut en Browser Mode.
  • Correspondance de texte. toHaveTextContent est désormais strict. toMatchTextContent constitue la nouvelle alternative.
  • Globs de couverture. Les motifs include et exclude sont désormais comparés au chemin de chaque fichier relatif à la racine du projet, et un motif sans caractère générique désigne un dossier entier. L’ensemble des fichiers pris en compte dans la couverture peut donc changer : vérifiez vos seuils après la première exécution.
  • Projets inline. Les projets inline héritent désormais de la configuration racine, comme si extends: true était défini.

Voici comment évolue une étape typique de gestion des artefacts :

-          path: .vitest-attachements/
+          path: .vitest/attachments/
+          # sharded runs: upload .vitest/blob/ for --merge-reports

Nouveautés de Vitest 5 à connaître

vi.when permet d’attribuer à un spy un résultat différent pour chaque jeu d’arguments. calledWith accepte les matchers asymétriques, et les appels dont les arguments ne correspondent à aucune règle sont transmis à l’implémentation d’origine.

// Vitest 5.0.x
vi.when(getUser).calledWith(1).thenResolve({ id: 1, name: 'Ada' })

En Browser Mode, définir test.browser.traceView: true active la vue de trace. Chaque interaction, assertion et appel à page.mark est enregistré sous forme de snapshot du DOM, ce qui permet de rejouer le test étape par étape dans l’interface.

Les projets imbriqués sont désormais pris en charge, ce qui aide les monorepos à regrouper les projets apparentés.

Checklist de mise à niveau vers Vitest 5

  1. Passez vos environnements CI et locaux à Node.js 22.12.0+ et Vite 6.4.0+.
  2. Lancez la commande grep ci-dessus et ajoutez await partout où il manque.
  3. Déplacez chaque appel à vi.mock et vi.hoisted au niveau supérieur de son fichier.
  4. Remplacez sequential par { concurrent: false }, et ajoutez une configuration dans les dossiers de packages qui s’appuyaient sur une configuration parente.
  5. Exécutez la suite. Si des assertions sur le nombre d’appels échouent, corrigez-les, ou définissez clearMocks: false en guise de solution transitoire.
  6. Mettez à jour les chemins d’artefacts CI vers .vitest/, puis revoyez vos filtres -t et vos seuils de couverture.

Faut-il passer à Vitest 5 maintenant ou attendre ?

Passez à Vitest 5 dès ce sprint si votre CI tourne déjà sous Node.js 22.12.0+ et Vite 6.4.0+. La plupart des modifications nécessaires sont mécaniques.

L’exception concerne les suites dont les assertions portent sur un historique d’appels de mocks conservé d’un test à l’autre, qu’il provienne de fichiers de setup, de hooks beforeAll ou d’un test qui dépend des appels d’un autre. Ces échecs ne donnent aucun indice sur leur cause : auditez d’abord ces assertions, puis effectuez la mise à niveau.

Les suites de composants doivent également réexécuter leurs assertions sur le texte et les locators. Les exemples de l’article tester des composants Svelte 5 avec Vitest montrent où ces assertions apparaissent généralement.

Vitest 5 est plus rapide, et l’essentiel de ce qu’il casse relève d’un code de test qui était déjà incorrect. Commencez sur une branche par la commande grep et le déplacement des vi.mock, vérifiez les chemins d’artefacts CI, puis laissez la première exécution en CI vous indiquer le reste.

FAQ

Vitest 5 active-t-il aussi mockReset ou restoreMocks par défaut ?

Non. Le guide de migration de Vitest 5 ne modifie la valeur par défaut que pour clearMocks. clearMocks appelle vi.clearAllMocks() avant chaque test et réinitialise mock.calls, mock.instances, mock.contexts et mock.results, tout en conservant les implémentations. mockReset va plus loin : il efface l'historique et rétablit l'implémentation d'origine de chaque mock, si bien qu'un mock créé avec vi.fn(impl) revient à impl. restoreMocks, lui, rétablit les implémentations d'origine des spies créés avec vi.spyOn.

Pourquoi mon filtre -t sélectionne-t-il moins de tests depuis la mise à niveau vers Vitest 5 ?

Dans Vitest 5, testNamePattern (le flag -t) est comparé au nom complet du test, construit en insérant ' > ' entre chaque nom de suite et le nom du test. Il s'agit du même texte que celui affiché dans la sortie du reporter. Vitest 4 utilisait une simple espace entre les parties, comme Jest. Un motif ne casse que s'il chevauche deux parties du nom. Pour le corriger, ciblez une seule partie, par exemple -t adds, ou placez un caractère générique entre les parties, par exemple -t 'math.*adds'.

Pourquoi Vitest 5 ne parvient-il plus à résoudre vite après une mise à niveau avec Yarn ?

Dans Vitest 5, vite n'est plus une dépendance directe mais une peer dependency obligatoire. Vitest s'exécute donc avec la version de Vite installée dans votre projet. npm, pnpm, Bun et Deno ajoutent automatiquement les peer dependencies, mais Yarn vous laisse vous en charger. Ajoutez vite en version 6.4.0 ou ultérieure à votre package.json, puis réinstallez : Vitest pourra de nouveau le résoudre.

Comment fusionner les rapports de tests répartis en shards dans Vitest 5 ?

Exécutez chaque shard avec le reporter blob, par exemple vitest run --reporter=blob --shard=1/3 sur la première machine. Par défaut, chaque shard écrit ses résultats dans .vitest/blob/, et le flag --outputFile.blob permet de modifier cet emplacement. Copiez le répertoire de chaque machine dans un job final unique, puis lancez vitest --merge-reports. Si vos tests enregistrent des pièces jointes sous forme de fichiers, transférez également le dossier des pièces jointes dans le job de fusion.

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.