Skip to content
Vitest 1
Main Navigation ガイドAPI設定高度な
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 UI

ブラウザモード

ソース内テスト

テストコンテキスト

テスト環境

マッチャー拡張

IDE 連携機能

デバッグ

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

マイグレーションガイド

よくあるエラー

パフォーマンスの改善

API

テスト API リファレンス

モック関数

Vi

expect

expectTypeOf

assert

assertType

設定

Vitestの設定ファイル管理

Vitestの設定

このページの内容

Vi ​

Vitest は、vi ヘルパーを通じて、テストを支援するためのユーティリティ関数を提供しています。globals configurationが有効になっている場合は、グローバルにアクセスするか、vitest から直接インポートできます。

js
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() を呼び出すことができます。

WARNING

ブラウザモード は、現在モジュールのモックをサポートしていません。この機能は GitHub の issue で追跡できます。

factory が定義されている場合、以降のすべてのインポートはその結果を返します。Vitest はファクトリを一度だけ呼び出し、vi.unmock または vi.doUnmock が呼び出されるまで、後続のすべてのインポートの結果をキャッシュします。

jest と異なり、ファクトリは非同期にできます。vi.importActual またはヘルパーを、最初の引数として渡されたファクトリとともに使用して、元のモジュールを内部で取得できます。

js
import { vi } from 'vitest';
// ---cut---
// JavaScript を使用する場合

vi.mock('./path/to/module.js', async importOriginal => {
  const mod = await importOriginal();
  return {
    ...mod,
    // いくつかのエクスポートを置き換える
    namedExport: vi.fn(),
  };
});
ts
// 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 メソッドで定義された変数を参照することもできます。

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 はプロジェクトの root(デフォルトは process.cwd())に __mocks__ フォルダを見つけようとします。 deps.moduleDirectories 設定オプションを使用して、依存関係の場所を Vitest に伝えることができます。

たとえば、次のファイル構造があるとします。

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

ファクトリが提供されていないテストファイルで vi.mock を呼び出すと、モジュールとして使用する __mocks__ フォルダ内のファイルが見つかります。

ts
// 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 のすべての静的インポートは常に 巻き上げられる ことを忘れないでください。したがって、静的インポートの前にこれを記述しても、インポートの前に呼び出されるわけではありません。

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

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

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

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

ts
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 と同じですが、ファイルの先頭に巻き上げられません。モジュールの次のインポートは、モックの代わりに元のモジュールをインポートします。これは、以前にインポートされたモジュールをアンモックしません。

ts
// ./increment.js
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` はカウント + 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 テストで再評価されません

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
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() と同様に、オブジェクトのメソッドまたはゲッター/セッターに対するスパイを作成します。モック関数 を返します。

ts
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 を有効にする)と、すべてのメソッドが元の実装に復元されます。これにより、元の オブジェクト記述子 が復元されるため、メソッドの実装を変更できなくなります。

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!

vi.stubEnv 0.26.0+ ​

  • 型: (name: string, value: string) => Vitest

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

ts
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 を使用して以前の値を復元することはできません。

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

vi.unstubAllEnvs 0.26.0+ ​

  • 型: () => Vitest

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

ts
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 を呼び出すことで、元の値を復元できます。

ts
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 を使って元の値を復元することはできません。

ts
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 が再度呼び出されるまでその値を保持します。

ts
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

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

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

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

ts
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 つ実行します。各タイマーの実行後にアサーションを行う場合に便利です。メソッドチェーンで呼び出すことで、タイマーの実行を細かく制御できます。

ts
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 つ実行し、非同期的に設定されている場合は、その完了を待ちます。各タイマーの実行後にアサーションを行う場合に便利です。

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

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

ts
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 の呼び出し中に開始されたタイマーは実行されません。

ts
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 の呼び出し中に開始されたタイマーは実行されません。

ts
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 呼び出し) をテストする必要がある場合に便利です。

ts
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 を返す場合、成功するかタイムアウトするまで待機し続けます。

これは、サーバーを起動してその起動を待つ必要がある場合など、非同期処理の完了を待つ際に非常に役立ちます。

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

非同期コールバックでも動作します

ts
// @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 を使用して、要素がページに表示されるのを待ってから、その要素に対して何らかの処理を行うことができます。

ts
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 文の評価後に実行されます。

ただし、モジュールをインポートする前に日付をモックするなど、いくつかの副作用を伴う処理を実行したい場合があります。

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

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

vitest を実行する場合、vi.hoisted メソッドを使用してこれを自動的に行うことができます。

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

このメソッドは、ファクトリから返された値を返します。ローカルで定義された変数に簡単にアクセスする必要がある場合は、その値を 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 promised = 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),
    // supports the whole object
  },
  maxConcurrency: 10,
  sequence: {
    hooks: 'stack',
    // supports only "sequence.hooks"
  },
});

vi.resetConfig ​

  • 型: RuntimeConfig

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

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

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

Copyright (c) 2024 Mithril Contributors

https://v1.vitest.dev/api/vi

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

Copyright (c) 2024 Mithril Contributors