Guida alla Migrazione
Migrazione a Vitest 3.0
Opzioni di Test come Terzo Argomento
Vitest 3.0 emette un avviso se si passa un oggetto come terzo argomento alle funzioni test
o describe
:
test('validation works', () => {
// ...
}, { retry: 3 });
test('validation works', { retry: 3 }, () => {
// ...
});
La prossima versione maggiore genererà un errore se il terzo argomento è un oggetto. Si noti che il numero di timeout è ancora valido:
test('validation works', () => {
// ...
}, 1000); // Ok ✅
browser.name
e browser.providerOptions
sono Deprecati
Sia browser.name
che browser.providerOptions
verranno rimossi in Vitest 4. Invece, utilizzare la nuova opzione browser.instances
:
export default defineConfig({
test: {
browser: {
name: 'chromium',
providerOptions: {
launch: { devtools: true },
},
instances: [
{
browser: 'chromium',
launch: { devtools: true },
},
],
},
},
})
Con il nuovo campo browser.instances
è anche possibile specificare più configurazioni del browser.
spy.mockReset
Ora Ripristina l'Implementazione Originale
In precedenza, non c'era un modo efficace per ripristinare lo spy all'implementazione originale senza doverlo riapplicare. Ora, spy.mockReset
ripristinerà l'implementazione originale della funzione invece di una finta noop.
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
Riutilizza il Mock se il Metodo è Già Mockato
In precedenza, Vitest assegnava sempre un nuovo spy quando spiava un oggetto. Questo causava errori con mockRestore
, ripristinando lo spy precedente anziché la funzione 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
Valori Predefiniti dei Timer Falsi
Vitest non offre più opzioni predefinite per fakeTimers.toFake
. Ora, Vitest simulerà qualsiasi API relativa ai timer disponibile (eccetto nextTick
). In particolare, performance.now()
viene ora simulato quando si chiama vi.useFakeTimers
.
vi.useFakeTimers();
performance.now(); // originale
performance.now(); // simulato
È possibile ripristinare il comportamento precedente specificando i timer durante la chiamata a vi.useFakeTimers
o nella configurazione globale.
export default defineConfig({
test: {
fakeTimers: {
toFake: [
'setTimeout',
'clearTimeout',
'setInterval',
'clearInterval',
'setImmediate',
'clearImmediate',
'Date',
]
},
},
})
Uguaglianza degli Errori Più Stretta
Vitest ora verifica più proprietà quando confronta gli errori tramite toEqual
o toThrowError
. Vitest ora confronta name
, message
, cause
e AggregateError.errors
. Per Error.cause
, il confronto viene eseguito in modo asimmetrico:
expect(new Error('hi', { cause: 'x' })).toEqual(new Error('hi')); // ✅
expect(new Error('hi')).toEqual(new Error('hi', { cause: 'x' })); // ❌
In aggiunta a una verifica più approfondita delle proprietà, Vitest ora confronta i prototipi degli errori. Ad esempio, se è stato lanciato un TypeError
, il controllo di uguaglianza dovrebbe fare riferimento a TypeError
, non a Error
:
expect(() => {
throw new TypeError('type error');
})
.toThrowError(new Error('type error'))
.toThrowError(new TypeError('type error'));
Per maggiori dettagli, consultare la PR: #5876.
L'esportazione della condizione module
non viene risolta per impostazione predefinita su Vite 6
Vite 6 consente opzioni resolve.conditions
più flessibili e Vitest le configura per escludere l'esportazione condizionale module
di default. Vedere anche la guida alla migrazione di Vite 6 per i dettagli delle modifiche lato Vite.
Il Tipo Custom
è Deprecato API
Il tipo Custom
è ora un alias per il tipo Test
. Si noti che Vitest ha aggiornato i tipi pubblici in 2.1 e ha cambiato i nomi esportati in RunnerCustomCase
e RunnerTestCase
:
import {
RunnerCustomCase,
RunnerTestCase,
} from 'vitest';
Se si utilizza getCurrentSuite().custom()
, il type
del task restituito è ora 'test'
. Il tipo Custom
verrà rimosso in Vitest 4.
Il Tipo WorkspaceSpec
Non è Più Utilizzato API
Nell'API pubblica, questo tipo era precedentemente utilizzato nei sequencer personalizzati. Migrare a TestSpecification
invece.
onTestFinished
e onTestFailed
Ora Ricevono un Contesto
I hook onTestFinished
e onTestFailed
in precedenza ricevevano un risultato del test come primo argomento. Ora, ricevono un contesto del test, come beforeEach
e afterEach
.
Modifiche all'API Snapshot API
L'API pubblica Snapshot in @vitest/snapshot
è stata modificata per supportare più stati all'interno di una singola esecuzione. Per maggiori dettagli, consultare la PR: #6817
Si noti che queste modifiche riguardano solo gli sviluppatori che utilizzano direttamente l'API Snapshot. Non ci sono state modifiche all'API .toMatchSnapshot
.
Modifiche alla Firma del Tipo resolveConfig
API
La funzione resolveConfig
è ora più funzionale. Invece di accettare una configurazione Vite già risolta, ora accetta una configurazione utente e restituisce la configurazione risolta.
Questa funzione non è utilizzata internamente ed è esposta esclusivamente come API pubblica.
Tipi vitest/reporters
Puliti API
L'entrypoint vitest/reporters
ora esporta solo le implementazioni dei reporter e i tipi di opzioni. Se si ha bisogno di accedere a TestCase
/TestSuite
e ad altri tipi correlati ai task, importarli aggiuntivamente da vitest/node
.
La copertura ignora i file di test anche quando coverage.excludes
viene sovrascritto.
Non è più possibile includere i file di test nel report di copertura sovrascrivendo coverage.excludes
. I file di test sono ora sempre esclusi.
Migrazione a Vitest 2.0
Il Pool Predefinito è forks
Vitest 2.0 modifica la configurazione predefinita per pool
in 'forks'
per una migliore stabilità. È possibile leggere la motivazione completa nella PR.
Se si è 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 uno Stack
Prima di Vitest 2.0, tutti gli hook venivano eseguiti in parallelo. In Vitest 2.0, tutti gli hook vengono eseguiti in serie. Inoltre, gli hook afterAll
/afterEach
vengono eseguiti in ordine inverso.
Per ripristinare l'esecuzione parallela degli hook, modificare sequence.hooks
in 'parallel'
:
export default defineConfig({
test: {
sequence: {
hooks: 'parallel',
},
},
})
suite.concurrent
Esegue Tutti i Test Concorrentemente
In precedenza, specificare concurrent
su una suite raggruppava i test concorrenti per suite, eseguendoli in sequenza. Ora, seguendo il comportamento di Jest, tutti i test vengono eseguiti in modo concorrente (soggetti ai limiti di maxConcurrency
).
coverage.ignoreEmptyLines
di V8 Coverage è Abilitato per Impostazione Predefinita
Il valore predefinito di coverage.ignoreEmptyLines
è ora true
. Questa modifica significativa potrebbe influire sui report di copertura del codice, richiedendo aggiustamenti 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. Escludere file o directory aggiungendoli 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 si verificano errori di segfault, provare a passare al pool 'forks'
. Se il problema persiste, aprire un nuovo problema con una riproduzione.
Task Vuoto nei Task della Suite Rimosso
Questa è una modifica all'API avanzata dei task. In precedenza, l'attraversamento di .suite
avrebbe eventualmente portato alla suite interna vuota che veniva utilizzata al posto di un task di file.
Questo rende .suite
opzionale; se il task è definito al livello superiore, non avrà una suite. È possibile ricorrere alla proprietà .file
, che è ora presente su tutti i task (incluso il task del file stesso, quindi fare 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 reporter JSON 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>
al fine di semplificarne l'utilizzo.
import { vi } from 'vitest';
import type { Mock } 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 mock.results
Risolti
In precedenza, Vitest risolveva i valori di mock.results
se la funzione restituiva una Promise. Ora esiste 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, introduciamo anche nuovi matcher toHaveResolved*
simili a toHaveReturned
per facilitare la migrazione, nel caso in cui si utilizzasse toHaveReturned
in precedenza:
const fn = vi.fn().mockResolvedValueOnce('result');
await fn();
expect(fn).toHaveReturned('result');
expect(fn).toHaveResolved('result');
Modalità Browser
La modalità browser di Vitest ha subito numerose modifiche durante il ciclo beta. È possibile 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 introdotto rotture:
- Il provider
none
è stato rinominato inpreview
#5842 - Il provider
preview
è ora predefinito #5842 indexScripts
è stato rinominato inorchestratorScripts
#5842
Opzioni Deprecate Rimosse
Alcune opzioni deprecate sono state rimosse:
- comando
vitest typecheck
- usarevitest --typecheck
invece - variabili d'ambiente
VITEST_JUNIT_CLASSNAME
eVITEST_JUNIT_SUITE_NAME
(usare le opzioni del reporter invece) - controllo per la copertura
c8
(usarecoverage-v8
invece) - esportazione di
SnapshotEnvironment
davitest
- importarlo 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 versioni superiori.
Tutti i sotto-pacchetti @vitest/*
richiedono Vitest versione 1.0.
Aggiornamento degli Snapshot #3961
Le virgolette negli snapshot non sono più sottoposte a escape, e tutti gli snapshot usano le virgolette inverse (`) anche se la stringa è su una singola riga.
- Le virgolette non sono più escape:
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 si sta utilizzando direttamente, non è necessario cambiare nulla.
- Non è più necessario 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 semplificare la configurazione del runner in base alle proprie esigenze. Si prega di consultare gli esempi di migrazione se ci si affida 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.<pool-name>.isolate
ebrowser.isolate
test.maxThreads
è oratest.poolOptions.<pool-name>.maxThreads
test.minThreads
è oratest.poolOptions.<pool-name>.minThreads
test.useAtomics
è oratest.poolOptions.<pool-name>.useAtomics
test.poolMatchGlobs.child_process
è oratest.poolMatchGlobs.forks
test.poolMatchGlobs.experimentalVmThreads
è oratest.poolMatchGlobs.vmThreads
{
scripts: {
- "test": "vitest --no-threads"
// Per un comportamento identico:
+ "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 abilitata di default. Ciò significa che tutti i file di progetto che corrispondono al pattern coverage.include
verranno elaborati anche se non vengono eseguiti.
La forma 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 a favore della denominazione "Mock" in stile Jest.
- import { EnhancedSpy, SpyInstance } from 'vitest'
+ import { MockInstance } from 'vitest'
WARNING
SpyInstance
è deprecato a favore di MockInstance
e verrà rimosso nella prossima versione maggiore.
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
. Usare un'opzione --pool
diversa se è necessaria la 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 di default. Vitest no. È possibile abilitare le variabili globali tramite l'impostazione di configurazione globals
o aggiornare il proprio codice per utilizzare le importazioni dal modulo vitest
invece.
Se si decide di mantenere le variabili globali disabilitate, si tenga presente che librerie comuni come testing-library
non eseguiranno la pulizia automatica del DOM.
spy.mockReset
mockReset
di Jest sostituisce l'implementazione del mock con una funzione vuota che restituisce undefined
.
mockReset
di Vitest ripristina l'implementazione del mock a quella originale. Cioè, il ripristino di un mock creato da vi.fn(impl)
ripristinerà l'implementazione del mock a impl
.
Mock dei Moduli
Quando si simula un modulo in Jest, il valore di ritorno dell'argomento factory è l'esportazione predefinita. In Vitest, l'argomento factory deve restituire un oggetto con ogni esportazione esplicitamente definita. 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, fare riferimento alla sezione API di vi.mock
.
Comportamento di Auto-Mocking
A differenza di Jest, i moduli mockati in <root>/__mocks__
non vengono caricati a meno che non venga chiamato vi.mock()
. Se si ha bisogno che vengano mockati in ogni test, come in Jest, è possibile mockarli all'interno di setupFiles
.
Importazione dell'Originale di un Pacchetto Mockato
Se si sta solo parzialmente mockando un pacchetto, si potrebbe aver usato in precedenza la funzione requireActual
di Jest. In Vitest, si dovrebbero 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 di default, quando si simula un modulo e si desidera che questa simulazione sia estesa ad altre librerie esterne che utilizzano lo stesso modulo, è necessario indicare esplicitamente quale libreria di terze parti si desidera simulare, in modo che la libreria esterna faccia parte del codice sorgente, utilizzando server.deps.inline.
server.deps.inline: ["lib-name"]
expect.getState().currentTestName
I nomi dei test
di Vitest sono uniti 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
Proprio come Jest, Vitest imposta NODE_ENV
su test
, se non era stato impostato in precedenza. Vitest ha anche una controparte per JEST_WORKER_ID
chiamata VITEST_POOL_ID
(sempre minore o uguale a maxThreads
), quindi se ci si affida ad essa, non dimenticare di rinominarla. 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.
Sostituisci proprietà
Se si desidera modificare l'oggetto, in Jest si utilizzerebbe l'API replaceProperty; in Vitest, è possibile utilizzare vi.stubEnv
o vi.spyOn
per fare lo stesso.
Callback Done
A partire da Vitest v0.10.0, lo stile di dichiarazione dei test basato su callback è deprecato. È possibile riscriverli per usare funzioni async
/await
, o usare Promise per emulare 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, potrebbe essere necessario riscrivere le proprie dichiarazioni di 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). Di default, Vitest esegue gli hook in parallelo. Per utilizzare il comportamento di Jest, aggiornare l'opzione sequence.hooks
:
export default defineConfig({
test: {
sequence: {
hooks: 'list',
}
}
})
Tipi
Vitest non ha un equivalente allo spazio dei nomi jest
, quindi sarà necessario 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 si è utilizzato jest.setTimeout
, sarà necessario migrare 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 si utilizzava Jest con il preset vue-cli, sarà necessario 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 i propri snapshot avranno molti caratteri "
con escape.