Skip to content
Vitest 3
Main Navigation ガイド & API設定ブラウザモード高度なAPI
3.2.0
2.1.9
1.6.1
0.34.6

日本語

English
简体中文
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
한국어
Italiano
Polski
Türkçe
čeština
magyar

日本語

English
简体中文
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
한국어
Italiano
Polski
Türkçe
čeština
magyar

外観

Sidebar Navigation

はじめに

Vitest を選ぶ理由

はじめに

機能

Vitest の設定

API

テストAPIリファレンス

モック関数

Vi

expect

expectTypeOf

assert

assertType

ガイド

コマンドラインインターフェース

テストフィルタリング

テストプロジェクト

レポーター

カバレッジ

スナップショット

モック

並列処理

型テスト

Vitest UI

インソース・テスト

テストコンテキスト

テストアノテーション

テスト環境

マッチャーの拡張

IDE統合

デバッグ

よくあるエラー

移行ガイド

Vitest 3.0 への移行

Jest からの移行

パフォーマンス

テストパフォーマンスのプロファイリング

パフォーマンスの向上

ブラウザーモード

上級者向けAPI

他のテストランナーとの比較

このページの内容

Vi ​

Vitest は、vi ヘルパーを通じて便利なユーティリティ関数を提供します。これらの関数はグローバルにアクセスできるほか(globals 設定が有効な場合)、vitest から直接インポートすることも可能です。

js
import { vi } from 'vitest';

モジュールのモック ​

このセクションでは、モジュールをモックする際に使用できる API について説明します。Vitest は require() を使用してインポートされたモジュールのモックをサポートしていない点にご注意ください。

vi.mock ​

  • 型: (path: string, factory?: MockOptions | ((importOriginal: () => unknown) => unknown)) => void
  • 型: <T>(path: Promise<T>, factory?: MockOptions | ((importOriginal: () => T) => T | Promise<T>)) => void

指定された path からインポートされるすべてのモジュールを別のモジュールに置き換えます。パスには設定済みの Vite エイリアスを使用できます。vi.mock の呼び出しは巻き上げられるため、コード内のどこで呼び出しても問題ありません。常にすべてのインポートの前に実行されます。スコープ外の変数を参照する必要がある場合は、それらを 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 を使用するか、ファクトリを最初の引数として渡すヘルパーを使用して、元のモジュールを内部で取得できます。

ファクトリ関数の代わりに spy プロパティを持つオブジェクトを提供することもできます。spy が true の場合、Vitest は通常通りモジュールを自動モックしますが、エクスポートの実装を上書きしません。これは、エクスポートされたメソッドが別のメソッドによって正しく呼び出されたことをアサートしたい場合に便利です。

ts
import { calculator } from './src/calculator.ts';

vi.mock('./src/calculator.ts', { spy: true });

// 元の実装を呼び出すが、
// 後で動作をアサートできる
const result = calculator(1, 2);

expect(result).toBe(3);
expect(calculator).toHaveBeenCalledWith(1, 2);
expect(calculator).toHaveReturned(3);

Vitest は、より良い IDE サポートのために、vi.mock および vi.doMock メソッドで文字列の代わりにモジュールプロミスもサポートしています。ファイルが移動されると、パスが更新され、importOriginal は型を自動的に継承します。このシグネチャを使用すると、ファクトリの戻り値の型が元のモジュールと互換性があることも強制されます(エクスポートはオプションのまま)。

ts
// @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(); // 型が推論される
  //    ^?
  return {
    ...mod,
    // 一部のエクスポートを置き換える
    total: vi.fn(),
  };
});

内部的には、Vitest はモジュールオブジェクトではなく文字列で動作します。

ただし、tsconfig.json で paths エイリアスを設定して TypeScript を使用している場合、コンパイラはインポート型を正しく解決できません。 これを機能させるには、すべてのエイリアス化されたインポートを、対応する相対パスに置き換えるようにしてください。 例:import('@/module') の代わりに import('./path/to/module.js') を使用します。

WARNING

vi.mock はファイルの先頭に巻き上げられます(言い換えれば、_移動_されます)。これは、beforeEach 内であろうと test 内であろうと、どこに記述しても、実際にはその前に呼び出されることを意味します。

これはまた、ファクトリの外部で定義された変数をファクトリ内で使用できないことも意味します。

