Vi
Vitest, vi
yardımcı işlevleri aracılığıyla size destek olur. Bu işlevlere global olarak erişebilirsiniz ( globals yapılandırması etkinleştirildiğinde) veya doğrudan vitest
paketinden içe aktarabilirsiniz:
import { vi } from 'vitest';
Modülleri Taklit Etme
Bu bölüm, bir modülü taklit etmek için kullanabileceğiniz API'yi açıklar. Vitest'in require()
kullanılarak içe aktarılan modülleri taklit etmeyi desteklemediğini lütfen unutmayın.
vi.mock
- Tip:
(path: string, factory?: MockOptions | ((importOriginal: () => unknown) => unknown)) => void
- Tip:
<T>(path: Promise<T>, factory?: MockOptions | ((importOriginal: () => T) => T | Promise<T>)) => void
Belirtilen path
'ten içe aktarılan tüm modülleri başka bir modülle değiştirir. Yol içinde yapılandırılmış Vite takma adlarını kullanabilirsiniz. vi.mock
çağrısı dosyanın en üstüne taşınır (hoisted), bu nedenle onu nerede çağırdığınız önemli değildir; her zaman tüm içe aktarmalardan önce yürütülür. Kapsamı dışındaki bazı değişkenlere başvurmanız gerekiyorsa, bunları vi.hoisted
içinde tanımlayabilir ve vi.mock
içinde bunlara başvurabilirsiniz.
WARNING
vi.mock
yalnızca import
anahtar kelimesiyle içe aktarılan modüller için çalışır. require
ile çalışmaz.
vi.mock
'i yukarı taşımak için Vitest, dosyalarınızı statik olarak analiz eder. Bu, vitest
paketinden (örneğin, bazı yardımcı dosyalardan) doğrudan içe aktarılmayan vi
'nin kullanılamayacağı anlamına gelir. vi.mock
'i vitest
'ten içe aktarılan vi
ile kullanın veya globals
yapılandırma seçeneğini etkinleştirin.
Vitest, bir test dosyası çalışırken önbelleğe alındıkları için bir kurulum dosyasında içe aktarılan modülleri taklit etmez. Bir test dosyasını çalıştırmadan önce tüm modül önbelleklerini temizlemek için vi.hoisted
içinde vi.resetModules()
çağırabilirsiniz.
factory
işlevi tanımlanmışsa, tüm içe aktarmalar bu işlevin sonucunu döndürür. Vitest, factory'yi yalnızca bir kez çağırır ve vi.unmock
veya vi.doUnmock
çağrılana kadar sonraki tüm içe aktarmalar için sonuçları önbelleğe alır.
jest
'ten farklı olarak, factory asenkron olabilir. vi.importActual
veya factory'nin ilk argüman olarak geçtiği bir yardımcıyı kullanabilir ve orijinal modülü içeride alabilirsiniz.
Ayrıca bir factory işlevi yerine spy
özelliği olan bir nesne de sağlayabilirsiniz. spy
true
ise, Vitest modülü her zamanki gibi otomatik olarak taklit eder, ancak dışa aktarımların uygulamasını geçersiz kılmaz. Bu, yalnızca dışa aktarılan yöntemin başka bir yöntem tarafından doğru şekilde çağrıldığını doğrulamak istediğinizde faydalıdır.
import { calculator } from './src/calculator.ts';
vi.mock('./src/calculator.ts', { spy: true });
// orijinal uygulamayı çağırır,
// ancak davranışı daha sonra doğrulamaya izin verir
const result = calculator(1, 2);
expect(result).toBe(3);
expect(calculator).toHaveBeenCalledWith(1, 2);
expect(calculator).toHaveReturned(3);
Vitest ayrıca daha iyi IDE desteği için vi.mock
ve vi.doMock
yöntemlerinde bir dize yerine bir modül sözü de destekler. Dosya taşındığında, yol güncellenir ve importOriginal
türü otomatik olarak devralır. Bu imzayı kullanmak, factory dönüş türünün orijinal modülle uyumlu olmasını da zorunlu kılar (dışa aktarımları isteğe bağlı tutar).
// @filename: ./path/to/module.js
export declare function total(...numbers: number[]): number;
// @filename: test.js
import { vi } from 'vitest';
// ---cut---
vi.mock(import('./path/to/module.js'), async importOriginal => {
const mod = await importOriginal(); // tür çıkarılır
// ^?
return {
...mod,
// bazı dışa aktarımları değiştir
total: vi.fn(),
};
});
Vitest, dahili olarak hala bir dize üzerinde çalışır, bir modül nesnesi üzerinde değil.
Ancak, tsconfig.json
içinde yapılandırılmış paths
takma adlarıyla TypeScript kullanıyorsanız, derleyici içe aktarma türlerini doğru şekilde çözümleyemez. Bunu sağlamak için, tüm takma adlı içe aktarmaları, ilgili göreli yollarıyla değiştirdiğinizden emin olun. Örn. import('@/module')
yerine import('./path/to/module.js')
kullanın.
WARNING
vi.mock
dosyanın en üstüne taşınır (başka bir deyişle, hoisted). Bu, onu ne zaman yazarsanız yazın (ister beforeEach
içinde ister test
içinde olsun), aslında ondan önce çağrılacağı anlamına gelir.
Bu aynı zamanda, factory içinde, factory dışında tanımlanmış herhangi bir değişkeni kullanamayacağınız anlamına gelir.
Factory içinde değişkenleri kullanmanız gerekiyorsa, vi.doMock
kullanmayı deneyin. Aynı şekilde çalışır ancak yukarı taşınmaz. Yalnızca sonraki içe aktarmaları taklit ettiğini unutmayın.
vi.hoisted
yöntemiyle tanımlanan değişkenlere de vi.mock
'ten önce bildirilmişse başvurabilirsiniz:
import { namedExport } from './path/to/module.js';
const mocks = vi.hoisted(() => {
return {
namedExport: vi.fn(),
};
});
vi.mock('./path/to/module.js', () => {
return {
namedExport: mocks.namedExport,
};
});
vi.mocked(namedExport).mockReturnValue(100);
expect(namedExport()).toBe(100);
expect(namedExport).toBe(mocks.namedExport);
WARNING
Varsayılan dışa aktarıma sahip bir modülü taklit ediyorsanız, döndürülen factory işlevi nesnesinde bir default
anahtarı sağlamanız gerekir. Bu, ES modülüne özgü bir durumdur; bu nedenle, jest
CommonJS modüllerini kullandığı için jest
belgeleri farklılık gösterebilir. Örneğin,
vi.mock('./path/to/module.js', () => {
return {
default: { myDefaultKey: vi.fn() },
namedExport: vi.fn(),
// vb...
};
});
Taklit ettiğiniz bir dosyanın yanında bir __mocks__
klasörü varsa ve factory sağlanmamışsa, Vitest __mocks__
alt klasöründe aynı ada sahip bir dosya bulmaya çalışır ve onu gerçek bir modül olarak kullanır. Bir bağımlılığı taklit ediyorsanız, Vitest projenin kökünde (varsayılan olarak process.cwd()
'dir) bir __mocks__
klasörü bulmaya çalışır. Bağımlılıkların nerede bulunduğunu Vitest'e deps.moduleDirectories
yapılandırma seçeneği aracılığıyla belirtebilirsiniz.
Örneğin, şu dosya yapısına sahipsiniz:
- __mocks__
- axios.js
- src
__mocks__
- increment.js
- increment.js
- tests
- increment.test.js
Bir test dosyasında factory veya seçenekler sağlanmadan vi.mock
çağırırsanız, bir modül olarak kullanılacak __mocks__
klasöründe bir dosya bulur:
import { vi } from 'vitest';
// axios, `__mocks__/axios.js`'den varsayılan bir dışa aktarımdır
import axios from 'axios';
// increment, `src/__mocks__/increment.js`'den adlandırılmış bir dışa aktarımdır
import { increment } from '../increment.js';
vi.mock('axios');
vi.mock('../increment.js');
axios.get(`/apples/${increment(1)}`);
WARNING
Dikkat edin, eğer vi.mock
çağrılmazsa modüller otomatik olarak taklit edilmez. Jest'in otomatik taklit davranışını taklit etmek için, setupFiles
içinde her gerekli modül için vi.mock
çağırabilirsiniz.
__mocks__
klasörü veya bir factory sağlanmamışsa, Vitest orijinal modülü içe aktarır ve tüm dışa aktarımlarını otomatik olarak taklit eder. Uygulanan kuralları görmek için algoritma bölümüne bakın.
vi.doMock
- Tip:
(path: string, factory?: MockOptions | ((importOriginal: () => unknown) => unknown)) => void
- Tip:
<T>(path: Promise<T>, factory?: MockOptions | ((importOriginal: () => T) => T | Promise<T>)) => void
vi.mock
ile aynıdır, ancak dosyanın en üstüne taşınmaz, böylece dosyanın global kapsamındaki değişkenlere başvurabilirsiniz. Modülün bir sonraki dinamik içe aktarımı taklit edilir.
WARNING
Bu, bundan önce içe aktarılan modülleri taklit etmez. ESM'deki tüm statik içe aktarmaların her zaman en üste taşındığını unutmayın, bu nedenle bunu statik içe aktarmadan önce koymak, içe aktarmadan önce çağrılmasını zorlamaz:
vi.doMock('./increment.js'); // bu, import ifadesinden _sonra_ çağrılacaktır
import { increment } from './increment.js';
export function increment(number) {
return number + 1;
}
import { beforeEach, test } from 'vitest';
import { increment } from './increment.js';
// modül taklit edilmedi, çünkü vi.doMock henüz çağrılmadı
increment(1) === 2;
let mockedIncrement = 100;
beforeEach(() => {
// bir factory içinde değişkenlere erişebilirsiniz
vi.doMock('./increment.js', () => ({ increment: () => ++mockedIncrement }));
});
test('bir sonraki modülü içe aktarmak taklit edilmiş olanı içe aktarır', async () => {
// orijinal içe aktarma TAKLİT EDİLMEDİ, çünkü vi.doMock içe aktarmalardan SONRA değerlendirilir
expect(increment(1)).toBe(2);
const { increment: mockedIncrement } = await import('./increment.js');
// yeni dinamik içe aktarma taklit edilmiş modülü döndürür
expect(mockedIncrement(1)).toBe(101);
expect(mockedIncrement(1)).toBe(102);
expect(mockedIncrement(1)).toBe(103);
});
vi.mocked
- Tip:
<T>(obj: T, deep?: boolean) => MaybeMockedDeep<T>
- Tip:
<T>(obj: T, options?: { partial?: boolean; deep?: boolean }) => MaybePartiallyMockedDeep<T>
TypeScript için bir tür yardımcı işlevidir. Yalnızca kendisine geçirilen nesneyi döndürür.
partial
true
olduğunda, dönüş değeri olarak Partial<T>
bekleyecektir. Varsayılan olarak, bu yalnızca TypeScript'in birinci seviye değerlerinin taklit edildiğini varsaymasını sağlar. Tüm nesnenin taklit edildiğini TypeScript'e bildirmek için ikinci argüman olarak { deep: true }
geçirebilirsiniz.
export function add(x: number, y: number): number {
return x + y;
}
export function fetchSomething(): Promise<Response> {
return fetch('https://vitest.dev/');
}
import * as example from './example';
vi.mock('./example');
test('1 + 1 eşittir 10', async () => {
vi.mocked(example.add).mockReturnValue(10);
expect(example.add(1, 1)).toBe(10);
});
test('yalnızca kısmen doğru yazımla dönüş değerini taklit et', async () => {
vi.mocked(example.fetchSomething).mockResolvedValue(new Response('hello'));
vi.mocked(example.fetchSomething, { partial: true }).mockResolvedValue({
ok: false,
});
// vi.mocked(example.someFn).mockResolvedValue({ ok: false }) // bu bir tip hatasıdır
});
vi.importActual
- Tip:
<T>(path: string) => Promise<T>
Modülü içe aktarır, taklit edilip edilmeyeceğiyle ilgili tüm kontrolleri atlar. Modülü kısmen taklit etmek istediğinizde faydalı olabilir.
vi.mock('./example.js', async () => {
const originalModule = await vi.importActual('./example.js');
return { ...originalModule, get: vi.fn() };
});
vi.importMock
- Tip:
<T>(path: string) => Promise<MaybeMockedDeep<T>>
Tüm özellikleriyle (iç içe geçmiş özellikler dahil) taklit edilmiş bir modülü içe aktarır. vi.mock
ile aynı kuralları izler. Uygulanan kuralları görmek için algoritma bölümüne bakın.
vi.unmock
- Tip:
(path: string | Promise<Module>) => void
Modülü taklit edilmiş kayıt defterinden kaldırır. İçe aktarma çağrılarının tümü, daha önce taklit edilmiş olsa bile orijinal modülü döndürecektir. Bu çağrı dosyanın en üstüne taşınır, bu nedenle yalnızca setupFiles
içinde tanımlanmış modüllerin taklitini kaldırır, örneğin.
vi.doUnmock
- Tip:
(path: string | Promise<Module>) => void
vi.unmock
ile aynıdır, ancak dosyanın en üstüne taşınmaz. Modülün bir sonraki içe aktarımı, taklit yerine orijinal modülü içe aktaracaktır. Bu, daha önce içe aktarılan modüllerin taklitini kaldırmaz.
export function increment(number) {
return number + 1;
}
import { increment } from './increment.js';
// increment zaten taklit edildi, çünkü vi.mock yukarı taşındı
increment(1) === 100;
// bu yukarı taşındı ve factory 1. satırdaki içe aktarmadan önce çağrıldı
vi.mock('./increment.js', () => ({ increment: () => 100 }));
// tüm çağrılar taklit edildi ve `increment` her zaman 100 döndürür
increment(1) === 100;
increment(30) === 100;
// bu yukarı taşınmadı, bu yüzden diğer içe aktarma taklit edilmemiş modülü döndürecektir
vi.doUnmock('./increment.js');
// bu hala 100 döndürüyor, çünkü `vi.doUnmock` bir modülü yeniden değerlendirmiyor
increment(1) === 100;
increment(30) === 100;
// bir sonraki içe aktarma taklit edilmedi, şimdi `increment` sayıyı + 1 döndüren orijinal işlevdir
const { increment: unmockedIncrement } = await import('./increment.js');
unmockedIncrement(1) === 2;
unmockedIncrement(30) === 31;
vi.resetModules
- Tip:
() => Vitest
Tüm modüllerin önbelleğini temizleyerek modül kayıt defterini sıfırlar. Bu, modüllerin yeniden içe aktarıldığında yeniden değerlendirilmesine olanak tanır. Üst düzey içe aktarmalar yeniden değerlendirilemez. Yerel durumun testler arasında çakıştığı modülleri izole etmek için faydalı olabilir.
import { vi } from 'vitest';
import { data } from './data.js'; // Her testten önce yeniden değerlendirilmeyecek
beforeEach(() => {
vi.resetModules();
});
test('durumu değiştir', async () => {
const mod = await import('./some/path.js'); // Yeniden değerlendirilecek
mod.changeLocalState('new value');
expect(mod.getLocalState()).toBe('new value');
});
test('modülün eski durumu var', async () => {
const mod = await import('./some/path.js'); // Yeniden değerlendirilecek
expect(mod.getLocalState()).toBe('old value');
});
WARNING
Taklit kayıt defterini sıfırlamaz. Taklit kayıt defterini temizlemek için vi.unmock
veya vi.doUnmock
kullanın.
vi.dynamicImportSettled
Tüm içe aktarmaların yüklenmesini bekler. Aksi takdirde bekleyemeyeceğiniz bir modülü içe aktarmaya başlayan eşzamanlı bir çağrınız varsa kullanışlıdır.
import { expect, test } from 'vitest';
// Promise döndürülmediği için içe aktarma izlenemiyor
function renderComponent() {
import('./component.js').then(({ render }) => {
render();
});
}
test('işlemler çözüldü', async () => {
renderComponent();
await vi.dynamicImportSettled();
expect(document.querySelector('.component')).not.toBeNull();
});
TIP
Dinamik bir içe aktarma sırasında başka bir dinamik içe aktarma başlatılırsa, bu yöntem hepsi çözülene kadar bekler.
Bu yöntem aynı zamanda, içe aktarma çözüldükten sonra bir sonraki setTimeout
işlemini de bekleyecektir, böylece tüm eşzamanlı işlemler çözüldüğünde tamamlanmış olacaktır.
İşlevleri ve Nesneleri Taklit Etme
Bu bölüm, metod mock'ları ile nasıl çalışılacağını ve çevresel ve global değişkenlerin nasıl değiştirileceğini açıklar.
vi.fn
- Tip:
(fn?: Function) => Mock
Bir işlev üzerinde bir casus (spy) oluşturur, ancak bir tane olmadan başlatılabilir. Bir işlev her çağrıldığında, çağrı argümanlarını, dönüşlerini ve örneklerini saklar. Ayrıca, yöntemlerle davranışını manipüle edebilirsiniz. Bir işlev verilmezse, çağrıldığında taklit undefined
döndürür.
const getApples = vi.fn(() => 0);
getApples();
expect(getApples).toHaveBeenCalled();
expect(getApples).toHaveReturnedWith(0);
getApples.mockReturnValueOnce(5);
const res = getApples();
expect(res).toBe(5);
expect(getApples).toHaveNthReturnedWith(2, 5);
vi.mockObject 3.2.0+
- Tip:
<T>(value: T) => MaybeMockedDeep<T>
Verilen bir nesnenin özelliklerini ve yöntemlerini, vi.mock()
'in modül dışa aktarımlarını taklit ettiği şekilde derinlemesine taklit eder. Ayrıntılar için otomatik taklit bölümüne bakın.
const original = {
simple: () => 'value',
nested: {
method: () => 'real',
},
prop: 'foo',
};
const mocked = vi.mockObject(original);
expect(mocked.simple()).toBe(undefined);
expect(mocked.nested.method()).toBe(undefined);
expect(mocked.prop).toBe('foo');
mocked.simple.mockReturnValue('mocked');
mocked.nested.method.mockReturnValue('mocked nested');
expect(mocked.simple()).toBe('mocked');
expect(mocked.nested.method()).toBe('mocked nested');
vi.isMockFunction
- Tip:
(fn: Function) => boolean
Verilen bir parametrenin bir taklit işlevi olup olmadığını kontrol eder. TypeScript kullanıyorsanız, türünü de daraltacaktır.
vi.clearAllMocks
Tüm casuslarda .mockClear()
çağırır. Bu, taklit uygulamalarını etkilemeden taklit geçmişini temizler.
vi.resetAllMocks
Tüm casuslarda .mockReset()
çağırır. Bu, taklit geçmişini temizler ve her taklitin uygulamasını orijinal haline döndürür.
vi.restoreAllMocks
Tüm casuslarda .mockRestore()
çağırır. Bu, taklit geçmişini temizler, tüm orijinal taklit uygulamalarını geri yükler ve casuslanmış nesnelerin orijinal tanımlayıcılarını geri yükler.
vi.spyOn
- Tip:
<T, K extends keyof T>(object: T, method: K, accessType?: 'get' | 'set') => MockInstance
vi.fn()
benzeri bir nesnenin bir yöntemi veya getter/setter'ı üzerinde bir casus oluşturur. Bir taklit işlevi döndürür.
let apples = 0;
const cart = {
getApples: () => 42,
};
const spy = vi.spyOn(cart, 'getApples').mockImplementation(() => apples);
apples = 1;
expect(cart.getApples()).toBe(1);
expect(spy).toHaveBeenCalled();
expect(spy).toHaveReturnedWith(1);
TIP
Açık Kaynak Yönetimi destekleyen ortamlarda, içeren bloktan çıkıldığında herhangi bir taklit edilmiş işlevde mockRestore
'u otomatik olarak çağırmak için const
yerine using
kullanabilirsiniz. Bu, casuslanmış yöntemler için özellikle faydalıdır:
it('console.log çağırır', () => {
using spy = vi.spyOn(console, 'log').mockImplementation(() => {})
debug('message')
expect(spy).toHaveBeenCalled()
})
// console.log burada geri yüklendi
TIP
Tüm yöntemleri orijinal uygulamalarına geri yüklemek için afterEach
içinde vi.restoreAllMocks
çağırabilirsiniz (veya test.restoreMocks
etkinleştirebilirsiniz). Bu, orijinal nesne tanımlayıcısını geri yükler, böylece yöntemin uygulamasını değiştiremezsiniz:
const cart = {
getApples: () => 42,
};
const spy = vi.spyOn(cart, 'getApples').mockReturnValue(10);
console.log(cart.getApples()); // 10
vi.restoreAllMocks();
console.log(cart.getApples()); // 42
spy.mockReturnValue(10);
console.log(cart.getApples()); // hala 42!
TIP
Tarayıcı Modunda dışa aktarılan yöntemleri casuslamak mümkün değildir. Bunun yerine, vi.mock("./file-path.js", { spy: true })
çağırarak her dışa aktarılan yöntemi casuslayabilirsiniz. Bu, her dışa aktarmayı taklit eder ancak uygulamasını sağlam tutar, böylece yöntemin doğru şekilde çağrılıp çağrılmadığını doğrulayabilirsiniz.
import { calculator } from './src/calculator.ts';
vi.mock('./src/calculator.ts', { spy: true });
calculator(1, 2);
expect(calculator).toHaveBeenCalledWith(1, 2);
expect(calculator).toHaveReturned(3);
Ve jsdom
veya diğer Node.js ortamlarında dışa aktarımları casuslamak mümkün olsa da, bu gelecekte değişebilir.
vi.stubEnv
- Tip:
<T extends string>(name: T, value: T extends "PROD" | "DEV" | "SSR" ? boolean : string | undefined) => Vitest
process.env
ve import.meta.env
üzerindeki çevresel değişkenin değerini değiştirir. Değerini vi.unstubAllEnvs
çağırarak geri yükleyebilirsiniz.
import { vi } from 'vitest';
// `process.env.NODE_ENV` ve `import.meta.env.NODE_ENV`
// "vi.stubEnv" çağrılmadan önce "development" idi
vi.stubEnv('NODE_ENV', 'production');
process.env.NODE_ENV === 'production';
import.meta.env.NODE_ENV === 'production';
vi.stubEnv('NODE_ENV', undefined);
process.env.NODE_ENV === undefined;
import.meta.env.NODE_ENV === undefined;
// diğer ortamları değiştirmez
import.meta.env.MODE === 'development';
TIP
Değeri basitçe atayarak da değiştirebilirsiniz, ancak önceki değeri geri yüklemek için vi.unstubAllEnvs
kullanamazsınız:
import.meta.env.MODE = 'test';
vi.unstubAllEnvs
- Tip:
() => Vitest
vi.stubEnv
ile değiştirilen tüm import.meta.env
ve process.env
değerlerini geri yükler. İlk kez çağrıldığında, Vitest orijinal değeri hatırlar ve unstubAllEnvs
tekrar çağrılana kadar saklayacaktır.
import { vi } from 'vitest';
// `process.env.NODE_ENV` ve `import.meta.env.NODE_ENV`
// stubEnv çağrılmadan önce "development" idi
vi.stubEnv('NODE_ENV', 'production');
process.env.NODE_ENV === 'production';
import.meta.env.NODE_ENV === 'production';
vi.stubEnv('NODE_ENV', 'staging');
process.env.NODE_ENV === 'staging';
import.meta.env.NODE_ENV === 'staging';
vi.unstubAllEnvs();
// ilk "stubEnv" çağrısından önce saklanan değere geri yükler
process.env.NODE_ENV === 'development';
import.meta.env.NODE_ENV === 'development';
vi.stubGlobal
- Tip:
(name: string | number | symbol, value: unknown) => Vitest
Global değişkenin değerini değiştirir. Orijinal değerini vi.unstubAllGlobals
çağırarak geri yükleyebilirsiniz.
import { vi } from 'vitest';
// `innerWidth` stubGlobal çağrılmadan önce "0" idi
vi.stubGlobal('innerWidth', 100);
innerWidth === 100;
globalThis.innerWidth === 100;
// jsdom veya happy-dom kullanıyorsanız
window.innerWidth === 100;
TIP
Değeri basitçe globalThis
veya window
'a (eğer jsdom
veya happy-dom
ortamı kullanıyorsanız) atayarak da değiştirebilirsiniz, ancak orijinal değeri geri yüklemek için vi.unstubAllGlobals
kullanamazsınız:
globalThis.innerWidth = 100;
// jsdom veya happy-dom kullanıyorsanız
window.innerWidth = 100;
vi.unstubAllGlobals
- Tip:
() => Vitest
vi.stubGlobal
ile değiştirilen globalThis
/global
(ve window
/top
/self
/parent
, eğer jsdom
veya happy-dom
ortamı kullanıyorsanız) üzerindeki tüm global değerleri geri yükler. İlk kez çağrıldığında, Vitest orijinal değeri hatırlar ve unstubAllGlobals
tekrar çağrılana kadar saklayacaktır.
import { vi } from 'vitest';
const Mock = vi.fn();
// IntersectionObserver "stubGlobal" çağrılmadan önce "undefined" idi
vi.stubGlobal('IntersectionObserver', Mock);
IntersectionObserver === Mock;
global.IntersectionObserver === Mock;
globalThis.IntersectionObserver === Mock;
// jsdom veya happy-dom kullanıyorsanız
window.IntersectionObserver === Mock;
vi.unstubAllGlobals();
globalThis.IntersectionObserver === undefined;
'IntersectionObserver' in globalThis === false;
// tanımlı olmadığı için ReferenceError fırlatır
IntersectionObserver === undefined;
Sahte Zamanlayıcılar
Bu bölüm, sahte zamanlayıcılarla nasıl çalışılacağını açıklar.
vi.advanceTimersByTime
- Tip:
(ms: number) => Vitest
Bu yöntem, belirtilen milisaniye sayısı geçene veya kuyruk boşalana kadar (hangisi önce gelirse) başlatılan her zamanlayıcıyı çağırır.
let i = 0;
setInterval(() => console.log(++i), 50);
vi.advanceTimersByTime(150);
// log: 1
// log: 2
// log: 3
vi.advanceTimersByTimeAsync
- Tip:
(ms: number) => Promise<Vitest>
Bu yöntem, belirtilen milisaniye sayısı geçene veya kuyruk boşalana kadar (hangisi önce gelirse) başlatılan her zamanlayıcıyı çağırır. Bu, asenkron olarak ayarlanmış zamanlayıcıları da içerir.
let i = 0;
setInterval(() => Promise.resolve().then(() => console.log(++i)), 50);
await vi.advanceTimersByTimeAsync(150);
// log: 1
// log: 2
// log: 3
vi.advanceTimersToNextTimer
- Tip:
() => Vitest
Bir sonraki kullanılabilir zamanlayıcıyı çağırır. Her zamanlayıcı çağrısı arasında doğrulama yapmak için faydalıdır. Zamanlayıcıları kendiniz yönetmek için zincirleme çağrılar yapabilirsiniz.
let i = 0;
setInterval(() => console.log(++i), 50);
vi.advanceTimersToNextTimer() // log: 1
.advanceTimersToNextTimer() // log: 2
.advanceTimersToNextTimer(); // log: 3
vi.advanceTimersToNextTimerAsync
- Tip:
() => Promise<Vitest>
Bir sonraki kullanılabilir zamanlayıcıyı çağırır ve asenkron olarak ayarlanmışsa çözülene kadar bekler. Her zamanlayıcı çağrısı arasında doğrulama yapmak için faydalıdır.
let i = 0;
setInterval(() => Promise.resolve().then(() => console.log(++i)), 50);
await vi.advanceTimersToNextTimerAsync(); // log: 1
expect(console.log).toHaveBeenCalledWith(1);
await vi.advanceTimersToNextTimerAsync(); // log: 2
await vi.advanceTimersToNextTimerAsync(); // log: 3
vi.advanceTimersToNextFrame 2.1.0+
- Tip:
() => Vitest
vi.advanceTimersByTime
benzeridir, ancak requestAnimationFrame
ile şu anda zamanlanmış geri aramaları yürütmek için gereken milisaniye kadar zamanlayıcıları ilerletir.
let frameRendered = false;
requestAnimationFrame(() => {
frameRendered = true;
});
vi.advanceTimersToNextFrame();
expect(frameRendered).toBe(true);
vi.getTimerCount
- Tip:
() => number
Bekleyen zamanlayıcı sayısını alın.
vi.clearAllTimers
Çalıştırılması planlanan tüm zamanlayıcıları kaldırır. Bu zamanlayıcılar gelecekte asla çalışmaz.
vi.getMockedSystemTime
- Tip:
() => Date | null
Taklit edilmiş geçerli tarihi döndürür. Tarih taklit edilmemişse yöntem null
döndürür.
vi.getRealSystemTime
- Tip:
() => number
vi.useFakeTimers
kullanıldığında, Date.now
çağrıları taklit edilir. Milisaniye cinsinden gerçek zamanı almanız gerekiyorsa, bu işlevi çağırabilirsiniz.
vi.runAllTicks
- Tip:
() => Vitest
process.nextTick
tarafından kuyruğa alınan her mikro görevi çağırır. Bu, kendi kendine zamanlanmış tüm mikro görevleri de çalıştırır.
vi.runAllTimers
- Tip:
() => Vitest
Bu yöntem, zamanlayıcı kuyruğu boşalana kadar başlatılan her zamanlayıcıyı çağırır. Bu, runAllTimers
sırasında çağrılan her zamanlayıcının tetikleneceği demektir. Sonsuz bir aralığınız varsa, 10.000 denemeden sonra bir hata atacaktır ( fakeTimers.loopLimit
ile yapılandırılabilir).
let i = 0;
setTimeout(() => console.log(++i));
const interval = setInterval(() => {
console.log(++i);
if (i === 3) {
clearInterval(interval);
}
}, 50);
vi.runAllTimers();
// log: 1
// log: 2
// log: 3
vi.runAllTimersAsync
- Tip:
() => Promise<Vitest>
Bu yöntem, zamanlayıcı kuyruğu boşalana kadar başlatılan her zamanlayıcıyı asenkron olarak çağırır. Bu, runAllTimersAsync
sırasında çağrılan her zamanlayıcının, asenkron zamanlayıcılar bile olsa, tetikleneceği demektir. Sonsuz bir aralığınız varsa, 10.000 denemeden sonra bir hata atacaktır ( fakeTimers.loopLimit
ile yapılandırılabilir).
setTimeout(async () => {
console.log(await Promise.resolve('result'));
}, 100);
await vi.runAllTimersAsync();
// log: result
vi.runOnlyPendingTimers
- Tip:
() => Vitest
Bu yöntem, vi.useFakeTimers
çağrısından sonra başlatılan her zamanlayıcıyı çağırır. Çağrısı sırasında başlatılan hiçbir zamanlayıcıyı tetiklemez.
let i = 0;
setInterval(() => console.log(++i), 50);
vi.runOnlyPendingTimers();
// log: 1
vi.runOnlyPendingTimersAsync
- Tip:
() => Promise<Vitest>
Bu yöntem, vi.useFakeTimers
çağrısından sonra başlatılan her zamanlayıcıyı, asenkron olanlar bile olsa, asenkron olarak çağırır. Çağrısı sırasında başlatılan hiçbir zamanlayıcıyı tetiklemez.
setTimeout(() => {
console.log(1);
}, 100);
setTimeout(() => {
Promise.resolve().then(() => {
console.log(2);
setInterval(() => {
console.log(3);
}, 40);
});
}, 10);
await vi.runOnlyPendingTimersAsync();
// log: 2
// log: 3
// log: 3
// log: 1
vi.setSystemTime
- Tip:
(date: string | number | Date) => void
Sahte zamanlayıcılar etkinse, bu yöntem kullanıcının sistem saatini değiştirmesini simüle eder ( hrtime
, performance.now
veya new Date()
gibi tarihle ilgili API'leri etkiler) - ancak hiçbir zamanlayıcıyı tetiklemez. Sahte zamanlayıcılar etkin değilse, bu yöntem yalnızca Date.*
çağrılarını taklit eder.
Geçerli tarihe bağlı herhangi bir şeyi test etmeniz gerekiyorsa faydalıdır - örneğin kodunuzdaki Luxon çağrıları.
Date
ile aynı dize ve sayı argümanlarını kabul eder.
const date = new Date(1998, 11, 19);
vi.useFakeTimers();
vi.setSystemTime(date);
expect(Date.now()).toBe(date.valueOf());
vi.useRealTimers();
vi.useFakeTimers
- Tip:
(config?: FakeTimerInstallOpts) => Vitest
Zamanlayıcıları taklit etmeyi etkinleştirmek için bu yöntemi çağırmalısınız. vi.useRealTimers()
çağrılana kadar tüm sonraki zamanlayıcı çağrılarını ( setTimeout
, setInterval
, clearTimeout
, clearInterval
, setImmediate
, clearImmediate
ve Date
gibi) sarar.
--pool=forks
kullanarak Vitest'i node:child_process
içinde çalıştırırken nextTick
'i taklit etmek desteklenmemektedir. NodeJS, node:child_process
içinde dahili olarak process.nextTick
kullanır ve taklit edildiğinde donar. nextTick
'i taklit etmek, Vitest'i --pool=threads
ile çalıştırırken desteklenir.
Uygulama dahili olarak @sinonjs/fake-timers
üzerine kuruludur.
TIP
vi.useFakeTimers()
otomatik olarak process.nextTick
ve queueMicrotask
'i taklit etmez. Ancak, toFake
argümanında seçeneği belirterek etkinleştirebilirsiniz: vi.useFakeTimers({ toFake: ['nextTick', 'queueMicrotask'] })
.
vi.isFakeTimers
- Tip:
() => boolean
Sahte zamanlayıcılar etkinse true
döndürür.
vi.useRealTimers
- Tip:
() => Vitest
Zamanlayıcılar bittiğinde, taklit edilmiş zamanlayıcıları orijinal uygulamalarına geri döndürmek için bu yöntemi çağırabilirsiniz. Daha önce zamanlanmış tüm zamanlayıcılar atılır.
Çeşitli
Vitest'in sağladığı bir dizi kullanışlı yardımcı işlev.
vi.waitFor
- Tip:
<T>(callback: WaitForCallback<T>, options?: number | WaitForOptions) => Promise<T>
Geri aramanın başarıyla yürütülmesini bekler. Geri arama bir hata fırlatırsa veya reddedilmiş bir söz döndürürse, başarılı olana veya zaman aşımına uğrayana kadar beklemeye devam eder.
Seçenekler bir sayıya ayarlanırsa, etkisi { timeout: options }
ayarlamakla aynıdır.
Bu, bazı asenkron eylemlerin tamamlanmasını beklemeniz gerektiğinde oldukça faydalıdır, örneğin bir sunucu başlattığınızda ve başlamasını beklemeniz gerektiğinde.
import { expect, test, vi } from 'vitest';
import { createServer } from './server.js';
test('Sunucu başarıyla başlatıldı', async () => {
const server = createServer();
await vi.waitFor(
() => {
if (!server.isReady) {
throw new Error('Sunucu başlatılmadı');
}
console.log('Sunucu başlatıldı');
},
{
timeout: 500, // varsayılan 1000
interval: 20, // varsayılan 50
}
);
expect(server.isReady).toBe(true);
});
Asenkron geri aramalar için de çalışır
// @vitest-environment jsdom
import { expect, test, vi } from 'vitest';
import { getDOMElementAsync, populateDOMAsync } from './dom.js';
test('Öğe DOM\'da mevcut', async () => {
// DOM'u doldurmaya başla
populateDOMAsync();
const element = await vi.waitFor(
async () => {
// öğe mevcut olana kadar almaya çalış
const element = (await getDOMElementAsync()) as HTMLElement | null;
expect(element).toBeTruthy();
expect(element.dataset.initialized).toBeTruthy();
return element;
},
{
timeout: 500, // varsayılan 1000
interval: 20, // varsayılan 50
}
);
expect(element).toBeInstanceOf(HTMLElement);
});
vi.useFakeTimers
kullanılırsa, vi.waitFor
her kontrol geri aramasında otomatik olarak vi.advanceTimersByTime(interval)
çağırır.
vi.waitUntil
- Tip:
<T>(callback: WaitUntilCallback<T>, options?: number | WaitUntilOptions) => Promise<T>
Bu, vi.waitFor
'a benzer, ancak geri arama herhangi bir hata fırlatırsa, yürütme hemen kesilir ve bir hata mesajı alırsınız. Geri arama yanlış bir değer döndürürse, bir sonraki kontrol doğru bir değer döndürülene kadar devam eder. Bu, bir şeyin var olmasını bekledikten sonra bir sonraki adımı atmanız gerektiğinde faydalıdır.
Aşağıdaki örneğe bakın. Öğenin sayfada görünmesini beklemek için vi.waitUntil
kullanabiliriz ve ardından öğeyle bir şeyler yapabiliriz.
import { expect, test, vi } from 'vitest';
test('Öğe doğru şekilde render edildi', async () => {
const element = await vi.waitUntil(() => document.querySelector('.element'), {
timeout: 500, // varsayılan 1000
interval: 20, // varsayılan 50
});
// öğeyle bir şeyler yap
expect(element.querySelector('.element-child')).toBeTruthy();
});
vi.hoisted
- Tip:
<T>(factory: () => T) => T
ES modüllerindeki tüm statik import
ifadeleri dosyanın en üstüne taşınır, bu nedenle içe aktarmalardan önce tanımlanan herhangi bir kod aslında içe aktarmalar değerlendirildikten sonra yürütülür.
Ancak, bir modülü içe aktarmadan önce tarihleri taklit etmek gibi bazı yan etkileri çağırmak yararlı olabilir.
Bu sınırlamayı aşmak için, statik içe aktarmaları dinamik olanlara şu şekilde yeniden yazabilirsiniz:
callFunctionWithSideEffect()
- import { value } from './some/module.js'
+ const { value } = await import('./some/module.js')
vitest
çalıştırırken, bunu vi.hoisted
yöntemini kullanarak otomatik olarak yapabilirsiniz. Dahili olarak, Vitest statik içe aktarmaları, canlı bağlamaları korunmuş dinamik olanlara dönüştürür.
- callFunctionWithSideEffect()
import { value } from './some/module.js'
+ vi.hoisted(() => callFunctionWithSideEffect())
İÇE AKTARMALAR KULLANILAMAZ
İçe aktarmalardan önce kod çalıştırmak, içe aktarılan değişkenlere erişemeyeceğiniz anlamına gelir, çünkü henüz tanımlı değillerdir:
import { value } from './some/module.js';
vi.hoisted(() => { value }); // hata fırlatır
Bu kod bir hata üretir:
'__vi_import_0__' başlatılmadan önce erişilemez
vi.hoisted
içinde başka bir modülden bir değişkene erişmeniz gerekiyorsa, dinamik içe aktarma kullanın:
await vi.hoisted(async () => {
const { value } = await import('./some/module.js');
});
Ancak, vi.hoisted
içinde herhangi bir şeyi içe aktarmak tavsiye edilmez, çünkü içe aktarmalar zaten en üste taşınmıştır - testler çalışmadan önce bir şey yürütmeniz gerekiyorsa, onu doğrudan içe aktarılan modülün kendisinde yürütün.
Bu yöntem, factory'den dönen değeri verir. Yerel olarak tanımlanmış değişkenlere kolayca erişmeniz gerekiyorsa, bu değeri vi.mock
factory'lerinizde kullanabilirsiniz:
import { expect, vi } from 'vitest';
import { originalMethod } from './path/to/module.js';
const { mockedMethod } = vi.hoisted(() => {
return { mockedMethod: vi.fn() };
});
vi.mock('./path/to/module.js', () => {
return { originalMethod: mockedMethod };
});
mockedMethod.mockReturnValue(100);
expect(originalMethod()).toBe(100);
Bu yöntemin, ortamınız üst düzey await'i desteklemese bile asenkron olarak da çağrılabileceğini lütfen aklınızda bulundurun:
const json = await vi.hoisted(async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
return response.json();
});
vi.setConfig
- Tip:
RuntimeConfig
Geçerli test dosyası için yapılandırmayı günceller. Bu yöntem yalnızca geçerli test dosyasını etkileyecek yapılandırma seçeneklerini destekler:
vi.setConfig({
allowOnly: true,
testTimeout: 10_000,
hookTimeout: 10_000,
clearMocks: true,
restoreMocks: true,
fakeTimers: {
now: new Date(2021, 11, 19),
// tüm nesneyi destekler
},
maxConcurrency: 10,
sequence: {
hooks: 'stack',
// yalnızca "sequence.hooks" destekler
},
});
vi.resetConfig
- Tip:
RuntimeConfig
Daha önce vi.setConfig
çağrıldıysa, bu, yapılandırmayı orijinal durumuna sıfırlar.