Przewodnik migracji
Migracja do Vitest 2.0
Domyślna pula to forks
Vitest 2.0 zmienia domyślną konfigurację pool na 'forks' w celu zwiększenia stabilności. Pełne uzasadnienie tej zmiany znajduje się w PR.
Jeśli używałeś poolOptions bez jawnego określania pool, może być konieczna aktualizacja konfiguracji:
export default defineConfig({
test: {
poolOptions: {
threads: {
singleThread: true,
},
forks: {
singleFork: true,
},
}
}
});Hooki działają szeregowo
Przed Vitest 2.0 wszystkie hooki działały równolegle. W wersji 2.0 wszystkie hooki działają szeregowo. Dodatkowo, hooki afterAll/afterEach są wykonywane w odwrotnej kolejności.
Aby powrócić do równoległego wykonywania hooków, zmień sequence.hooks na 'parallel':
export default defineConfig({
test: {
sequence: {
hooks: 'parallel',
},
},
});suite.concurrent uruchamia wszystkie testy współbieżnie
Wcześniej, określenie concurrent dla zestawu testów grupowało testy współbieżne w ramach zestawów, uruchamiając je sekwencyjnie. Teraz, zgodnie z zachowaniem Jest, wszystkie testy uruchamiane są współbieżnie (z uwzględnieniem limitów maxConcurrency).
coverage.ignoreEmptyLines w V8 Coverage jest domyślnie włączone
Domyślna wartość coverage.ignoreEmptyLines jest teraz true. Ta znacząca zmiana może wpłynąć na raporty pokrycia, wymagając dostosowania progów pokrycia dla niektórych projektów. To dostosowanie dotyczy tylko domyślnego ustawienia, gdy coverage.provider to 'v8'.
Usunięcie opcji watchExclude
Vitest używa obserwatora Vite. Aby wykluczyć pliki lub foldery, dodaj je do server.watch.ignored:
export default defineConfig({
server: {
watch: {
ignored: ['!node_modules/examplejs']
}
}
});Usunięto --segfault-retry
Wraz ze zmianami w domyślnej puli, ta opcja nie jest już potrzebna. Jeśli napotkasz błędy segfault, spróbuj przełączyć się na pulę 'forks'. Jeśli problem będzie się powtarzał, zgłoś nowy problem z możliwością odtworzenia.
Usunięto puste zadanie w zadaniach zestawu
To zmiana w zaawansowanym API zadań. Wcześniej, przechodząc przez .suite ostatecznie prowadziło do pustego wewnętrznego zestawu, który był używany zamiast zadania pliku.
To sprawia, że .suite jest opcjonalne; jeśli zadanie jest zdefiniowane na najwyższym poziomie, nie będzie miało zestawu. Możesz użyć właściwości .file, która jest teraz obecna we wszystkich zadaniach (w tym w samym zadaniu pliku, więc uważaj, aby nie wpaść w nieskończoną rekurencję).
Ta zmiana usuwa również plik z expect.getState().currentTestName i sprawia, że expect.getState().testPath jest wymagane.
task.meta dodano do raportu JSON
Reporter JSON teraz zawiera task.meta dla każdego wyniku asercji.
Uproszczone typy generyczne funkcji atrap (np. vi.fn<T>, Mock<T>)
Wcześniej vi.fn<TArgs, TReturn> przyjmowało dwa typy generyczne oddzielnie dla argumentów i wartości zwracanej. Zostało to zmienione na bezpośrednie akceptowanie typu funkcji vi.fn<T>, aby uprościć użycie.
import { type Mock, vi } 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(); Dostęp do rozstrzygniętych mock.results
Wcześniej Vitest rozwiązywał wartości mock.results, jeśli funkcja zwracała Promise. Teraz istnieje oddzielna właściwość mock.settledResults, która jest wypełniana tylko wtedy, gdy zwrócona Promise zostanie rozwiązana lub odrzucona.
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'Wraz z tą zmianą wprowadzamy również nowe matchery toHaveResolved* podobne do toHaveReturned, aby ułatwić migrację, jeśli wcześniej używałeś toHaveReturned:
const fn = vi.fn().mockResolvedValueOnce('result');
await fn();
expect(fn).toHaveReturned('result');
expect(fn).toHaveResolved('result'); Tryb przeglądarkowy
Tryb przeglądarkowy Vitest przeszedł wiele zmian podczas cyklu beta. Możesz przeczytać o naszej filozofii dotyczącej trybu przeglądarki na stronie dyskusji GitHub.
Większość zmian to dodatki, ale było kilka drobnych zmian powodujących niezgodność:
- Opcja
nonezostała zmieniona napreview#5842 - Dostawca
previewjest teraz domyślny #5842 indexScriptszostał zmieniony naorchestratorScripts#5842
Usunięto zdezaktualizowane opcje
Niektóre zdezaktualizowane opcje zostały usunięte:
- polecenie
vitest typecheck- zamiast tego użyjvitest --typecheck - zmienne środowiskowe
VITEST_JUNIT_CLASSNAMEiVITEST_JUNIT_SUITE_NAME(zamiast tego użyj opcji reportera) - sprawdzanie pokrycia
c8(zamiast tego użyj coverage-v8) - eksport
SnapshotEnvironmentzvitest- zamiast tego importuj go zvitest/snapshot SpyInstancezostało usunięte na rzeczMockInstance
Migracja do Vitest 1.0
Wymagania minimalne
Vitest 1.0 wymaga Vite 5.0 i Node.js 18 lub nowszej.
Wszystkie podpakiety @vitest/* wymagają Vitest w wersji 1.0.
Zmiany w migawkach #3961
Cudzysłowy w migawkach nie są już escapowane, a wszystkie migawki używają cudzysłowów wstecznych (`) nawet jeśli ciąg znaków jest tylko jedną linią.
- Cudzysłowy nie są już escapowane:
expect({ foo: 'bar' }).toMatchInlineSnapshot(`
Object {
- \\"foo\\": \\"bar\\",
+ "foo": "bar",
}
`)- Jednoliniowe migawki używają teraz cudzysłowów "`" zamiast ':
- expect('some string').toMatchInlineSnapshot('"some string"')
+ expect('some string').toMatchInlineSnapshot(`"some string"`)W pakiecie @vitest/snapshot wprowadzono również zmiany. Jeśli nie używasz go bezpośrednio, nie musisz nic zmieniać.
- Nie musisz już rozszerzać
SnapshotClienttylko po to, aby nadpisać metodęequalityCheck: po prostu przekaż ją jakoisEqualpodczas inicjowania instancji client.setTestzostało zmienione naclient.startCurrentRunclient.resetCurrentzostało zmienione naclient.finishCurrentRun
Pule zostały ustandaryzowane #4172
Zredukowaliśmy liczbę opcji konfiguracyjnych, aby ułatwić konfigurację runnera do Twoich potrzeb. Zapoznaj się z przykładami migracji, jeśli polegasz na --threads lub innych powiązanych flagach.
--threadsto teraz--pool=threads--no-threadsto teraz--pool=forks--single-threadto teraz--poolOptions.threads.singleThread--experimental-vm-threadsto teraz--pool=vmThreads--experimental-vm-worker-memory-limitto teraz--poolOptions.vmThreads.memoryLimit--isolateto teraz--poolOptions.<pool-name>.isolateibrowser.isolatetest.maxThreadsto teraztest.poolOptions.<pool-name>.maxThreadstest.minThreadsto teraztest.poolOptions.<pool-name>.minThreadstest.useAtomicsto teraztest.poolOptions.<pool-name>.useAtomicstest.poolMatchGlobs.child_processto teraztest.poolMatchGlobs.forkstest.poolMatchGlobs.experimentalVmThreadsto teraztest.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"
}
}Zmiany w pokryciu #4265, #4442
Opcja coverage.all jest teraz domyślnie włączona. Oznacza to, że wszystkie pliki projektu pasujące do wzorca coverage.include zostaną przetworzone, nawet jeśli nie zostaną wykonane.
Struktura API progów pokrycia została zmieniona i teraz obsługuje określanie progów dla konkretnych plików za pomocą wzorców 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,
+ }
}
}
})Typy atrap #4400
Usunięto kilka typów na rzecz nazewnictwa "Mock" w stylu Jest.
- import { EnhancedSpy, SpyInstance } from 'vitest'
+ import { MockInstance } from 'vitest'WARNING
SpyInstance jest przestarzałe na rzecz MockInstance i zostanie usunięte w następnej głównej wersji.
Atrapy timerów #3925
vi.useFakeTimers() nie mockuje już automatycznie process.nextTick. Nadal można mockować process.nextTick poprzez jawne określenie go za pomocą vi.useFakeTimers({ toFake: ['nextTick'] }).
Jednak mockowanie process.nextTick nie jest możliwe podczas używania --pool=forks. Wybierz inną opcję --pool, jeśli potrzebujesz mockowania process.nextTick.
Migracja z Jest
Vitest oferuje API kompatybilne z Jest, aby migracja z Jest była jak najprostsza. Mimo to, nadal możesz napotkać następujące różnice:
Domyślne globale
Jest ma swoje API globalnych zmiennych domyślnie włączone. Vitest nie. Możesz albo włączyć globale za pomocą ustawienia konfiguracji globals, albo zaktualizować swój kod, aby używał importów z modułu vitest.
Jeśli zdecydujesz się pozostawić globale wyłączone, pamiętaj, że popularne biblioteki jak testing-library, nie będą automatycznie czyścić DOM cleanup.
Mocki modułów
Przy mockowaniu modułu w Jest, wartość zwracana przez argument fabryki jest domyślnym eksportem. W Vitest, argument fabryki musi zwracać obiekt z każdym eksportem jawnie zdefiniowanym. Na przykład, następujący jest.mock musiałby zostać zaktualizowany w następujący sposób:
jest.mock('./some-path', () => 'hello');
vi.mock('./some-path', () => ({
default: 'hello',
})); Więcej szczegółów znajdziesz w sekcji API vi.mock.
Zachowanie automatycznego mockowania
Inaczej niż w Jest, mockowane moduły w <root>/__mocks__ nie są ładowane, chyba że zostanie wywołane vi.mock(). Jeśli chcesz, aby były mockowane w każdym teście, tak jak w Jest, możesz je mockować w setupFiles.
Importowanie oryginału mockowanego pakietu
Jeśli częściowo mockujesz pakiet, być może wcześniej używałeś funkcji Jest requireActual. W Vitest powinieneś zastąpić te wywołania vi.importActual.
const { cloneDeep } = jest.requireActual('lodash/cloneDeep');
const { cloneDeep } = await vi.importActual('lodash/cloneDeep'); Rozszerzanie mockowania na biblioteki zewnętrzne
W Jest, mockowanie modułu domyślnie rozszerza się na inne biblioteki zewnętrzne, które używają tego samego modułu. W Vitest, aby osiągnąć ten sam efekt, musisz jawnie określić, która biblioteka zewnętrzna ma być mockowana, dodając ją do server.deps.inline. Dzięki temu biblioteka zewnętrzna będzie traktowana jako część Twojego kodu źródłowego.
server.deps.inline: ["lib-name"]expect.getState().currentTestName
Nazwy test w Vitest są łączone symbolem > w celu ułatwienia rozróżniania testów od zestawów, podczas gdy Jest używa pustej spacji ().
- `${describeTitle} ${testTitle}`
+ `${describeTitle} > ${testTitle}`Zmienne środowiskowe
Analogicznie do Jest, Vitest ustawia NODE_ENV na test, jeśli nie było wcześniej ustawione. Vitest ma również odpowiednik dla JEST_WORKER_ID o nazwie VITEST_POOL_ID (zawsze mniejszy lub równy maxThreads), więc jeśli z niego korzystasz, nie zapomnij go zmienić. Vitest udostępnia również VITEST_WORKER_ID, który jest unikalnym identyfikatorem uruchomionego workera - ta liczba nie jest zależna od maxThreads i będzie rosła z każdym utworzonym workerem.
Właściwość replace
Jeśli chcesz zmodyfikować obiekt, w Jest użyjesz API replaceProperty, w Vitest możesz użyć vi.stubEnv lub vi.spyOn, aby zrobić to samo.
Funkcja zwrotna Done
Od Vitest v0.10.0, sposób deklarowania testów z użyciem funkcji zwrotnej jest przestarzały. Możesz je przepisać, aby używały funkcji async/await, lub użyć Promise, aby naśladować styl funkcji zwrotnej.
it('should work', (done) => {
it('should work', () => new Promise(done => {
// ...
done()
})
})) Hooki
Hooki beforeAll/beforeEach mogą zwracać funkcję czyszczącą w Vitest. Z tego powodu może być konieczne przepisanie deklaracji hooków, jeśli zwracają coś innego niż undefined lub null:
beforeEach(() => setActivePinia(createTestingPinia()));
beforeEach(() => { setActivePinia(createTestingPinia()) }); W Jest hooki wykonują się sekwencyjnie (jeden po drugim). Domyślnie Vitest uruchamia hooki równolegle. Aby użyć zachowania Jest, zaktualizuj opcję sequence.hooks:
export default defineConfig({
test: {
sequence: {
hooks: 'list',
}
}
});Typy
Vitest nie posiada odpowiednika przestrzeni nazw jest, więc będziesz musiał importować typy bezpośrednio z vitest:
let fn: jest.Mock<(name: string) => number>;
import type { Mock } from 'vitest';
let fn: Mock<(name: string) => number>; Timery
Vitest nie obsługuje starszych implementacji timerów z Jest.
Limit czasu
Jeśli korzystałeś z jest.setTimeout, musiałbyś migrować do vi.setConfig:
jest.setTimeout(5_000);
vi.setConfig({ testTimeout: 5_000 }); Migawki Vue
To nie jest funkcjonalność specyficzna dla Jest, ale jeśli wcześniej używałeś Jest z presetem vue-cli, będziesz musiał zainstalować pakiet jest-serializer-vue i użyć go w setupFiles:
import { defineConfig } from 'vite';
export default defineConfig({
test: {
setupFiles: ['./tests/unit/setup.js'],
},
});import vueSnapshotSerializer from 'jest-serializer-vue';
expect.addSnapshotSerializer(vueSnapshotSerializer);W przeciwnym przypadku Twoje migawki będą zawierały wiele uciekanych znaków ".