ファクトリ内で変数を使用する必要がある場合は、vi.doMock を試してください。これは同じように機能しますが、巻き上げられません。ただし、後続のインポートのみをモックすることに注意してください。

vi.mock の前に宣言されていれば、vi.hoisted メソッドで定義された変数を参照することもできます。

ts
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 のドキュメントとは異なる場合があります。例:

ts
vi.mock('./path/to/module.js', () => {
  return {
    default: { myDefaultKey: vi.fn() },
    namedExport: vi.fn(),
    // など...
  };
});

モックするファイルの横に __mocks__ フォルダがあり、ファクトリが提供されていない場合、Vitest は __mocks__ サブフォルダ内に同じ名前のファイルを見つけようとし、それを実際のモジュールとして使用します。依存関係をモックしている場合、Vitest はプロジェクトのルート(デフォルトは process.cwd())に __mocks__ フォルダを見つけようとします。deps.moduleDirectories 設定オプションを通じて、依存関係の場所を Vitest に伝えることができます。

例えば、次のようなファイル構造があるとします。

- __mocks__
  - axios.js
- src
  __mocks__
    - increment.js
  - increment.js
- tests
  - increment.test.js

テストファイルでファクトリやオプションを指定せずに vi.mock を呼び出すと、__mocks__ フォルダ内のファイルがモジュールとして使用されます。

ts
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?: MockOptions | ((importOriginal: () => unknown) => unknown)) => void
  • 型: <T>(path: Promise<T>, factory?: MockOptions | ((importOriginal: () => T) => T | Promise<T>)) => void

vi.mock と同じですが、ファイルの先頭に巻き上げられないため、グローバルファイルスコープの変数を参照できます。モジュールの次の動的インポートはモックされます。

WARNING

これは、呼び出される前にインポートされたモジュールをモックしません。ESM のすべての静的インポートは常に巻き上げられることを忘れないでください。したがって、これを静的インポートの前に置いても、インポートの前に呼び出されることはありません。

ts
vi.doMock('./increment.js'); // これはimportステートメントの_後に_呼び出される

import { increment } from './increment.js';
ts
export function increment(number) {
  return number + 1;
}
ts
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 は最初のレベルの値がモックされているとしか認識しません。オブジェクト全体がモックされている場合は、2番目の引数として { deep: true } を渡して、TypeScript にそのように伝えることができます。

ts
export function add(x: number, y: number): number {
  return x + y;
}

export function fetchSomething(): Promise<Response> {
  return fetch('https://vitest.dev/');
}
ts
import * as example from './example';

vi.mock('./example');

test('1 + 1 は 10', async () => {
  vi.mocked(example.add).mockReturnValue(10);
  expect(example.add(1, 1)).toBe(10);
});

test('部分的に正しい型付けで戻り値をモックする', 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 }) // これは型エラー
});

vi.importActual ​

  • 型: <T>(path: string) => Promise<T>

モックすべきかどうかのすべてのチェックをバイパスしてモジュールをインポートします。モジュールを部分的にモックしたい場合に役立ちます。

ts
vi.mock('./example.js', async () => {
  const originalModule = await vi.importActual('./example.js');

  return { ...originalModule, get: vi.fn() };
});

vi.importMock ​

  • 型: <T>(path: string) => Promise<MaybeMockedDeep<T>>

すべてのプロパティ(ネストされたプロパティを含む)がモックされたモジュールをインポートします。vi.mock と同じルールに従います。適用されるルールについては、アルゴリズムを参照してください。

vi.unmock ​

  • 型: (path: string | Promise<Module>) => void

モックされたレジストリからモジュールを削除します。すべてのインポート呼び出しは、以前にモックされていたとしても、元のモジュールを返します。この呼び出しはファイルの先頭に巻き上げられるため、例えば setupFiles で定義されたモジュールのみをアンモックします。

vi.doUnmock ​

  • 型: (path: string | Promise<Module>) => void

vi.unmock と同じですが、ファイルの先頭に巻き上げられません。モジュールの次のインポートは、モックではなく元のモジュールをインポートします。これは、以前にインポートされたモジュールをアンモックしません。

