Guida alla Migrazione
Migrazione a Vitest 2.0
Il Pool Predefinito è forks
Vitest 2.0 modifica la configurazione predefinita per pool in 'forks' per migliorare la stabilità. Puoi leggere la motivazione completa nella PR.
Se hai utilizzato poolOptions senza specificare un pool, potrebbe essere necessario aggiornare la configurazione:
export default defineConfig({
test: {
poolOptions: {
threads: {
singleThread: true,
},
forks: {
singleFork: true,
},
}
}
});Gli Hook Vengono Eseguiti in Sequenza
Prima di Vitest 2.0, tutti gli hook venivano eseguiti in parallelo. In Vitest 2.0, tutti gli hook vengono eseguiti in sequenza. Inoltre, gli hook afterAll/afterEach vengono eseguiti in ordine inverso.
Per ripristinare l'esecuzione parallela degli hook, imposta sequence.hooks su 'parallel':
export default defineConfig({
test: {
sequence: {
hooks: 'parallel',
},
},
});suite.concurrent Esegue Tutti i Test in Parallelo
In precedenza, specificare concurrent su una suite raggruppava i test concorrenti per suite, eseguendoli sequenzialmente. Ora, seguendo il comportamento di Jest, tutti i test vengono eseguiti in parallelo (soggetti ai limiti di maxConcurrency).
L'opzione coverage.ignoreEmptyLines di V8 Coverage è Abilitata per Impostazione Predefinita
Il valore predefinito di coverage.ignoreEmptyLines è ora true. Questo cambiamento significativo potrebbe influenzare i report di copertura del codice, richiedendo modifiche alle soglie di copertura per alcuni progetti. Questo aggiustamento influisce solo sull'impostazione predefinita quando coverage.provider è 'v8'.
Rimozione dell'Opzione watchExclude
Vitest utilizza il watcher di Vite. Per escludere file o directory, aggiungili a server.watch.ignored:
export default defineConfig({
server: {
watch: {
ignored: ['!node_modules/examplejs']
}
}
});--segfault-retry Rimosso
Con le modifiche al pool predefinito, questa opzione non è più necessaria. Se riscontri errori di segfault, prova a cambiare il pool in 'forks'. Se il problema persiste, apri una nuova issue con una riproduzione.
Task Vuota nelle Suite Rimossa
Questa modifica riguarda l'API avanzata delle task. In precedenza, l'attraversamento di .suite avrebbe eventualmente portato alla suite interna vuota che veniva utilizzata al posto di una task di file.
Questo rende .suite opzionale; se la task è definita a livello superiore, non avrà una suite. Puoi usare la proprietà .file che ora è presente su tutte le task (inclusa la task di file stessa, quindi fai attenzione a non cadere in una ricorsione infinita).
Questa modifica rimuove anche il file da expect.getState().currentTestName e rende expect.getState().testPath obbligatorio.
task.meta Aggiunto al JSON Reporter
Il JSON reporter ora stampa task.meta per ogni risultato di asserzione.
Tipi Generici Semplificati delle Funzioni Mock (es. vi.fn<T>, Mock<T>)
In precedenza vi.fn<TArgs, TReturn> accettava due tipi generici separatamente per gli argomenti e il valore di ritorno. Questo è stato modificato per accettare direttamente un tipo di funzione vi.fn<T> per semplificare l'utilizzo.
import { type Mock, vi } from 'vitest';
const add = (x: number, y: number): number => x + y;
// usando vi.fn<T>
const mockAdd = vi.fn<Parameters<typeof add>, ReturnType<typeof add>>();
const mockAdd = vi.fn<typeof add>();
// usando Mock<T>
const mockAdd: Mock<Parameters<typeof add>, ReturnType<typeof add>> = vi.fn();
const mockAdd: Mock<typeof add> = vi.fn(); Accesso ai Valori Risolti di mock.results
In precedenza Vitest risolveva i valori di mock.results se la funzione restituiva una Promise. Ora c'è una proprietà separata mock.settledResults che si popola solo quando la Promise restituita viene risolta o rifiutata.
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'Con questa modifica, vengono introdotti anche nuovi matcher toHaveResolved* simili a toHaveReturned per facilitare la migrazione se in precedenza usavi toHaveReturned:
const fn = vi.fn().mockResolvedValueOnce('result');
await fn();
expect(fn).toHaveReturned('result');
expect(fn).toHaveResolved('result'); Modalità Browser
La modalità browser di Vitest è stata ampiamente modificata durante il ciclo beta. Puoi leggere la nostra filosofia sulla modalità Browser nella pagina di discussione di GitHub.
La maggior parte delle modifiche erano additive, ma ci sono state alcune piccole modifiche che hanno causato interruzioni:
- Il provider
noneè stato rinominato inpreview#5842 - Il provider
previewè ora predefinito #5842 indexScriptsè stato rinominato inorchestratorScripts#5842
Opzioni Deprecate Rimosse
Sono state rimosse alcune opzioni deprecate:
- Comando
vitest typecheck- usavitest --typecheckinvece - Variabili d'ambiente
VITEST_JUNIT_CLASSNAMEeVITEST_JUNIT_SUITE_NAME(usa le opzioni del reporter invece) - Controllo per la copertura
c8(usa coverage-v8 invece) - Esportazione di
SnapshotEnvironmentdavitest- importalo davitest/snapshotinvece SpyInstanceè stato rimosso a favore diMockInstance
Migrazione a Vitest 1.0
Requisiti Minimi
Vitest 1.0 richiede Vite 5.0 e Node.js 18 o superiore.
Tutti i sotto-pacchetti @vitest/* richiedono Vitest versione 1.0.
Aggiornamento Snapshot #3961
Negli snapshot le virgolette non vengono più escaped, e tutti gli snapshot usano virgolette inverse (`) anche se la stringa è una singola riga.
- Le virgolette non sono più escaped:
expect({ foo: 'bar' }).toMatchInlineSnapshot(`
Object {
- \\"foo\\": \\"bar\\",
+ "foo": "bar",
}
`)- Gli snapshot su una riga ora usano le virgolette "`" invece di ':
- expect('some string').toMatchInlineSnapshot('"some string"')
+ expect('some string').toMatchInlineSnapshot(`"some string"`)Ci sono state anche modifiche al pacchetto @vitest/snapshot. Se non lo stai usando direttamente, non devi cambiare nulla.
- Non serve più estendere
SnapshotClientsolo per sovrascrivere il metodoequalityCheck: basta passarlo comeisEqualquando si inizializza un'istanza client.setTestè stato rinominato inclient.startCurrentRunclient.resetCurrentè stato rinominato inclient.finishCurrentRun
I Pool Sono Standardizzati #4172
Abbiamo rimosso molte opzioni di configurazione per rendere più facile configurare il runner in base alle tue esigenze. Per favore, consulta gli esempi di migrazione se ti affidi a --threads o ad altri flag correlati.
--threadsè ora--pool=threads--no-threadsè ora--pool=forks--single-threadè ora--poolOptions.threads.singleThread--experimental-vm-threadsè ora--pool=vmThreads--experimental-vm-worker-memory-limitè ora--poolOptions.vmThreads.memoryLimit--isolateè ora--poolOptions.<nome-pool>.isolateebrowser.isolatetest.maxThreadsè oratest.poolOptions.<nome-pool>.maxThreadstest.minThreadsè oratest.poolOptions.<nome-pool>.minThreadstest.useAtomicsè oratest.poolOptions.<nome-pool>.useAtomicstest.poolMatchGlobs.child_processè oratest.poolMatchGlobs.forkstest.poolMatchGlobs.experimentalVmThreadsè oratest.poolMatchGlobs.vmThreads
{
scripts: {
- "test": "vitest --no-threads"
// Per ottenere lo stesso comportamento:
+ "test": "vitest --pool forks --poolOptions.forks.singleFork"
// O più fork paralleli:
+ "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"
}
}Modifiche alla Copertura #4265, #4442
L'opzione coverage.all è ora attiva di default. Ciò significa che tutti i file di progetto che corrispondono al pattern coverage.include verranno elaborati anche se non vengono eseguiti.
La struttura dell'API delle soglie di copertura è stata modificata e ora supporta la specifica di soglie per file specifici utilizzando pattern 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,
+ }
}
}
})Tipi Mock #4400
Alcuni tipi sono stati rimossi. Ora si usa la denominazione "Mock" come in Jest.
- import { EnhancedSpy, SpyInstance } from 'vitest'
+ import { MockInstance } from 'vitest'WARNING
SpyInstance è deprecato a favore di MockInstance e verrà rimosso nella prossima major release.
Mock dei Timer #3925
vi.useFakeTimers() non simula più automaticamente process.nextTick. È ancora possibile simulare process.nextTick specificandolo esplicitamente usando vi.useFakeTimers({ toFake: ['nextTick'] }).
Tuttavia, la simulazione di process.nextTick non è possibile quando si usa --pool=forks. Usa un'opzione --pool diversa se hai bisogno della simulazione di process.nextTick.
Migrazione da Jest
Vitest è stato progettato con un'API compatibile con Jest, al fine di rendere la migrazione da Jest il più semplice possibile. Nonostante questi sforzi, potresti comunque riscontrare le seguenti differenze:
Globali come Predefiniti
Jest ha la sua API globale abilitata per impostazione predefinita. Vitest no. Puoi abilitare le globali tramite l'impostazione di configurazione globals o aggiornare il tuo codice per utilizzare le importazioni dal modulo vitest invece.
Se decidi di mantenere le globali disabilitate, tieni presente che librerie comuni come testing-library non eseguiranno la pulizia automatica del DOM.
Mock dei Moduli
Quando si simula un modulo in Jest, il valore di ritorno dell'argomento factory è l'export predefinito. In Vitest, l'argomento factory deve restituire un oggetto con ogni export esplicitamente definito. Ad esempio, il seguente jest.mock dovrebbe essere aggiornato come segue:
jest.mock('./some-path', () => 'hello');
vi.mock('./some-path', () => ({
default: 'hello',
})); Per maggiori dettagli, si prega di consultare la sezione API vi.mock.
Comportamento di Auto-Mocking
Diversamente da Jest, i moduli simulati in <root>/__mocks__ non vengono caricati a meno che non venga chiamato vi.mock(). Se vuoi che vengano simulati in ogni test, come in Jest, puoi simularli all'interno di setupFiles.
Importazione dell'Originale di un Pacchetto Mockato
Se stai solo parzialmente simulando un pacchetto, potresti aver usato in precedenza la funzione requireActual di Jest. In Vitest, dovresti sostituire queste chiamate con vi.importActual.
const { cloneDeep } = jest.requireActual('lodash/cloneDeep');
const { cloneDeep } = await vi.importActual('lodash/cloneDeep'); Estensione del Mocking a Librerie Esterne
Mentre Jest lo fa per impostazione predefinita, quando si simula un modulo e si desidera che questa simulazione si estenda ad altre librerie esterne che utilizzano lo stesso modulo, è necessario indicare esplicitamente quale libreria di terze parti si desidera simulare. Questo assicura che la libreria esterna sia trattata come parte del tuo codice sorgente, utilizzando server.deps.inline.
server.deps.inline: ["lib-name"]expect.getState().currentTestName
Vitest unisce i nomi dei test con un simbolo > per rendere più facile distinguere i test dalle suite, mentre Jest usa uno spazio vuoto ().
- `${describeTitle} ${testTitle}`
+ `${describeTitle} > ${testTitle}`Variabili d'Ambiente
Come Jest, Vitest imposta NODE_ENV a test, se non era stato impostato prima. Vitest ha anche un equivalente per JEST_WORKER_ID chiamato VITEST_POOL_ID (sempre minore o uguale a maxThreads), quindi se lo utilizzi, non dimenticare di rinominarlo. Vitest espone anche VITEST_WORKER_ID che è un ID univoco di un worker in esecuzione - questo numero non è influenzato da maxThreads e aumenterà con ogni worker creato.
Sostituzione della Proprietà
Per modificare l'oggetto, in Jest si utilizza l'API replaceProperty. In Vitest, puoi ottenere lo stesso risultato usando vi.stubEnv o vi.spyOn.
Callback Done
A partire da Vitest v0.10.0, lo stile di dichiarazione dei test basato su callback è deprecato. Puoi riscriverli per usare funzioni async/await, o usare Promise per replicare lo stile callback.
it('should work', (done) => {
it('should work', () => new Promise(done => {
// ...
done()
})
})) Hook
Gli hook beforeAll/beforeEach possono restituire una funzione di teardown in Vitest. Per questo motivo potresti dover riscrivere la definizione dei tuoi hook, se restituiscono qualcosa di diverso da undefined o null:
beforeEach(() => setActivePinia(createTestingPinia()));
beforeEach(() => { setActivePinia(createTestingPinia()) }); In Jest gli hook vengono chiamati sequenzialmente (uno dopo l'altro). Per impostazione predefinita, Vitest esegue gli hook in parallelo. Per utilizzare il comportamento di Jest, aggiorna l'opzione sequence.hooks:
export default defineConfig({
test: {
sequence: {
hooks: 'list',
}
}
});Tipi
Vitest non ha un equivalente allo spazio dei nomi jest, quindi dovrai importare i tipi direttamente da vitest:
let fn: jest.Mock<(name: string) => number>;
import type { Mock } from 'vitest';
let fn: Mock<(name: string) => number>; Timer
Vitest non supporta i timer legacy di Jest.
Timeout
Se hai usato jest.setTimeout, dovrai passare a vi.setConfig:
jest.setTimeout(5_000);
vi.setConfig({ testTimeout: 5_000 }); Snapshot Vue
Questa non è una funzionalità specifica di Jest, ma se in precedenza stavi usando Jest con il preset vue-cli, dovrai installare il pacchetto jest-serializer-vue e usarlo all'interno di setupFiles:
import { defineConfig } from 'vite';
export default defineConfig({
test: {
setupFiles: ['./tests/unit/setup.js'],
},
});import vueSnapshotSerializer from 'jest-serializer-vue';
expect.addSnapshotSerializer(vueSnapshotSerializer);Altrimenti negli snapshot appariranno molti caratteri " escaped.