Guide de migration
Migration vers Vitest 3.0
Options de test en tant que troisième argument
Vitest 3.0 émet un avertissement si vous passez un objet comme troisième argument aux fonctions test
ou describe
:
test('validation works', () => {
// ...
}, { retry: 3 });
test('validation works', { retry: 3 }, () => {
// ...
});
La prochaine version majeure générera une erreur si le troisième argument est un objet. Notez que le délai d'attente numérique n'est pas déprécié :
test('validation works', () => {
// ...
}, 1000); // Ok ✅
browser.name
et browser.providerOptions
sont dépréciés
Les options browser.name
et browser.providerOptions
seront supprimées dans Vitest 4. Utilisez plutôt la nouvelle option browser.instances
:
export default defineConfig({
test: {
browser: {
name: 'chromium',
providerOptions: {
launch: { devtools: true },
},
instances: [
{
browser: 'chromium',
launch: { devtools: true },
},
],
},
},
})
Avec le nouveau champ browser.instances
, vous pouvez également spécifier plusieurs configurations de navigateur.
spy.mockReset
restaure maintenant l'implémentation originale
Il n'existait pas de méthode efficace pour réinitialiser l'espion à son implémentation originale sans le réappliquer. Désormais, spy.mockReset
réinitialisera la fonction d'implémentation à l'originale au lieu d'une fausse fonction vide.
const foo = {
bar: () => 'Hello, world!',
};
vi.spyOn(foo, 'bar').mockImplementation(() => 'Hello, mock!');
foo.bar(); // 'Hello, mock!'
foo.bar.mockReset();
foo.bar(); // undefined
foo.bar(); // 'Hello, world!'
vi.spyOn
réutilise le mock si la méthode est déjà mockée
Auparavant, Vitest assignait toujours un nouvel espion lors de l'espionnage d'un objet. Cela entraînait des erreurs avec mockRestore
, car il restaurait l'espion précédent au lieu de la fonction originale :
vi.spyOn(fooService, 'foo').mockImplementation(() => 'bar');
vi.spyOn(fooService, 'foo').mockImplementation(() => 'bar');
vi.restoreAllMocks();
vi.isMockFunction(fooService.foo); // true
vi.isMockFunction(fooService.foo); // false
Valeurs par défaut des simulateurs de temps
Vitest ne fournit plus d'options fakeTimers.toFake
par défaut. Désormais, Vitest simulera toute API liée aux temporisateurs si elle est disponible (sauf nextTick
). Plus précisément, performance.now()
est maintenant mocké lorsque vi.useFakeTimers
est appelé.
vi.useFakeTimers();
performance.now(); // original
performance.now(); // fake
Vous pouvez revenir au comportement précédent en spécifiant les temporisateurs lors de l'appel de vi.useFakeTimers
ou globalement dans la configuration :
export default defineConfig({
test: {
fakeTimers: {
toFake: [
'setTimeout',
'clearTimeout',
'setInterval',
'clearInterval',
'setImmediate',
'clearImmediate',
'Date',
]
},
},
})
Égalité d'erreur plus stricte
Vitest vérifie maintenant plus de propriétés lors de la comparaison d'erreurs via toEqual
ou toThrowError
. Vitest compare maintenant name
, message
, cause
et AggregateError.errors
. Pour Error.cause
, la comparaison s'effectue de manière asymétrique :
expect(new Error('hi', { cause: 'x' })).toEqual(new Error('hi')); // ✅
expect(new Error('hi')).toEqual(new Error('hi', { cause: 'x' })); // ❌
Outre la vérification de propriétés supplémentaires, Vitest compare désormais les prototypes d'erreur. Par exemple, si une TypeError
a été levée, la vérification d'égalité doit faire référence à TypeError
, et non à Error
:
expect(() => {
throw new TypeError('type error');
})
.toThrowError(new Error('type error'))
.toThrowError(new TypeError('type error'));
Voir la PR pour plus de détails : #5876.
L'exportation de condition module
n'est pas résolue par défaut sur Vite 6
Vite 6 offre des options resolve.conditions
plus flexibles, et Vitest est configuré pour exclure l'exportation conditionnelle module
par défaut. Voir aussi le guide de migration de Vite 6 pour le détail des changements côté Vite.
Le type Custom
est déprécié API
Le type Custom
est maintenant un alias pour le type Test
. Notez que Vitest a mis à jour les types publics en 2.1 et a changé les noms exportés en RunnerCustomCase
et RunnerTestCase
:
import {
RunnerCustomCase,
RunnerTestCase,
} from 'vitest';
Si vous utilisez getCurrentSuite().custom()
, le type
de la tâche retournée est maintenant égal à 'test'
. Le type Custom
sera supprimé dans Vitest 4.
Le type WorkspaceSpec
n'est plus utilisé API
Dans l'API publique, ce type était précédemment utilisé dans les séquenceurs personnalisés. Veuillez migrer vers TestSpecification
à la place.
onTestFinished
et onTestFailed
reçoivent maintenant un contexte
Les hooks onTestFinished
et onTestFailed
recevaient auparavant un résultat de test en tant que premier argument. Maintenant, ils reçoivent un contexte de test, comme beforeEach
et afterEach
.
Modifications de l'API Snapshot API
L'API publique Snapshot dans @vitest/snapshot
a été modifiée pour prendre en charge plusieurs états au cours d'une seule exécution. Voir la PR pour plus de détails : #6817
Notez que ces modifications n'affectent que les développeurs utilisant directement l'API Snapshot. L'API .toMatchSnapshot
n'a subi aucune modification.
Modifications de la signature de type resolveConfig
API
La fonction resolveConfig
est désormais plus utile. Au lieu d'accepter une configuration Vite déjà résolue, elle prend maintenant en charge une configuration utilisateur et retourne la configuration résolue.
Cette fonction n'est pas utilisée en interne et est exposée exclusivement en tant qu'API publique.
Types vitest/reporters
nettoyés API
Le point d'entrée vitest/reporters
n'exporte désormais que les implémentations de reporters et les types d'options. Si vous avez besoin d'accéder à TestCase
/TestSuite
et à d'autres types liés aux tâches, importez-les en plus depuis vitest/node
.
La couverture ignore les fichiers de test même lorsque coverage.excludes
est modifié.
Il n'est plus possible d'inclure les fichiers de test dans le rapport de couverture en modifiant coverage.excludes
. Les fichiers de test sont désormais toujours exclus.
Migration vers Vitest 2.0
Le pool par défaut est forks
Vitest 2.0 modifie la configuration par défaut de pool
en 'forks'
pour une meilleure stabilité. Vous pouvez lire la motivation complète dans la PR.
Si vous avez utilisé poolOptions
sans spécifier de pool
, vous devrez peut-être mettre à jour votre configuration :
export default defineConfig({
test: {
poolOptions: {
threads: {
singleThread: true,
},
forks: {
singleFork: true,
},
}
}
})
Les hooks s'exécutent en pile
Avant Vitest 2.0, tous les hooks s'exécutaient en parallèle. Avec la version 2.0, tous les hooks s'exécutent en série. De plus, les hooks afterAll
/afterEach
s'exécutent dans l'ordre inverse.
Pour revenir à l'exécution parallèle des hooks, changez sequence.hooks
en 'parallel'
:
export default defineConfig({
test: {
sequence: {
hooks: 'parallel',
},
},
})
suite.concurrent
exécute tous les tests simultanément
Auparavant, spécifier concurrent
sur une suite regroupait les tests concurrents par suite, les exécutant séquentiellement. Désormais, conformément au comportement de Jest, tous les tests s'exécutent simultanément (dans la limite de maxConcurrency
).
coverage.ignoreEmptyLines
de la couverture V8 est activé par défaut
La valeur par défaut de coverage.ignoreEmptyLines
est maintenant true
. Ce changement significatif peut affecter les rapports de couverture de code, nécessitant des ajustements des seuils de couverture pour certains projets. Cette modification n'affecte que le paramètre par défaut lorsque coverage.provider
est 'v8'
.
Suppression de l'option watchExclude
Vitest utilise le système de surveillance de fichiers (watcher) de Vite. Excluez les fichiers ou répertoires en les ajoutant à server.watch.ignored
:
export default defineConfig({
server: {
watch: {
ignored: ['!node_modules/examplejs']
}
}
})
--segfault-retry
supprimé
Avec les modifications apportées au pool par défaut, cette option n'est plus nécessaire. Si vous rencontrez des erreurs de segmentation (segfault), essayez de passer au pool 'forks'
. Si le problème persiste, veuillez ouvrir un nouveau problème avec une reproduction.
Tâche vide dans les tâches de suite supprimée
Ceci est une modification de l'API de tâche avancée. Auparavant, parcourir .suite
menait finalement à la suite interne vide qui était utilisée à la place d'une tâche de fichier.
Cela rend .suite
facultatif ; si la tâche est définie au niveau supérieur, elle ne contiendra pas de suite. Vous pouvez vous rabattre sur la propriété .file
qui est maintenant présente sur toutes les tâches (y compris la tâche de fichier elle-même, veillez donc à ne pas tomber dans une récursion infinie).
Ce changement supprime également le fichier de expect.getState().currentTestName
et rend expect.getState().testPath
obligatoire.
task.meta
est ajouté au rapporteur JSON
Le rapporteur JSON affiche désormais task.meta
pour chaque résultat d'assertion.
Types génériques simplifiés des fonctions mock (par exemple vi.fn<T>
, Mock<T>
)
Auparavant, vi.fn<TArgs, TReturn>
acceptait deux types génériques distincts pour les arguments et la valeur de retour. Cela a été modifié pour accepter directement un type de fonction vi.fn<T>
afin de simplifier l'utilisation.
import { vi } from 'vitest';
import type { Mock } from 'vitest';
const add = (x: number, y: number): number => x + y;
// using vi.fn<T>
const mockAdd = vi.fn<Parameters<typeof add>, ReturnType<typeof add>>();
const mockAdd = vi.fn<typeof add>();
// using Mock<T>
const mockAdd: Mock<Parameters<typeof add>, ReturnType<typeof add>> = vi.fn();
const mockAdd: Mock<typeof add> = vi.fn();
Accès aux mock.results
résolus
Auparavant, Vitest résolvait les valeurs de mock.results
si la fonction retournait une Promise. Désormais, il existe une propriété mock.settledResults
distincte qui n'est renseignée que lorsque la Promise retournée est résolue ou rejetée.
const fn = vi.fn().mockResolvedValueOnce('result');
await fn();
const result = fn.mock.results[0]; // 'result'
const result = fn.mock.results[0]; // 'Promise<result>'
const settledResult = fn.mock.settledResults[0]; // 'result'
Avec ce changement, nous introduisons également de nouveaux matchers toHaveResolved*
similaires à toHaveReturned
pour faciliter la migration si vous utilisiez toHaveReturned
auparavant :
const fn = vi.fn().mockResolvedValueOnce('result');
await fn();
expect(fn).toHaveReturned('result');
expect(fn).toHaveResolved('result');
Mode Navigateur
Le mode navigateur de Vitest a connu de nombreuses évolutions durant le cycle bêta. Vous pouvez en savoir plus sur notre philosophie concernant le mode navigateur sur la page de discussion GitHub.
La plupart des changements étaient additifs, mais il y a eu quelques petits changements cassants :
- Le fournisseur
none
a été renommé enpreview
#5842 - Le fournisseur
preview
est maintenant le défaut #5842 indexScripts
a été renommé enorchestratorScripts
#5842
Options dépréciées supprimées
Certaines options dépréciées ont été supprimées :
- commande
vitest typecheck
- utilisezvitest --typecheck
à la place - variables d'environnement
VITEST_JUNIT_CLASSNAME
etVITEST_JUNIT_SUITE_NAME
(utilisez les options du rapporteur à la place) - vérification de la couverture
c8
(utilisez coverage-v8 à la place) - exportation de
SnapshotEnvironment
depuisvitest
- importez-le depuisvitest/snapshot
à la place SpyInstance
est supprimé au profit deMockInstance
Migration vers Vitest 1.0
Exigences minimales
Vitest 1.0 nécessite Vite 5.0 et Node.js 18 ou plus.
Tous les sous-packages @vitest/*
nécessitent la version 1.0 de Vitest.
Mise à jour des instantanés #3961
Les guillemets dans les instantanés ne sont plus échappés, et tous les instantanés utilisent des apostrophes inversées (`) même si la chaîne est une seule ligne.
- Les guillemets ne sont plus échappés :
expect({ foo: 'bar' }).toMatchInlineSnapshot(`
Object {
- \\"foo\\": \\"bar\\",
+ "foo": "bar",
}
`)
- Les instantanés d'une ligne utilisent maintenant les guillemets "`" au lieu de ':' :
- expect('some string').toMatchInlineSnapshot('"some string"')
+ expect('some string').toMatchInlineSnapshot(`"some string"`)
Il y a également eu des modifications au package @vitest/snapshot
. Si vous ne l'utilisez pas directement, vous n'avez rien à changer.
- Vous n'avez plus besoin d'étendre
SnapshotClient
juste pour surcharger la méthodeequalityCheck
: il suffit de la passer en tant queisEqual
lors de l'initialisation d'une instance. client.setTest
a été renommé enclient.startCurrentRun
client.resetCurrent
a été renommé enclient.finishCurrentRun
Les pools sont standardisés #4172
Nous avons supprimé de nombreuses options de configuration pour faciliter la configuration du runner selon vos besoins. Veuillez consulter les exemples de migration si vous utilisez --threads
ou d'autres options similaires.
--threads
est maintenant--pool=threads
--no-threads
est maintenant--pool=forks
--single-thread
est maintenant--poolOptions.threads.singleThread
--experimental-vm-threads
est maintenant--pool=vmThreads
--experimental-vm-worker-memory-limit
est maintenant--poolOptions.vmThreads.memoryLimit
--isolate
est maintenant--poolOptions.<pool-name>.isolate
etbrowser.isolate
test.maxThreads
est maintenanttest.poolOptions.<pool-name>.maxThreads
test.minThreads
est maintenanttest.poolOptions.<pool-name>.minThreads
test.useAtomics
est maintenanttest.poolOptions.<pool-name>.useAtomics
test.poolMatchGlobs.child_process
est maintenanttest.poolMatchGlobs.forks
test.poolMatchGlobs.experimentalVmThreads
est maintenanttest.poolMatchGlobs.vmThreads
{
scripts: {
- "test": "vitest --no-threads"
// For identical behaviour:
+ "test": "vitest --pool forks --poolOptions.forks.singleFork"
// Or multi parallel forks:
+ "test": "vitest --pool forks"
}
}
{
scripts: {
- "test": "vitest --experimental-vm-threads"
+ "test": "vitest --pool vmThreads"
}
}
{
scripts: {
- "test": "vitest --isolate false"
+ "test": "vitest --poolOptions.threads.isolate false"
}
}
{
scripts: {
- "test": "vitest --no-threads --isolate false"
+ "test": "vitest --pool forks --poolOptions.forks.isolate false"
}
}
Modifications de la couverture #4265, #4442
L'option coverage.all
est maintenant activée par défaut. Cela signifie que tous les fichiers de projet correspondant au motif coverage.include
seront traités même s'ils ne sont pas exécutés.
La forme de l'API des seuils de couverture a été modifiée, et elle prend désormais en charge la spécification de seuils pour des fichiers spécifiques à l'aide de motifs génériques (glob) :
export default defineConfig({
test: {
coverage: {
- perFile: true,
- thresholdAutoUpdate: true,
- 100: true,
- lines: 100,
- functions: 100,
- branches: 100,
- statements: 100,
+ thresholds: {
+ perFile: true,
+ autoUpdate: true,
+ 100: true,
+ lines: 100,
+ functions: 100,
+ branches: 100,
+ statements: 100,
+ }
}
}
})
Types de mock #4400
Quelques types ont été supprimés au profit de la convention de nommage "Mock" de style Jest.
- import { EnhancedSpy, SpyInstance } from 'vitest'
+ import { MockInstance } from 'vitest'
WARNING
SpyInstance
est déprécié au profit de MockInstance
et sera supprimé dans la prochaine version majeure.
Mocks de temporisateurs #3925
vi.useFakeTimers()
ne simule plus automatiquement process.nextTick
. Il est toujours possible de simuler process.nextTick
en le spécifiant explicitement avec vi.useFakeTimers({ toFake: ['nextTick'] })
.
Cependant, la simulation de process.nextTick
n'est pas possible lors de l'utilisation de --pool=forks
. Utilisez une option --pool
différente si vous avez besoin de la simulation de process.nextTick
.
Migration depuis Jest
Vitest a été conçu avec une API compatible avec Jest, afin de rendre la migration depuis Jest aussi simple que possible. Malgré ces efforts, vous pourriez toujours rencontrer les différences suivantes :
Globals par défaut
Jest a son API globale activée par défaut, ce qui n'est pas le cas de Vitest. Vous pouvez soit activer les globales via le paramètre de configuration globals
, soit mettre à jour votre code pour utiliser les importations du module vitest
à la place.
Si vous décidez de maintenir les globales désactivées, sachez que les bibliothèques courantes comme testing-library
n'exécuteront pas le nettoyage automatique du DOM.
spy.mockReset
mockReset
de Jest (mockReset
) remplace l'implémentation du mock par une fonction vide qui retourne undefined
.
mockReset
de Vitest (mockReset
) réinitialise l'implémentation du mock à son original. Autrement dit, réinitialiser un mock créé par vi.fn(impl)
réinitialisera l'implémentation du mock à impl
.
Mocks de modules
Lors de la simulation d'un module dans Jest, la valeur de retour de la fonction usine est l'exportation par défaut. Dans Vitest, la fonction usine doit retourner un objet avec chaque exportation explicitement définie. Par exemple, le jest.mock
suivant devrait être mis à jour comme suit :
jest.mock('./some-path', () => 'hello')
vi.mock('./some-path', () => ({
default: 'hello',
}))
Pour plus de détails, veuillez vous référer à la section API vi.mock
.
Comportement d'auto-mocking
Contrairement à Jest, les modules simulés dans <root>/__mocks__
ne sont pas chargés à moins que vi.mock()
ne soit appelé. Si vous avez besoin qu'ils soient simulés dans chaque test, comme dans Jest, vous pouvez les simuler à l'intérieur de setupFiles
.
Importation de l'original d'un package mocké
Si vous simulez partiellement un package, vous avez peut-être utilisé auparavant la fonction requireActual
de Jest. Dans Vitest, vous devriez remplacer ces appels par vi.importActual
.
const { cloneDeep } = jest.requireActual('lodash/cloneDeep');
const { cloneDeep } = await vi.importActual('lodash/cloneDeep');
Étendre le mocking aux bibliothèques externes
Contrairement à Jest qui le fait par défaut, lorsque vous simulez un module et que vous souhaitez étendre cette simulation à d'autres bibliothèques externes qui utilisent le même module, vous devez explicitement spécifier la bibliothèque tierce à simuler. Cela permet à la bibliothèque externe d'être traitée comme faisant partie de votre code source, en utilisant server.deps.inline.
server.deps.inline: ["lib-name"]
expect.getState().currentTestName
Les noms de test
de Vitest sont reliés par un symbole >
pour faciliter la distinction entre les tests et les suites, tandis que Jest utilise un espace vide ().
- `${describeTitle} ${testTitle}`
+ `${describeTitle} > ${testTitle}`
Environnements
Tout comme Jest, Vitest définit NODE_ENV
à test
s'il n'était pas déjà configuré. Vitest dispose également d'un équivalent pour JEST_WORKER_ID
appelé VITEST_POOL_ID
(toujours inférieur ou égal à maxThreads
) ; si vous l'utilisez, n'oubliez pas de le renommer. Vitest expose également VITEST_WORKER_ID
, un ID unique pour chaque worker – ce nombre n'est pas affecté par maxThreads
et augmentera avec chaque worker créé.
Propriété de remplacement
Pour modifier un objet, vous utiliserez l'API replaceProperty dans Jest. Dans Vitest, vous pouvez obtenir le même résultat en utilisant vi.stubEnv
ou vi.spyOn
.
Rappel Done
À partir de Vitest v0.10.0, le style de déclaration des tests basé sur les callbacks est déprécié. Vous pouvez les réécrire pour utiliser des fonctions async
/await
, ou utiliser des Promesses pour reproduire le comportement des callbacks.
it('should work', (done) => {
it('should work', () => new Promise(done => {
// ...
done()
})
}))
Hooks
Les hooks beforeAll
/beforeEach
peuvent retourner une fonction de nettoyage dans Vitest. Par conséquent, vous devrez peut-être réécrire vos déclarations de hooks s'ils retournent une valeur autre que undefined
ou null
:
beforeEach(() => setActivePinia(createTestingPinia()))
beforeEach(() => { setActivePinia(createTestingPinia()) })
Dans Jest, les hooks sont appelés séquentiellement (l'un après l'autre). Par défaut, Vitest exécute les hooks en parallèle. Pour utiliser le comportement de Jest, mettez à jour l'option sequence.hooks
:
export default defineConfig({
test: {
sequence: {
hooks: 'list',
}
}
})
Types
Vitest n'a pas d'équivalent à l'espace de noms jest
, vous devrez donc importer les types directement à partir de vitest
:
let fn: jest.Mock<(name: string) => number>;
import type { Mock } from 'vitest';
let fn: Mock<(name: string) => number>;
Temporisateurs
Vitest ne prend pas en charge les temporisateurs hérités de Jest.
Timeout
Si vous utilisiez jest.setTimeout
, vous devrez le migrer vers vi.setConfig
:
jest.setTimeout(5_000);
vi.setConfig({ testTimeout: 5_000 });
Instantanés Vue
Ce n'est pas une fonctionnalité spécifique à Jest, mais si vous utilisiez auparavant Jest avec la configuration prédéfinie (preset) de vue-cli, vous devrez installer le package jest-serializer-vue
et l'utiliser dans setupFiles :
import { defineConfig } from 'vite';
export default defineConfig({
test: {
setupFiles: ['./tests/unit/setup.js'],
},
});
import vueSnapshotSerializer from 'jest-serializer-vue';
expect.addSnapshotSerializer(vueSnapshotSerializer);
Sinon, vos instantanés contiendront de nombreux caractères "
échappés.