ts
export function increment(number) {
  return number + 1;
}
ts
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`は元の関数で、count + 1を返す
const { increment: unmockedIncrement } = await import('./increment.js');

unmockedIncrement(1) === 2;
unmockedIncrement(30) === 31;

vi.resetModules ​

  • 型: () => Vitest

すべてのモジュールのキャッシュをクリアして、モジュールレジストリをリセットします。これにより、再インポート時にモジュールが再評価されるようになります。トップレベルのインポートは再評価できません。ローカルの状態がテスト間で競合するモジュールを分離するのに役立つ場合があります。

ts
import { vi } from 'vitest';

import { data } from './data.js'; // 各テストの前に再評価されない

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 ​

すべてのインポートがロードされるのを待ちます。同期呼び出しがあり、他に待つことができないモジュールのインポートを開始する場合に便利です。

ts
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 を返します。

ts
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+ ​

  • 型: <T>(value: T) => MaybeMockedDeep<T>

vi.mock() がモジュールエクスポートをモックするのと同じ方法で、指定されたオブジェクトのプロパティとメソッドを深くモックします。詳細については、自動モックを参照してください。

ts
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 ​

  • 型: (fn: Function) => boolean

指定されたパラメータがモック関数であるかどうかをチェックします。TypeScript を使用している場合、その型も絞り込まれます。

vi.clearAllMocks ​

すべてのスパイに対して.mockClear() を呼び出します。 これにより、モックの実装に影響を与えることなく、モック履歴がクリアされます。

vi.resetAllMocks ​

すべてのスパイに対して.mockReset() を呼び出します。 これにより、モック履歴がクリアされ、各モックの実装が元の状態にリセットされます。

vi.restoreAllMocks ​

すべてのスパイに対して.mockRestore() を呼び出します。 これにより、モック履歴がクリアされ、すべての元のモック実装が復元され、スパイされたオブジェクトの元のディスクリプタが復元されます。

vi.spyOn ​

  • 型: <T, K extends keyof T>(object: T, method: K, accessType?: 'get' | 'set') => MockInstance

vi.fn() と同様に、オブジェクトのメソッドまたはゲッター/セッターにスパイを作成します。これはモック関数を返します。

ts
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

Explicit Resource Management をサポートする環境では、const の代わりに using を使用することで、包含ブロックが終了したときにモックされた関数に対して mockRestore を自動的に呼び出すことができます。これは、スパイされたメソッドに特に便利です。

ts
it('console.logを呼び出す', () => {
  using spy = vi.spyOn(console, 'log').mockImplementation(() => {})
  debug('message')
  expect(spy).toHaveBeenCalled()
})
// ここでconsole.logが復元される

TIP

afterEach 内で vi.restoreAllMocks を呼び出す(または test.restoreMocks を有効にする)ことで、すべてのメソッドを元の実装に復元できます。これにより、元のオブジェクトディスクリプタが復元されるため、メソッドの実装を変更することはできません。

ts
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!

TIP

ブラウザモードでは、エクスポートされたメソッドにスパイすることはできません。代わりに、vi.mock("./file-path.js", { spy: true }) を呼び出すことで、すべてのエクスポートされたメソッドにスパイできます。これにより、すべてのエクスポートがモックされますが、その実装はそのまま維持され、メソッドが正しく呼び出されたかどうかをアサートできます。

ts
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);

jsdom やその他の Node.js 環境でエクスポートにスパイすることは可能ですが、これは将来変更される可能性があります。

vi.stubEnv ​

  • 型: <T extends string>(name: T, value: T extends "PROD" | "DEV" | "SSR" ? boolean : string | undefined) => Vitest

process.env と import.meta.env の環境変数の値を変更します。vi.unstubAllEnvs を呼び出すことで、その値を復元できます。

ts
import { vi } from 'vitest';

// `process.env.NODE_ENV`と`import.meta.env.NODE_ENV`は
// `vi.stubEnv`を呼び出す前は"development"

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;

// 他の環境変数は変更しない
import.meta.env.MODE === 'development';

TIP

値を単純に代入することでも変更できますが、vi.unstubAllEnvs を使用して以前の値を復元することはできません。

ts
import.meta.env.MODE = 'test';

vi.unstubAllEnvs ​

  • 型: () => Vitest

vi.stubEnv で変更されたすべての import.meta.env と process.env の値を復元します。初めて呼び出されたとき、Vitest は元の値を記憶し、unstubAllEnvs が再度呼び出されるまでそれを保存します。

ts
import { vi } from 'vitest';

// `process.env.NODE_ENV`と`import.meta.env.NODE_ENV`は
// `stubEnv`を呼び出す前は"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 を呼び出すことで、元の値を復元できます。

ts
import { vi } from 'vitest';

// `innerWidth`はstubGlobalを呼び出す前は"0"

vi.stubGlobal('innerWidth', 100);

innerWidth === 100;
globalThis.innerWidth === 100;
// jsdomまたはhappy-domを使用している場合
window.innerWidth === 100;

TIP

値を globalThis または window(jsdom または happy-dom 環境を使用している場合)に単純に代入することでも変更できますが、vi.unstubAllGlobals を使用して元の値を復元することはできません。

ts
globalThis.innerWidth = 100;
// jsdomまたはhappy-domを使用している場合
window.innerWidth = 100;

vi.unstubAllGlobals ​

  • 型: () => Vitest

vi.stubGlobal で変更された globalThis/global(および window/top/self/parent、jsdom または happy-dom 環境を使用している場合)のすべてのグローバル値を復元します。初めて呼び出されたとき、Vitest は元の値を記憶し、unstubAllGlobals が再度呼び出されるまでそれを保存します。

ts
import { vi } from 'vitest';

const Mock = vi.fn();

// IntersectionObserverは"stubGlobal"を呼び出す前は"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

このメソッドは、指定されたミリ秒数が経過するか、キューが空になるか、どちらか早い方まで、開始されたすべてのタイマーを呼び出します。

ts
let i = 0;
setInterval(() => console.log(++i), 50);

vi.advanceTimersByTime(150);

// log: 1
// log: 2
// log: 3

vi.advanceTimersByTimeAsync ​

  • 型: (ms: number) => Promise<Vitest>

このメソッドは、指定されたミリ秒数が経過するか、キューが空になるか、どちらか早い方まで、開始されたすべてのタイマーを呼び出します。これには非同期に設定されたタイマーも含まれます。

ts
let i = 0;
setInterval(() => Promise.resolve().then(() => console.log(++i)), 50);

await vi.advanceTimersByTimeAsync(150);

// log: 1
// log: 2
// log: 3

vi.advanceTimersToNextTimer ​

  • 型: () => Vitest

次に利用可能なタイマーを呼び出します。各タイマー呼び出しの間でアサーションを行うのに便利です。チェーン呼び出しして、自分でタイマーを管理できます。

ts
let i = 0;
setInterval(() => console.log(++i), 50);

vi.advanceTimersToNextTimer() // log: 1
  .advanceTimersToNextTimer() // log: 2
  .advanceTimersToNextTimer(); // log: 3

vi.advanceTimersToNextTimerAsync ​

  • 型: () => Promise<Vitest>

次に利用可能なタイマーを呼び出し、非同期に設定されている場合は解決されるまで待機します。各タイマー呼び出しの間でアサーションを行うのに便利です。

ts
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+ ​

  • 型: () => Vitest

vi.advanceTimersByTime に似ていますが、requestAnimationFrame で現在スケジュールされているコールバックを実行するために必要なミリ秒数だけタイマーを進めます。

ts
let frameRendered = false;

requestAnimationFrame(() => {
  frameRendered = true;
});

vi.advanceTimersToNextFrame();

expect(frameRendered).toBe(true);

vi.getTimerCount ​

  • 型: () => number

待機中のタイマーの数を取得します。

vi.clearAllTimers ​

実行がスケジュールされているすべてのタイマーを削除します。これらのタイマーは将来実行されることはありません。

vi.getMockedSystemTime ​

  • 型: () => Date | null

モックされた現在の日付を返します。日付がモックされていない場合、メソッドは null を返します。

vi.getRealSystemTime ​

  • 型: () => number

vi.useFakeTimers を使用している場合、Date.now の呼び出しはモックされます。ミリ秒単位で実際の時間を取得する必要がある場合は、この関数を呼び出すことができます。

vi.runAllTicks ​

  • 型: () => Vitest

process.nextTick によってキューに入れられたすべてのマイクロタスクを呼び出します。これにより、それ自体によってスケジュールされたすべてのマイクロタスクも実行されます。

vi.runAllTimers ​

  • 型: () => Vitest

このメソッドは、タイマーキューが空になるまで、開始されたすべてのタイマーを呼び出します。これは、runAllTimers 中に呼び出されたすべてのタイマーが発火することを意味します。無限のインターバルがある場合、10,000 回の試行後にスローされます(fakeTimers.loopLimit で設定可能)。

ts
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 で設定可能)。

ts
setTimeout(async () => {
  console.log(await Promise.resolve('result'));
}, 100);

await vi.runAllTimersAsync();

// log: result

vi.runOnlyPendingTimers ​

  • 型: () => Vitest

このメソッドは、vi.useFakeTimers 呼び出し後に開始されたすべてのタイマーを呼び出します。その呼び出し中に開始されたタイマーは発火しません。

ts
let i = 0;
setInterval(() => console.log(++i), 50);

vi.runOnlyPendingTimers();

// log: 1

vi.runOnlyPendingTimersAsync ​

  • 型: () => Promise<Vitest>

このメソッドは、vi.useFakeTimers 呼び出し後に開始されたすべてのタイマーを非同期に呼び出します。非同期タイマーであっても同様です。その呼び出し中に開始されたタイマーは発火しません。

ts
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 の呼び出しなどです。

Date と同じ文字列および数値引数を受け入れます。

ts
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、clearTimeout、clearInterval、setImmediate、clearImmediate、Date など)へのすべての後続の呼び出しがラップされます。

--pool=forks を使用して node:child_process 内で Vitest を実行する場合、nextTick のモックはサポートされていません。NodeJS は node:child_process 内で内部的に process.nextTick を使用しており、モックされるとハングします。--pool=threads を使用して Vitest を実行する場合、nextTick のモックはサポートされています。

実装は内部的に @sinonjs/fake-timers に基づいています。

TIP

vi.useFakeTimers() は process.nextTick と queueMicrotask を自動的にモックしません。 しかし、toFake 引数にオプションを指定することで有効にできます:vi.useFakeTimers({ toFake: ['nextTick', 'queueMicrotask'] })。

vi.isFakeTimers ​

  • 型: () => boolean

フェイクタイマーが有効な場合は true を返します。

vi.useRealTimers ​

  • 型: () => Vitest

タイマーが終了したら、このメソッドを呼び出して、モックされたタイマーを元の実装に戻すことができます。それまでにスケジュールされていたすべてのタイマーは破棄されます。

その他 ​

Vitest が提供する便利なヘルパー関数のセットです。

vi.waitFor ​

  • 型: <T>(callback: WaitForCallback<T>, options?: number | WaitForOptions) => Promise<T>

コールバックが正常に実行されるのを待ちます。コールバックがエラーをスローしたり、拒否されたプロミスを返したりした場合、成功するかタイムアウトするまで待ち続けます。

オプションが数値に設定されている場合、その効果は { timeout: options } を設定するのと同等です。

これは、サーバーを起動して起動するのを待つ必要がある場合など、非同期アクションが完了するのを待つ必要がある場合に非常に便利です。

ts
import { expect, test, vi } from 'vitest';
import { createServer } from './server.js';

test('サーバーが正常に起動した', async () => {
  const server = createServer();

  await vi.waitFor(
    () => {
      if (!server.isReady) {
        throw new Error('サーバーが起動していません');
      }

      console.log('サーバーが起動しました');
    },
    {
      timeout: 500, // デフォルトは1000
      interval: 20, // デフォルトは50
    }
  );
  expect(server.isReady).toBe(true);
});

非同期コールバックでも機能します。

ts
// @vitest-environment jsdom

import { expect, test, vi } from 'vitest';
import { getDOMElementAsync, populateDOMAsync } from './dom.js';

test('要素がDOMに存在する', async () => {
  // DOMの生成を開始
  populateDOMAsync();

  const element = await vi.waitFor(
    async () => {
      // 要素が存在するまで取得を試みる
      const element = (await getDOMElementAsync()) as HTMLElement | null;
      expect(element).toBeTruthy();
      expect(element.dataset.initialized).toBeTruthy();
      return element;
    },
    {
      timeout: 500, // デフォルトは1000
      interval: 20, // デフォルトは50
    }
  );
  expect(element).toBeInstanceOf(HTMLElement);
});

vi.useFakeTimers が使用されている場合、vi.waitFor は各チェックコールバックで自動的に vi.advanceTimersByTime(interval) を呼び出します。

vi.waitUntil ​

  • 型: <T>(callback: WaitUntilCallback<T>, options?: number | WaitUntilOptions) => Promise<T>

これは vi.waitFor に似ていますが、コールバックがエラーをスローした場合、実行はすぐに中断され、エラーメッセージが受信されます。コールバックが偽の値を返した場合、真の値を返すまで次のチェックが続行されます。これは、次のステップに進む前に何かが存在するのを待つ必要がある場合に便利です。

以下の例を見てください。vi.waitUntil を使用して、要素がページに表示されるのを待ってから、その要素で何かを行うことができます。

ts
import { expect, test, vi } from 'vitest';

test('要素が正しくレンダリングされる', async () => {
  const element = await vi.waitUntil(() => document.querySelector('.element'), {
    timeout: 500, // デフォルトは1000
    interval: 20, // デフォルトは50
  });

  // 要素で何かを行う
  expect(element.querySelector('.element-child')).toBeTruthy();
});

vi.hoisted ​

  • 型: <T>(factory: () => T) => T

ES モジュールのすべての静的 import ステートメントはファイルの先頭に巻き上げられるため、インポートの前に定義されたコードは、実際にはインポートが評価された後に実行されます。

しかし、モジュールをインポートする前に日付をモックするなどの副作用を呼び出すことは有用な場合があります。

この制限を回避するには、静的インポートを次のように動的インポートに書き換えることができます。

diff
callFunctionWithSideEffect()
- import { value } from './some/module.js'
+ const { value } = await import('./some/module.js')

vitest を実行している場合、vi.hoisted メソッドを使用することでこれを自動的に行うことができます。内部的には、Vitest は静的インポートをライブバインディングを保持したまま動的インポートに変換します。

diff
- callFunctionWithSideEffect()
import { value } from './some/module.js'
+ vi.hoisted(() => callFunctionWithSideEffect())

インポートは利用できません

インポートの前にコードを実行するということは、インポートされた変数がまだ定義されていないため、それらにアクセスできないことを意味します。

ts
import { value } from './some/module.js';

vi.hoisted(() => { value }); // エラーをスローする

このコードはエラーを生成します。

Cannot access '__vi_import_0__' before initialization

vi.hoisted 内で別のモジュールから変数にアクセスする必要がある場合は、動的インポートを使用してください。

ts
await vi.hoisted(async () => {
  const { value } = await import('./some/module.js');
});

ただし、vi.hoisted 内で何かをインポートすることは推奨されません。なぜなら、インポートはすでに巻き上げられているからです。テストが実行される前に何かを実行する必要がある場合は、インポートされたモジュール自体で実行してください。

このメソッドは、ファクトリから返された値を返します。ローカルで定義された変数に簡単にアクセスする必要がある場合、その値を vi.mock ファクトリで使用できます。

ts
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 をサポートしていなくても、非同期で呼び出すこともできます。

ts
const json = await vi.hoisted(async () => {
  const response = await fetch('https://jsonplaceholder.typicode.com/posts');
  return response.json();
});

vi.setConfig ​

  • 型: RuntimeConfig

現在のテストファイルの設定を更新します。このメソッドは、現在のテストファイルに影響する設定オプションのみをサポートします。

ts
vi.setConfig({
  allowOnly: true,
  testTimeout: 10_000,
  hookTimeout: 10_000,
  clearMocks: true,
  restoreMocks: true,
  fakeTimers: {
    now: new Date(2021, 11, 19),
    // オブジェクト全体をサポート
  },
  maxConcurrency: 10,
  sequence: {
    hooks: 'stack',
    // "sequence.hooks"のみをサポート
  },
});

vi.resetConfig ​

  • 型: RuntimeConfig

以前に vi.setConfig が呼び出された場合、これは設定を元の状態にリセットします。

Pager
前のページモック関数
次のページexpect

MITライセンス の下で公開されています。

Copyright (c) 2021-Present Vitest Team

https://vitest.dev/api/vi

MITライセンス の下で公開されています。

Copyright (c) 2021-Present Vitest Team