Przewodnik migracji
Migracja do Vitest 3.0
Opcje testowe jako trzeci argument
Vitest 3.0 wyświetla ostrzeżenie, jeśli obiekt jest przekazywany jako trzeci argument do funkcji test
lub describe
:
test('validation works', () => {
// ...
}, { retry: 3 });
test('validation works', { retry: 3 }, () => {
// ...
});
W kolejnej głównej wersji przekazanie obiektu jako trzeciego argumentu spowoduje błąd. Należy pamiętać, że numeryczny limit czasu nie jest przestarzały:
test('validation works', () => {
// ...
}, 1000); // Ok ✅
browser.name
i browser.providerOptions
są przestarzałe
Opcje browser.name
i browser.providerOptions
zostaną usunięte w Vitest 4. Zamiast nich należy użyć nowej opcji browser.instances
:
export default defineConfig({
test: {
browser: {
name: 'chromium',
providerOptions: {
launch: { devtools: true },
},
instances: [
{
browser: 'chromium',
launch: { devtools: true },
},
],
},
},
})
Nowe pole browser.instances
umożliwia również określenie wielu konfiguracji przeglądarek.
spy.mockReset
teraz przywraca oryginalną implementację
Wcześniej nie było łatwego sposobu na zresetowanie szpiega do jego oryginalnej implementacji bez ponownego jego użycia. Teraz spy.mockReset
zresetuje funkcję implementacji do oryginalnej, zamiast do fałszywej funkcji 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
ponownie używa makiety, jeśli metoda jest już zamockowana
Wcześniej Vitest zawsze przypisywał nowego szpiega podczas szpiegowania obiektu. Powodowało to błędy z mockRestore
, ponieważ przywracało poprzednią wersję szpiega zamiast oryginalnej funkcji:
vi.spyOn(fooService, 'foo').mockImplementation(() => 'bar');
vi.spyOn(fooService, 'foo').mockImplementation(() => 'bar');
vi.restoreAllMocks();
vi.isMockFunction(fooService.foo); // true
vi.isMockFunction(fooService.foo); // false
Domyślne ustawienia fałszywych timerów
Vitest nie dostarcza już domyślnych opcji fakeTimers.toFake
. Teraz Vitest mockuje dowolne dostępne API związane z timerami (z wyjątkiem nextTick
). Oznacza to, że performance.now()
jest teraz mockowane, gdy wywoływane jest vi.useFakeTimers
.
vi.useFakeTimers();
performance.now(); // original
performance.now(); // fake
Możesz wrócić do poprzedniego zachowania, określając timery podczas wywoływania vi.useFakeTimers
lub globalnie w konfiguracji:
export default defineConfig({
test: {
fakeTimers: {
toFake: [
'setTimeout',
'clearTimeout',
'setInterval',
'clearInterval',
'setImmediate',
'clearImmediate',
'Date',
]
},
},
})
Bardziej ścisła równość błędów
Vitest teraz sprawdza więcej właściwości podczas porównywania błędów za pomocą toEqual
lub toThrowError
. Vitest porównuje teraz name
, message
, cause
i AggregateError.errors
. Dla Error.cause
porównanie odbywa się asymetrycznie:
expect(new Error('hi', { cause: 'x' })).toEqual(new Error('hi')); // ✅
expect(new Error('hi')).toEqual(new Error('hi', { cause: 'x' })); // ❌
Dodatkowo do sprawdzania większej liczby właściwości, Vitest porównuje teraz prototypy błędów. Na przykład, jeśli został zgłoszony TypeError
, sprawdzenie równości powinno odnosić się do TypeError
, a nie Error
:
expect(() => {
throw new TypeError('type error');
})
.toThrowError(new Error('type error'))
.toThrowError(new TypeError('type error'));
Więcej szczegółów w PR: #5876.
Eksport warunku module
nie jest domyślnie rozwiązywany w Vite 6
Vite 6 umożliwia bardziej elastyczne opcje resolve.conditions
, a Vitest domyślnie konfiguruje je tak, aby wykluczały eksport warunkowy module
. Zobacz także przewodnik migracji Vite 6 dla szczegółów zmian po stronie Vite.
Typ Custom
jest przestarzały API
Typ Custom
jest teraz aliasem dla typu Test
. Należy zauważyć, że Vitest zaktualizował publiczne typy w wersji 2.1 i zmienił eksportowane nazwy na RunnerCustomCase
i RunnerTestCase
:
import {
RunnerCustomCase,
RunnerTestCase,
} from 'vitest';
Jeśli używasz getCurrentSuite().custom()
, type
zwróconego zadania jest teraz 'test'
. Typ Custom
zostanie usunięty w Vitest 4.
Typ WorkspaceSpec
nie jest już używany API
W publicznym API ten typ był wcześniej używany w niestandardowych sekwencerach. Proszę, zamiast niego migruj do TestSpecification
.
onTestFinished
i onTestFailed
teraz otrzymują kontekst
Funkcje zwrotne onTestFinished
i onTestFailed
wcześniej otrzymywały wyniki testów jako pierwszy argument. Teraz otrzymują kontekst testu, podobnie jak beforeEach
i afterEach
.
Zmiany w API migawek API
Publiczne API migawek w @vitest/snapshot
zostało zmienione, aby obsługiwać wiele stanów w ramach jednego uruchomienia. Więcej szczegółów w PR: #6817
Należy zauważyć, że te zmiany dotyczą tylko programistów, którzy bezpośrednio używają API migawek. Nie było żadnych zmian w API .toMatchSnapshot
.
Zmiany w sygnaturze typu resolveConfig
API
Funkcja resolveConfig
jest teraz bardziej użyteczna. Zamiast akceptować już rozwiązaną konfigurację Vite, akceptuje teraz konfigurację użytkownika i zwraca rozwiązaną konfigurację.
Ta funkcja nie jest używana wewnętrznie i jest udostępniana wyłącznie jako publiczne API.
Uporządkowane typy vitest/reporters
API
Punkt wejścia vitest/reporters
eksportuje teraz tylko implementacje reporterów i typy opcji. Jeśli potrzebujesz dostępu do TestCase
/TestSuite
i innych typów związanych z zadaniami, zaimportuj je dodatkowo z vitest/node
.
Pokrycie ignoruje pliki testowe, nawet po nadpisaniu coverage.excludes
.
Nie jest już możliwe uwzględnianie plików testowych w raporcie pokrycia poprzez nadpisywanie coverage.excludes
. Pliki testowe są teraz zawsze wykluczone.
Migracja do Vitest 2.0
Domyślna pula to forks
W Vitest 2.0 zmieniono domyślną konfigurację pool
na 'forks'
dla lepszej stabilności. Pełne uzasadnienie można znaleźć w PR.
Jeśli używałeś poolOptions
bez określania pool
, być może będziesz musiał zaktualizować konfigurację:
export default defineConfig({
test: {
poolOptions: {
threads: {
singleThread: true,
},
forks: {
singleFork: true,
},
}
}
})
Hooki działają w stosie
Przed Vitest 2.0 wszystkie hooki działały równolegle. W wersji 2.0 wszystkie hooki działają sekwencyjnie. Dodatkowo, hooki afterAll
/afterEach
działają 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
w zestawie grupowało testy współbieżne według zestawów, uruchamiając je sekwencyjnie. Teraz, zgodnie z zachowaniem Jest, wszystkie testy uruchamiane są współbieżnie (z zastrzeżeniem limitów maxConcurrency
).
coverage.ignoreEmptyLines
dla pokrycia V8 jest domyślnie włączone
Domyślna wartość coverage.ignoreEmptyLines
jest teraz true
. Ta znacząca zmiana może wpłynąć na raporty pokrycia kodu i wymagać 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 wykorzystuje obserwator Vite. Wyklucz pliki lub katalogi, dodając je do server.watch.ignored
:
export default defineConfig({
server: {
watch: {
ignored: ['!node_modules/examplejs']
}
}
})
Usunięto --segfault-retry
W związku ze zmianami w domyślnej puli, ta opcja nie jest już potrzebna. Jeśli doświadczasz błędów segfault, spróbuj przełączyć się na pulę 'forks'
. Jeśli problem nadal występuje, otwórz nowe zgłoszenie z reprodukcją.
Usunięto puste zadanie w zadaniach zestawu
Jest to zmiana dotycząca zaawansowanego API zadań. Wcześniej, przechodzenie przez .suite
ostatecznie prowadziło do pustego wewnętrznego zestawu, który zastępował zadanie 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ą rekursję).
Ta zmiana usuwa również plik z expect.getState().currentTestName
i sprawia, że expect.getState().testPath
jest wymagane.
task.meta
dodano do reportera JSON
Reporter JSON wyświetla teraz task.meta
dla każdego wyniku asercji.
Uproszczone typy generyczne funkcji mockujących (np. vi.fn<T>
, Mock<T>
)
Wcześniej vi.fn<TArgs, TReturn>
akceptowało dwa oddzielne typy generyczne 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 { vi } from 'vitest';
import type { Mock } 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 rozwiązanych mock.results
Wcześniej Vitest rozstrzygał wartości mock.results
, jeśli funkcja zwracała Promise. Teraz istnieje oddzielna właściwość mock.settledResults
, która jest dostępna 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ądarki
Tryb przeglądarki 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 wprowadzała nowe funkcje, ale było też kilka drobnych zmian powodujących niezgodność:
- Dostawca
none
został zmieniony napreview
#5842 - Dostawca
preview
jest teraz domyślny #5842 indexScripts
został zmieniony naorchestratorScripts
#5842
Usunięto przestarzałe opcje
Usunięto niektóre przestarzałe opcje:
- polecenie
vitest typecheck
- zamiast tego użyjvitest --typecheck
- zmienne środowiskowe
VITEST_JUNIT_CLASSNAME
iVITEST_JUNIT_SUITE_NAME
(zamiast nich użyj opcji reportera) - sprawdzanie pokrycia
c8
(zamiast tego użyj coverage-v8) - eksport
SnapshotEnvironment
zvitest
- zamiast tego zaimportuj go zvitest/snapshot
SpyInstance
został usunięty na rzeczMockInstance
Migracja do Vitest 1.0
Minimalne wymagania
Vitest 1.0 wymaga Vite 5.0 i Node.js 18 lub nowszych.
Wszystkie podpakiety @vitest/*
wymagają Vitest w wersji 1.0.
Aktualizacja migawek #3961
Cudzysłowy w migawkach nie są już uciekane, a wszystkie migawki używają apostrofów (`) nawet jeśli ciąg jest tylko jedną linią.
- Cudzysłowy nie są już uciekane:
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"`)
Były również zmiany w pakiecie @vitest/snapshot
. 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 są standaryzowane #4172
Usunęliśmy wiele opcji konfiguracji, aby ułatwić dostosowanie runnera do Twoich potrzeb. Proszę, spójrz na przykłady 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 Mocków #4400
Kilka typów zostało usuniętych na korzyść 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.
Mocki timerów #3925
vi.useFakeTimers()
nie mockuje już automatycznie process.nextTick
. Nadal możliwe jest mockowanie process.nextTick
poprzez jawne określenie go w vi.useFakeTimers({ toFake: ['nextTick'] })
.
Jednak mockowanie process.nextTick
nie jest możliwe podczas używania --pool=forks
. Użyj innej opcji --pool
, jeśli potrzebujesz mockowania process.nextTick
.
Migracja z Jest
Vitest został zaprojektowany z API kompatybilnym z Jest, aby migracja z Jest była jak najprostsza. Pomimo tych wysiłków, nadal możesz napotkać następujące różnice:
Globale jako domyślne
Jest ma domyślnie włączone swoje globalne API. 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, takie jak testing-library
, nie będą automatycznie czyścić DOM (funkcja cleanup).
spy.mockReset
mockReset
w Jest mockReset
zastępuje implementację mocka pustą funkcją, która zwraca undefined
.
mockReset
w Vitest mockReset
resetuje implementację mocka do jego oryginalnej. Oznacza to, że zresetowanie mocka utworzonego przez vi.fn(impl)
zresetuje implementację mocka do impl
.
Makiety modułów
Podczas mockowania modułu w Jest, wartość zwracana przez funkcję fabryczną 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
W przeciwieństwie do Jest, mockowane moduły w <root>/__mocks__
nie są ładowane, chyba że zostanie wywołane vi.mock()
. Jeśli potrzebujesz, aby były mockowane w każdym teście, tak jak w Jest, możesz mockować je w setupFiles
.
Importowanie oryginału zamockowanego pakietu
Jeśli tworzysz mocka pakietu tylko częściowo, być może wcześniej używałeś funkcji Jest requireActual
. W Vitest należy 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 przeciwieństwie do Jest, które domyślnie rozszerza mockowanie modułów na inne biblioteki zewnętrzne, w Vitest musisz jawnie określić, które biblioteki zewnętrzne mają być mockowane. Aby biblioteka zewnętrzna stała się częścią Twojego kodu źródłowego i podlegała mockowaniu, użyj opcji server.deps.inline.
server.deps.inline: ["lib-name"]
expect.getState().currentTestName
Nazwy test
w Vitest są łączone symbolem >
w celu łatwiejszego rozróżniania testów od zestawów, podczas gdy Jest używa pustej spacji ().
- `${describeTitle} ${testTitle}`
+ `${describeTitle} > ${testTitle}`
Zmienne środowiskowe
Podobnie jak 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 na nim bazujesz, nie zapomnij go zmienić. Vitest udostępnia również VITEST_WORKER_ID
, unikalny identyfikator uruchomionego workera – ta liczba nie jest zależna od maxThreads
i rośnie z każdym utworzonym workerem.
Zastąp właściwość
Jeśli chcesz zmodyfikować obiekt, w Jest użyjesz API replaceProperty. W Vitest możesz osiągnąć to samo, używając vi.stubEnv
lub vi.spyOn
.
Funkcja zwrotna Done
Od Vitest v0.10.0, deklarowanie testów w stylu funkcji zwrotnej jest przestarzałe. Możesz przepisać je, 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 sposobu deklarowania hooków, jeśli zwracają coś innego niż undefined
lub null
:
beforeEach(() => setActivePinia(createTestingPinia()))
beforeEach(() => { setActivePinia(createTestingPinia()) })
W Jest hooki są wywoływane 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 ma odpowiednika przestrzeni nazw jest
, dlatego należy 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 timerów Jest.
Limit czasu
Jeśli używałeś jest.setTimeout
, musiałbyś migrować do vi.setConfig
:
jest.setTimeout(5_000);
vi.setConfig({ testTimeout: 5_000 });
Migawki Vue
To nie jest funkcja 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 plikach 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 razie Twoje migawki będą zawierały wiele uciekanych znaków "
.