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
none
została zmieniona napreview
#5842 - Dostawca
preview
jest teraz domyślny #5842 indexScripts
został 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_CLASSNAME
iVITEST_JUNIT_SUITE_NAME
(zamiast tego użyj opcji reportera) - sprawdzanie pokrycia
c8
(zamiast tego użyj coverage-v8) - eksport
SnapshotEnvironment
zvitest
- zamiast tego importuj go zvitest/snapshot
SpyInstance
został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ć
SnapshotClient
tylko po to, aby nadpisać metodęequalityCheck
: po prostu przekaż ją jakoisEqual
podczas inicjowania instancji client.setTest
zostało zmienione naclient.startCurrentRun
client.resetCurrent
został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.
--threads
to teraz--pool=threads
--no-threads
to teraz--pool=forks
--single-thread
to teraz--poolOptions.threads.singleThread
--experimental-vm-threads
to teraz--pool=vmThreads
--experimental-vm-worker-memory-limit
to teraz--poolOptions.vmThreads.memoryLimit
--isolate
to teraz--poolOptions.<pool-name>.isolate
ibrowser.isolate
test.maxThreads
to teraztest.poolOptions.<pool-name>.maxThreads
test.minThreads
to teraztest.poolOptions.<pool-name>.minThreads
test.useAtomics
to teraztest.poolOptions.<pool-name>.useAtomics
test.poolMatchGlobs.child_process
to teraztest.poolMatchGlobs.forks
test.poolMatchGlobs.experimentalVmThreads
to 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) => { // [!code --]
it('should work', () => new Promise(done => { // [!code ++]
// ...
done()
}) // [!code --]
})) // [!code ++]
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 "
.