Vi
Vitest は、vi
ヘルパーを通じて、テストを支援するためのユーティリティ関数を提供しています。globals configurationが有効になっている場合は、グローバルにアクセスするか、vitest
から直接インポートできます。
import { vi } from 'vitest';
モジュールをモックする
このセクションでは、モジュールをモックする際に使用できる API について説明します。Vitest は require()
でインポートされたモジュールのモックをサポートしていないことに注意してください。
vi.mock
- 型:
(path: string, factory?: (importOriginal: () => unknown) => unknown) => void
指定された path
からインポートされるすべてのモジュールを、別のモジュールで置き換えます。パスには設定済みの Vite エイリアスを使用できます。vi.mock
の呼び出しは巻き上げ(hoisted)られるため、どこで呼び出しても問題ありません。常にすべてのインポートの前に実行されます。スコープ外の変数を参照したい場合は、vi.hoisted
内で定義し、vi.mock
内で参照してください。
WARNING
vi.mock
は、import
キーワードでインポートされたモジュールに対してのみ機能します。require
では動作しません。
vi.mock
を巻き上げるために、Vitest はファイルを静的に解析します。そのため、vitest
パッケージから直接インポートされなかった vi
(例えば、ユーティリティファイルからインポートされた場合など)は使用できません。vitest
からインポートされた vi
で vi.mock
を使用するか、globals
設定オプションを有効にしてください。
Vitest は、セットアップファイル 内でインポートされたモジュールをモックしないことに注意してください。これは、テストファイルが実行されるまでにキャッシュされるためです。テストファイルの実行前にすべてのモジュールキャッシュをクリアするには、vi.hoisted
内で vi.resetModules()
を呼び出すことができます。
factory
が定義されている場合、以降のすべてのインポートはその結果を返します。Vitest はファクトリを一度だけ呼び出し、vi.unmock
または vi.doUnmock
が呼び出されるまで、後続のすべてのインポートの結果をキャッシュします。
jest
と異なり、ファクトリは非同期にできます。vi.importActual
またはヘルパーを、最初の引数として渡されたファクトリとともに使用して、元のモジュールを内部で取得できます。
import { vi } from 'vitest';
// ---cut---
// JavaScript を使用する場合
vi.mock('./path/to/module.js', async importOriginal => {
const mod = await importOriginal();
return {
...mod,
// いくつかのエクスポートを置き換える
namedExport: vi.fn(),
};
});
// TypeScript を使用する場合
vi.mock('./path/to/module.js', async importOriginal => {
const mod = await importOriginal<typeof import('./path/to/module.js')>();
return {
...mod,
// いくつかのエクスポートを置き換える
namedExport: vi.fn(),
};
});
WARNING
vi.mock
は、ファイルの先頭に移動(巻き上げ)されます。つまり、コード内のどこに記述しても(beforeEach
または test
の内部であっても)、実際にはその前に呼び出されます。
これは、ファクトリの外で定義された変数を、ファクトリの中で使用できないことも意味します。
ファクトリ内で変数を使用する必要がある場合は、vi.doMock
を試してください。これは同じように機能しますが、巻き上げられません。ただし、後続のインポートのみをモックすることに注意してください。
vi.mock
の前に宣言されている場合は、vi.hoisted
メソッドで定義された変数を参照することもできます。
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
デフォルトエクスポートを持つモジュールをモックする場合、返されるファクトリ関数のオブジェクト内に default
キーを含める必要があります。これは ES モジュール特有の注意点です。jest
は CommonJS モジュールを使用するため、jest
のドキュメントとは異なる場合があります。例えば、
vi.mock('./path/to/module.js', () => {
return {
default: { myDefaultKey: vi.fn() },
namedExport: vi.fn(),
// など...
};
});
モック対象のファイルと同じ階層に __mocks__
フォルダがあり、ファクトリが提供されていない場合、Vitest は __mocks__
サブフォルダに同じ名前のファイルを見つけて、モジュールとして使用しようとします。依存関係をモックしている場合、Vitest はプロジェクトの root(デフォルトは process.cwd()
)に __mocks__
フォルダを見つけようとします。 deps.moduleDirectories 設定オプションを使用して、依存関係の場所を Vitest に伝えることができます。
たとえば、次のファイル構造があるとします。
- __mocks__
- axios.js
- src
__mocks__
- increment.js
- increment.js
- tests
- increment.test.js
ファクトリが提供されていないテストファイルで vi.mock
を呼び出すと、モジュールとして使用する __mocks__
フォルダ内のファイルが見つかります。
// increment.test.js
import { vi } from 'vitest';
// axios は `__mocks__/axios.js` からのデフォルトエクスポートです
import axios from 'axios';
// increment は `src/__mocks__/increment.js` からの名前付きエクスポートです
import { increment } from '../increment.js';
vi.mock('axios');
vi.mock('../increment.js');
axios.get(`/apples/${increment(1)}`);
WARNING
vi.mock
を呼び出さない限り、モジュールは自動的にモックされないことに注意してください。Jest の自動モックの動作を再現するには、setupFiles
内の必要な各モジュールに対して vi.mock
を呼び出すことができます。
__mocks__
フォルダがない場合、またはファクトリが提供されている場合、Vitest は元のモジュールをインポートし、そのすべてのエクスポートを自動的にモックします。適用されるルールについては、アルゴリズム を参照してください。
vi.doMock
- 型:
(path: string, factory?: (importOriginal: () => unknown) => unknown) => void
vi.mock
と同じですが、ファイルの先頭に巻き上げられないため、グローバルファイルスコープ内の変数を参照できます。モジュールの次の 動的インポート がモックされます。
WARNING
これは、呼び出される前にインポートされたモジュールをモックしません。ESM のすべての静的インポートは常に 巻き上げられる ことを忘れないでください。したがって、静的インポートの前にこれを記述しても、インポートの前に呼び出されるわけではありません。
vi.doMock('./increment.js'); // これは import ステートメントの _後_ に呼び出されます
import { increment } from './increment.js';
// ./increment.js
export function increment(number) {
return number + 1;
}
import { beforeEach, test } from 'vitest';
import { increment } from './increment.js';
// vi.doMock がまだ呼び出されていないため、モジュールはモックされていません
increment(1) === 2;
let mockedIncrement = 100;
beforeEach(() => {
// ファクトリ内の変数にアクセスできます
vi.doMock('./increment.js', () => ({ increment: () => ++mockedIncrement }));
});
test('次のモジュールをインポートすると、モックされたモジュールがインポートされます', async () => {
// 元のインポートはモックされませんでした。vi.doMock はインポート後に評価されるためです
expect(increment(1)).toBe(2);
const { increment: mockedIncrement } = await import('./increment.js');
// 新しい動的インポートはモックされたモジュールを返します
expect(mockedIncrement(1)).toBe(101);
expect(mockedIncrement(1)).toBe(102);
expect(mockedIncrement(1)).toBe(103);
});
vi.mocked
- 型:
<T>(obj: T, deep?: boolean) => MaybeMockedDeep<T>
- 型:
<T>(obj: T, options?: { partial?: boolean; deep?: boolean }) => MaybePartiallyMockedDeep<T>
TypeScript の型ヘルパーです。渡されたオブジェクトをそのまま返します。
partial
が true
の場合、戻り値として Partial<T>
が期待されます。デフォルトでは、これにより、TypeScript は最初のレベルの値がモックされていると認識するだけです。オブジェクト全体がモックされていることを TypeScript に伝えるには、2 番目の引数として { deep: true }
を渡すことができます(実際にモックされている場合)。
import example from './example.js';
vi.mock('./example.js');
test('1 + 1 は 10 に等しい', async () => {
vi.mocked(example.calc).mockReturnValue(10);
expect(example.calc(1, '+', 1)).toBe(10);
});
vi.importActual
- 型:
<T>(path: string) => Promise<T>
モジュールをインポートし、モックする必要があるかどうかのすべてのチェックをバイパスします。モジュールを部分的にモックする場合に役立ちます。
vi.mock('./example.js', async () => {
const axios = await vi.importActual('./example.js');
return { ...axios, get: vi.fn() };
});
vi.importMock
- 型:
<T>(path: string) => Promise<MaybeMockedDeep<T>>
すべてのプロパティ(ネストされたプロパティを含む)がモックされたモジュールをインポートします。vi.mock
と同じルールに従います。適用されるルールについては、アルゴリズム を参照してください。
vi.unmock
- 型:
(path: string) => void
モックされたモジュールをレジストリから削除します。インポートの呼び出しはすべて、以前にモックされていたとしても、元のモジュールを返します。この呼び出しはファイルの先頭に巻き上げられるため、たとえば setupFiles
で定義されたモジュールのみをアンモックします。
vi.doUnmock
- 型:
(path: string) => void
vi.unmock
と同じですが、ファイルの先頭に巻き上げられません。モジュールの次のインポートは、モックの代わりに元のモジュールをインポートします。これは、以前にインポートされたモジュールをアンモックしません。
// ./increment.js
export function increment(number) {
return number + 1;
}
import { increment } from './increment.js';
// vi.mock が巻き上げられるため、increment はすでにモックされています
increment(1) === 100;
// これは巻き上げられ、ファクトリは 1 行目のインポートの前に呼び出されます
vi.mock('./increment.js', () => ({ increment: () => 100 }));
// すべての呼び出しがモックされ、`increment` は常に 100 を返します
increment(1) === 100;
increment(30) === 100;
// これは巻き上げられないため、他のインポートはアンモックされたモジュールを返します
vi.doUnmock('./increment.js');
// これはまだ 100 を返します。`vi.doUnmock` はモジュールを再評価しないためです
increment(1) === 100;
increment(30) === 100;
// 次のインポートはアンモックされ、`increment` はカウント + 1 を返す元の関数になりました
const { increment: unmockedIncrement } = await import('./increment.js');
unmockedIncrement(1) === 2;
unmockedIncrement(30) === 31;
vi.resetModules
- 型:
() => Vitest
すべてのモジュールのキャッシュをクリアし、モジュールレジストリをリセットします。これにより、再インポート時にモジュールを再評価できます。トップレベルのインポートは再評価できません。テスト間でローカルな状態が競合するモジュールを分離する際に役立つことがあります。
import { vi } from 'vitest';
import { data } from './data.js'; // beforeEach テストで再評価されません
beforeEach(() => {
vi.resetModules();
});
test('状態を変更する', async () => {
const mod = await import('./some/path.js'); // 再評価されます
mod.changeLocalState('new value');
expect(mod.getLocalState()).toBe('new value');
});
test('モジュールに古い状態がある', async () => {
const mod = await import('./some/path.js'); // 再評価されます
expect(mod.getLocalState()).toBe('old value');
});
WARNING
モックレジストリはリセットされません。モックレジストリをクリアするには、vi.unmock
または vi.doUnmock
を使用します。
vi.dynamicImportSettled
すべてのインポートがロードされるのを待ちます。通常は待機できないモジュールのインポートを開始する同期的な呼び出しがある場合に役立ちます。
import { expect, test } from 'vitest';
// Promise が返されないため、インポートを追跡できません
function renderComponent() {
import('./component.js').then(({ render }) => {
render();
});
}
test('操作が解決される', async () => {
renderComponent();
await vi.dynamicImportSettled();
expect(document.querySelector('.component')).not.toBeNull();
});
TIP
動的インポート中に別の動的インポートが開始された場合、このメソッドはそれらすべてが解決されるまで待機します。
このメソッドは、インポートが解決された後の次の setTimeout
ティックも待機するため、すべての同期操作は解決されるまでに完了しているはずです。
関数とオブジェクトのモック
このセクションでは、メソッドモック の操作方法と、環境変数とグローバル変数の置き換え方法について説明します。
vi.fn
- 型:
(fn?: Function) => Mock
関数のスパイを作成します。関数を指定せずに作成することも可能です。関数が呼び出されるたびに、その呼び出し引数、戻り値、およびインスタンスが保存されます。また、メソッド でその動作を操作することもできます。関数が指定されていない場合、モックは呼び出されると undefined
を返します。
import { expect, vi } from 'vitest';
// ---cut---
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.isMockFunction
- 型:
(fn: Function) => boolean
指定されたパラメータがモック関数かどうかを確認します。TypeScript を使用している場合は、その型も絞り込みます。
vi.clearAllMocks
すべてのスパイで .mockClear()
を呼び出します。これにより、モックの履歴はクリアされますが、その実装はデフォルトの実装にリセットされません。
vi.resetAllMocks
すべてのスパイで .mockReset()
を呼び出します。これにより、モックの履歴がクリアされ、その実装が空の関数にリセットされます(undefined
を返します)。
vi.restoreAllMocks
すべてのスパイで .mockRestore()
を呼び出します。これにより、モックの履歴がクリアされ、その実装が元の実装にリセットされます。
vi.spyOn
- 型:
<T, K extends keyof T>(object: T, method: K, accessType?: 'get' | 'set') => MockInstance
vi.fn()
と同様に、オブジェクトのメソッドまたはゲッター/セッターに対するスパイを作成します。モック関数 を返します。
import { expect, vi } from 'vitest';
// ---cut---
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
afterEach
内で vi.restoreAllMocks
を呼び出す(または test.restoreMocks
を有効にする)と、すべてのメソッドが元の実装に復元されます。これにより、元の オブジェクト記述子 が復元されるため、メソッドの実装を変更できなくなります。
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()); // まだ 42!
vi.stubEnv 0.26.0+
- 型:
(name: string, value: string) => Vitest
process.env
および import.meta.env
の環境変数の値を変更します。vi.unstubAllEnvs
を呼び出すことで、その値を復元できます。
import { vi } from 'vitest';
// "vi.stubEnv" を呼び出す前は、`process.env.NODE_ENV` と `import.meta.env.NODE_ENV` は "development" です
vi.stubEnv('NODE_ENV', 'production');
process.env.NODE_ENV === 'production';
import.meta.env.NODE_ENV === 'production';
// 他の env は変更されません
import.meta.env.MODE === 'development';
TIP
値を単純に割り当てることによって変更することもできますが、vi.unstubAllEnvs
を使用して以前の値を復元することはできません。
import.meta.env.MODE = 'test';
vi.unstubAllEnvs 0.26.0+
- 型:
() => Vitest
vi.stubEnv
で変更されたすべての import.meta.env
および process.env
の値を復元します。最初に呼び出された際、Vitest は元の値を記憶し、unstubAllEnvs
が再度呼び出されるまでその値を保持します。
import { vi } from 'vitest';
// stubEnv を呼び出す前は、`process.env.NODE_ENV` と `import.meta.env.NODE_ENV` は "development" です
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();
// 最初の "stubEnv" 呼び出しの前に保存された値に復元します
process.env.NODE_ENV === 'development';
import.meta.env.NODE_ENV === 'development';
vi.stubGlobal
- 型:
(name: string | number | symbol, value: unknown) => Vitest
グローバル変数の値を変更します。vi.unstubAllGlobals
を呼び出すことで、元の値を復元できます。
import { vi } from 'vitest';
// stubGlobal を呼び出す前は、`innerWidth` は "0" です
vi.stubGlobal('innerWidth', 100);
innerWidth === 100;
globalThis.innerWidth === 100;
// jsdom または happy-dom を使用している場合
window.innerWidth === 100;
TIP
値を直接割り当てることでも変更できますが、その場合、vi.unstubAllGlobals
を使って元の値を復元することはできません。
globalThis.innerWidth = 100;
// jsdom または happy-dom を使用している場合
window.innerWidth = 100;
vi.unstubAllGlobals 0.26.0+
- 型:
() => Vitest
vi.stubGlobal
で変更された globalThis
/global
(および window
/top
/self
/parent
(jsdom
または happy-dom
環境を使用している場合))のすべてのグローバル値を復元します。最初に呼び出された際、Vitest は元の値を記憶し、unstubAllGlobals
が再度呼び出されるまでその値を保持します。
import { vi } from 'vitest';
const Mock = vi.fn();
// "stubGlobal" を呼び出す前は、IntersectionObserver は "undefined" です
vi.stubGlobal('IntersectionObserver', Mock);
IntersectionObserver === Mock;
global.IntersectionObserver === Mock;
globalThis.IntersectionObserver === Mock;
// jsdom または happy-dom を使用している場合
window.IntersectionObserver === Mock;
vi.unstubAllGlobals();
globalThis.IntersectionObserver === undefined;
'IntersectionObserver' in globalThis === false;
// ReferenceError がスローされます。定義されていないためです
IntersectionObserver === undefined;
偽のタイマー
このセクションでは、偽のタイマーの使い方について説明します。
vi.advanceTimersByTime
- 型:
(ms: number) => Vitest
このメソッドは、指定されたミリ秒数が経過するか、タイマーキューが空になるかのいずれか早い方まで、開始済みのすべてのタイマーを実行します。
import { vi } from 'vitest';
// ---cut---
let i = 0;
setInterval(() => console.log(++i), 50);
vi.advanceTimersByTime(150);
// log: 1
// log: 2
// log: 3
vi.advanceTimersByTimeAsync
- 型:
(ms: number) => Promise<Vitest>
このメソッドは、指定されたミリ秒数が経過するか、タイマーキューが空になるかのいずれか早い方まで、開始済みのすべてのタイマーを実行します。非同期タイマーも含まれます。
import { vi } from 'vitest';
// ---cut---
let i = 0;
setInterval(() => Promise.resolve().then(() => console.log(++i)), 50);
await vi.advanceTimersByTimeAsync(150);
// log: 1
// log: 2
// log: 3
vi.advanceTimersToNextTimer
- 型:
() => Vitest
次に実行される予定のタイマーを 1 つ実行します。各タイマーの実行後にアサーションを行う場合に便利です。メソッドチェーンで呼び出すことで、タイマーの実行を細かく制御できます。
import { vi } from 'vitest';
// ---cut---
let i = 0;
setInterval(() => console.log(++i), 50);
vi.advanceTimersToNextTimer() // log: 1
.advanceTimersToNextTimer() // log: 2
.advanceTimersToNextTimer(); // log: 3
vi.advanceTimersToNextTimerAsync
- 型:
() => Promise<Vitest>
次に実行される予定のタイマーを 1 つ実行し、非同期的に設定されている場合は、その完了を待ちます。各タイマーの実行後にアサーションを行う場合に便利です。
import { expect, vi } from 'vitest';
// ---cut---
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.getTimerCount
- 型:
() => number
現在、実行待ちのタイマーの数を取得します。
vi.clearAllTimers
実行がスケジュールされているすべてのタイマーをクリアします。これらのタイマーは実行されなくなります。
vi.getMockedSystemTime
- 型:
() => Date | null
setSystemTime
を使用して設定された、モックされた現在の日時を返します。日付がモックされていない場合、このメソッドは null
を返します。
vi.getRealSystemTime
- 型:
() => number
vi.useFakeTimers
を使用すると、Date.now
の呼び出しがモックされます。ミリ秒単位で実際の時間を取得する必要がある場合は、この関数を呼び出すことができます。
vi.runAllTicks
- 型:
() => Vitest
process.nextTick
によってキューに入れられたすべてのマイクロタスクを実行します。これにより、再帰的にスケジュールされたマイクロタスクもすべて実行されます。
vi.runAllTimers
- 型:
() => Vitest
タイマーキューが空になるまで、開始済みのすべてのタイマーを実行します。これは、runAllTimers
の実行中にスケジュールされたタイマーもすべて実行されることを意味します。無限インターバルがある場合、10,000 回試行しても終わらない場合はエラーがスローされます (fakeTimers.loopLimit
で設定可能)。
import { vi } from 'vitest';
// ---cut---
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
- 型:
() => Promise<Vitest>
タイマーキューが空になるまで、開始済みのすべてのタイマーを非同期的に実行します。これは、runAllTimersAsync
の実行中にスケジュールされたタイマーも、非同期タイマーであってもすべて実行されることを意味します。無限インターバルがある場合、10,000 回試行しても終わらない場合はエラーがスローされます (fakeTimers.loopLimit
で設定可能)。
import { vi } from 'vitest';
// ---cut---
setTimeout(async () => {
console.log(await Promise.resolve('result'));
}, 100);
await vi.runAllTimersAsync();
// log: result
vi.runOnlyPendingTimers
- 型:
() => Vitest
このメソッドは、vi.useFakeTimers
を呼び出した後に開始されたすべてのタイマーを実行します。vi.useFakeTimers
の呼び出し中に開始されたタイマーは実行されません。
import { vi } from 'vitest';
// ---cut---
let i = 0;
setInterval(() => console.log(++i), 50);
vi.runOnlyPendingTimers();
// log: 1
vi.runOnlyPendingTimersAsync
- 型:
() => Promise<Vitest>
このメソッドは、vi.useFakeTimers
を呼び出した後に開始されたすべてのタイマーを非同期的に実行します。非同期タイマーも同様です。vi.useFakeTimers
の呼び出し中に開始されたタイマーは実行されません。
import { vi } from 'vitest';
// ---cut---
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
- 型:
(date: string | number | Date) => void
偽のタイマーが有効な場合、このメソッドはシステムクロックを変更する操作をシミュレートします (hrtime
、performance.now
、new Date()
などの日付関連 API に影響します)。ただし、タイマーは実行されません。偽のタイマーが有効になっていない場合、このメソッドは Date.*
呼び出しのみをモックします。
現在の日付に依存する処理 (たとえば、コード内の Luxon 呼び出し) をテストする必要がある場合に便利です。
import { expect, vi } from 'vitest';
// ---cut---
const date = new Date(1998, 11, 19);
vi.useFakeTimers();
vi.setSystemTime(date);
expect(Date.now()).toBe(date.valueOf());
vi.useRealTimers();
vi.useFakeTimers
- 型:
(config?: FakeTimerInstallOpts) => Vitest
タイマーのモックを有効にするには、このメソッドを呼び出す必要があります。これにより、vi.useRealTimers()
が呼び出されるまで、すべてのタイマー関連関数 (setTimeout
、setInterval
など) の呼び出しがラップされます。
--pool=forks
を使用して node:child_process
内で Vitest を実行する場合、nextTick
のモックはサポートされていません。NodeJS は node:child_process
内で内部的に process.nextTick
を使用しており、モックされるとハングアップします。--pool=threads
を使用して Vitest を実行する場合、nextTick
のモックはサポートされています。
実装は、内部的に @sinonjs/fake-timers
に基づいています。
TIP
バージョン 0.35.0
以降、vi.useFakeTimers()
は process.nextTick
を自動的にモックしなくなりました。 toFake
引数でオプションを指定することで、引き続きモックできます: vi.useFakeTimers({ toFake: ['nextTick'] })
。
vi.isFakeTimers 0.34.5+
- 型:
() => boolean
偽のタイマーが有効になっている場合は true
を返します。
vi.useRealTimers
- 型:
() => Vitest
タイマーのモックを解除するには、このメソッドを呼び出して、モックされたタイマーを元の実装に戻すことができます。以前にスケジュールされたすべてのタイマーは破棄されます。
その他
Vitest が提供する便利なヘルパー関数のセットです。
vi.waitFor 0.34.5+
- 型:
<T>(callback: WaitForCallback<T>, options?: number | WaitForOptions) => Promise<T>
コールバックが正常に実行されるまで待機します。コールバックがエラーをスローするか、拒否された Promise を返す場合、成功するかタイムアウトするまで待機し続けます。
これは、サーバーを起動してその起動を待つ必要がある場合など、非同期処理の完了を待つ際に非常に役立ちます。
import { expect, test, vi } from 'vitest';
import { createServer } from './server.js';
test('Server started successfully', async () => {
const server = createServer();
await vi.waitFor(
() => {
if (!server.isReady) throw new Error('Server not started');
console.log('Server started');
},
{
timeout: 500, // default is 1000
interval: 20, // default is 50
}
);
expect(server.isReady).toBe(true);
});
非同期コールバックでも動作します
// @vitest-environment jsdom
import { expect, test, vi } from 'vitest';
import { getDOMElementAsync, populateDOMAsync } from './dom.js';
test('Element exists in a DOM', async () => {
// start populating DOM
populateDOMAsync();
const element = await vi.waitFor(
async () => {
// try to get the element until it exists
const element = (await getDOMElementAsync()) as HTMLElement | null;
expect(element).toBeTruthy();
expect(element.dataset.initialized).toBeTruthy();
return element;
},
{
timeout: 500, // default is 1000
interval: 20, // default is 50
}
);
expect(element).toBeInstanceOf(HTMLElement);
});
vi.useFakeTimers
が使用されている場合、vi.waitFor
はすべてのチェックコールバックで vi.advanceTimersByTime(interval)
を自動的に呼び出します。
vi.waitUntil 0.34.5+
- 型:
<T>(callback: WaitUntilCallback<T>, options?: number | WaitUntilOptions) => Promise<T>
これは vi.waitFor
に似ていますが、コールバックがエラーをスローすると、実行が即座に中断され、エラーメッセージが表示されます。コールバックが falsy な値を返す場合、truthy な値が返されるまで次のチェックが繰り返されます。これは、次のステップに進む前に何かが存在することを待つ必要がある場合に役立ちます。
以下の例を見てください。vi.waitUntil
を使用して、要素がページに表示されるのを待ってから、その要素に対して何らかの処理を行うことができます。
import { expect, test, vi } from 'vitest';
test('Element render correctly', async () => {
const element = await vi.waitUntil(() => document.querySelector('.element'), {
timeout: 500, // default is 1000
interval: 20, // default is 50
});
// do something with the element
expect(element.querySelector('.element-child')).toBeTruthy();
});
vi.hoisted 0.31.0+
- 型:
<T>(factory: () => T) => T
ES モジュールでは、静的な import
文はすべてファイルの先頭に巻き上げられます。そのため、import
文よりも前に記述されたコードは、実際には import
文の評価後に実行されます。
ただし、モジュールをインポートする前に日付をモックするなど、いくつかの副作用を伴う処理を実行したい場合があります。
この制限を回避するには、静的インポートを次のように動的なインポートに書き換えることができます。
callFunctionWithSideEffect()
- import { value } from './some/module.js'
+ const { value } = await import('./some/module.js')
vitest
を実行する場合、vi.hoisted
メソッドを使用してこれを自動的に行うことができます。
- callFunctionWithSideEffect()
import { value } from './some/module.js'
+ vi.hoisted(() => callFunctionWithSideEffect())
このメソッドは、ファクトリから返された値を返します。ローカルで定義された変数に簡単にアクセスする必要がある場合は、その値を vi.mock
ファクトリで使用できます。
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);
このメソッドは、環境がトップレベルの await をサポートしていない場合でも、非同期的に呼び出すことができることに注意してください。
const promised = await vi.hoisted(async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
return response.json();
});
vi.setConfig
- 型:
RuntimeConfig
現在のテストファイルの設定を更新します。このメソッドは、現在のテストファイルに影響を与える設定オプションのみをサポートします。
vi.setConfig({
allowOnly: true,
testTimeout: 10_000,
hookTimeout: 10_000,
clearMocks: true,
restoreMocks: true,
fakeTimers: {
now: new Date(2021, 11, 19),
// supports the whole object
},
maxConcurrency: 10,
sequence: {
hooks: 'stack',
// supports only "sequence.hooks"
},
});
vi.resetConfig
- 型:
RuntimeConfig
vi.setConfig
が以前に呼び出された場合、これにより設定が元の状態にリセットされます。