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 --typecheck
invece - Variabili d'ambiente
VITEST_JUNIT_CLASSNAME
eVITEST_JUNIT_SUITE_NAME
(usa le opzioni del reporter invece) - Controllo per la copertura
c8
(usa coverage-v8 invece) - Esportazione di
SnapshotEnvironment
davitest
- importalo davitest/snapshot
invece 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
SnapshotClient
solo per sovrascrivere il metodoequalityCheck
: basta passarlo comeisEqual
quando si inizializza un'istanza client.setTest
è stato rinominato inclient.startCurrentRun
client.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>.isolate
ebrowser.isolate
test.maxThreads
è oratest.poolOptions.<nome-pool>.maxThreads
test.minThreads
è oratest.poolOptions.<nome-pool>.minThreads
test.useAtomics
è oratest.poolOptions.<nome-pool>.useAtomics
test.poolMatchGlobs.child_process
è oratest.poolMatchGlobs.forks
test.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) => { // [!code --]
it('should work', () => new Promise(done => { // [!code ++]
// ...
done()
}) // [!code --]
})) // [!code ++]
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.