Skip to content
Vitest 2
Main Navigation ガイドAPI設定ブラウザモード高度な
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

テスト API リファレンス

モック関数

Vi

expect

expectTypeOf

assert

assertType

このページの内容

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 またはファクトリを最初の引数として渡すヘルパーを使用して、内部で元のモジュールを取得できます。

Vitest 2.1 以降、ファクトリ関数の代わりに 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.hoisted メソッドで定義された変数を、vi.mock の前に宣言されていれば参照することもできます。

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
// 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?: 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 { 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
// example.ts
export function add(x: number, y: number): number {
  return x + y;
}

export function fetchSomething(): Promise<Response> {
  return fetch('https://vitest.dev/');
}
ts
// example.test.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 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 | Promise<Module>) => void

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

vi.doUnmock ​

  • 型: (path: string | Promise<Module>) => 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(() => {
  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.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
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!

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

setSystemTime を使用して設定されたモックされた現在の日付を返します。日付がモックされていない場合、メソッドは 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 を使用しており、モックされるとハングします。nextTick のモックは、--pool=threads を使用して Vitest を実行している場合にサポートされます。

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

TIP

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

vi.isFakeTimers ​

  • 型: () => boolean

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

vi.useRealTimers ​

  • 型: () => Vitest

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

その他 ​

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

vi.waitFor ​

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

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

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

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 メソッドを使用することでこれを自動的に行うことができます。

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),
    // オブジェクト全体をサポート
  },
  maxConcurrency: 10,
  sequence: {
    hooks: 'stack',
    // "sequence.hooks" のみをサポート
  },
});

vi.resetConfig ​

  • 型: RuntimeConfig

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

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

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

Copyright (c) 2024 Mithril Contributors

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

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

Copyright (c) 2024 Mithril Contributors