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

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

このページの内容

モック ​

テストを作成する際、内部または外部サービスの「偽の」バージョンを作成する必要が生じることがよくあります。これは一般的にモックと呼ばれます。Vitestは、viヘルパーを通じて、そのためのユーティリティを提供します。vitestからインポートするか、global設定が有効になっている場合はグローバルにアクセスできます。

WARNING

各テスト実行の前後に、必ずモックをクリアまたは復元して、テスト実行間でモックの状態変更が残らないようにしてください。詳細については、mockResetのドキュメントを参照してください。

vi.fn、vi.mock、vi.spyOnメソッドに慣れていない場合は、まずAPI項目を確認してください。

日付 ​

テストの一貫性を確保するために、日付を制御する必要がある場合があります。Vitestは、タイマーとシステム日付を操作するために@sinonjs/fake-timersパッケージを使用します。特定のAPIの詳細は、こちらをご覧ください。

例 ​

js
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

const businessHours = [9, 17];

function purchase() {
  const currentHour = new Date().getHours();
  const [open, close] = businessHours;

  if (currentHour > open && currentHour < close) {
    return { message: 'Success' };
  }

  return { message: 'Error' };
}

describe('purchasing flow', () => {
  beforeEach(() => {
    // Vitestにモック時間を使用することを指示する
    vi.useFakeTimers();
  });

  afterEach(() => {
    // 各テスト実行後に日付を復元する
    vi.useRealTimers();
  });

  it('allows purchases within business hours', () => {
    // 営業時間内に時間を設定する
    const date = new Date(2000, 1, 1, 13);
    vi.setSystemTime(date);

    // Date.now()にアクセスすると、上記で設定された日付が取得される
    expect(purchase()).toEqual({ message: 'Success' });
  });

  it('disallows purchases outside of business hours', () => {
    // 営業時間外に時間を設定する
    const date = new Date(2000, 1, 1, 19);
    vi.setSystemTime(date);

    // Date.now()にアクセスすると、上記で設定された日付が取得される
    expect(purchase()).toEqual({ message: 'Error' });
  });
});

関数 ​

関数のモックは、_スパイ_と_モック_の2つのカテゴリに大別できます。

特定の関数が呼び出されたかどうか(そして、どの引数が渡されたか)を検証するだけでよい場合があります。そのような場合はスパイで十分であり、vi.spyOn()を直接使用できます(詳細はこちら)。

ただし、スパイは関数を監視するのに役立つだけで、それらの関数の実装を変更することはできません。関数の偽の(またはモックされた)バージョンを作成する必要がある場合は、vi.fn()を使用できます(詳細はこちら)。

関数をモックするためのベースとしてTinyspyを使用していますが、jest互換にするための独自のラッパーがあります。vi.fn()とvi.spyOn()はどちらも同じメソッドを共有しますが、vi.fn()の戻り値のみが呼び出し可能です。

例 ​

js
import { afterEach, describe, expect, it, vi } from 'vitest';

const messages = {
  items: [
    { message: 'Simple test message', from: 'Testman' },
    // ...
  ],
  getLatest, // サポートされている場合は、getterまたはsetterとしても使用可能
};

function getLatest(index = messages.items.length - 1) {
  return messages.items[index];
}

describe('reading messages', () => {
  afterEach(() => {
    vi.restoreAllMocks();
  });

  it('should get the latest message with a spy', () => {
    const spy = vi.spyOn(messages, 'getLatest');
    expect(spy.getMockName()).toEqual('getLatest');

    expect(messages.getLatest()).toEqual(
      messages.items[messages.items.length - 1]
    );

    expect(spy).toHaveBeenCalledTimes(1);

    spy.mockImplementationOnce(() => 'access-restricted');
    expect(messages.getLatest()).toEqual('access-restricted');

    expect(spy).toHaveBeenCalledTimes(2);
  });

  it('should get with a mock', () => {
    const mock = vi.fn().mockImplementation(getLatest);

    expect(mock()).toEqual(messages.items[messages.items.length - 1]);
    expect(mock).toHaveBeenCalledTimes(1);

    mock.mockImplementationOnce(() => 'access-restricted');
    expect(mock()).toEqual('access-restricted');

    expect(mock).toHaveBeenCalledTimes(2);

    expect(mock()).toEqual(messages.items[messages.items.length - 1]);
    expect(mock).toHaveBeenCalledTimes(3);
  });
});

その他 ​

  • Jestのモック関数

グローバル変数 ​

jsdomやnodeに存在しないグローバル変数をモックするには、vi.stubGlobalヘルパーを使用できます。これにより、グローバル変数の値がglobalThisに設定されます。

ts
import { vi } from 'vitest';

const IntersectionObserverMock = vi.fn(() => ({
  disconnect: vi.fn(),
  observe: vi.fn(),
  takeRecords: vi.fn(),
  unobserve: vi.fn(),
}));

vi.stubGlobal('IntersectionObserver', IntersectionObserverMock);

// これで`IntersectionObserver`または`window.IntersectionObserver`としてアクセスできる

モジュール ​

モジュールをモックすることで、他のコードで呼び出されるサードパーティライブラリの動作を監視し、引数や出力のテスト、さらにはその実装の再定義が可能になります。

より詳細なAPIの説明については、vi.mock() API項目を参照してください。

オートモックアルゴリズム ​

コードがモックされたモジュールをインポートしており、このモジュールに関連する__mocks__ファイルやfactoryがない場合、Vitestはモジュール自体を呼び出し、すべてのエクスポートをモックします。

以下の原則が適用されます。

  • すべての配列は空になる
  • すべてのプリミティブとコレクションは同じまま
  • すべてのオブジェクトはディープクローンされる
  • クラスのすべてのインスタンスとそのプロトタイプはディープクローンされる

仮想モジュール ​

VitestはViteの仮想モジュールのモックをサポートしています。その動作はJestでの仮想モジュールの扱い方とは異なります。vi.mock関数にvirtual: trueを渡す代わりに、モジュールが存在することをViteに伝える必要があります。そうしないと、パース中に失敗します。これにはいくつかの方法があります。

  1. エイリアスを提供する
ts
import { defineConfig } from 'vitest/config';
import { resolve } from 'node:path';
export default defineConfig({
  test: {
    alias: {
      '$app/forms': resolve('./mocks/forms.js'),
    },
  },
});
  1. 仮想モジュールを解決するプラグインを提供する
ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
  plugins: [
    {
      name: 'virtual-modules',
      resolveId(id) {
        if (id === '$app/forms') {
          return 'virtual:$app/forms';
        }
      },
    },
  ],
});

2番目のアプローチの利点は、異なる仮想エントリーポイントを動的に作成できる点です。複数の仮想モジュールを単一のファイルにリダイレクトすると、それらすべてがvi.mockの影響を受けるため、一意の識別子を使用するようにしてください。

モックの落とし穴 ​

同じファイルの他のメソッド内で呼び出されるメソッドの呼び出しをモックすることはできません。たとえば、このコードでは:

ts
export function foo() {
  return 'foo';
}

export function foobar() {
  return `${foo()}bar`;
}

fooメソッドは直接参照されているため、外部からモックすることはできません。そのため、このコードはfoobar内のfoo呼び出しには影響しません(ただし、他のモジュール内のfoo呼び出しには影響します):

ts
import { vi } from 'vitest';
import * as mod from './foobar.js';

// これは元のモジュールの外部の"foo"にのみ影響する
vi.spyOn(mod, 'foo');
vi.mock('./foobar.js', async importOriginal => {
  return {
    ...(await importOriginal<typeof import('./foobar.js')>()),
    // これは元のモジュールの外部の"foo"にのみ影響する
    foo: () => 'mocked',
  };
});

foobarメソッドに直接実装を提供することで、この動作を確認できます。

ts
import * as mod from './foobar.js';

vi.spyOn(mod, 'foo');

// エクスポートされたfooはモックされたメソッドを参照します。
mod.foobar(mod.foo);
ts
export function foo() {
  return 'foo';
}

export function foobar(injectedFoo) {
  return injectedFoo === foo; // false
}

これは意図された動作です。このような方法でモックが関与する場合、通常はコードの設計が悪い兆候です。コードを複数のファイルにリファクタリングするか、依存性の注入などの手法を使用してアプリケーションアーキテクチャを改善することを検討してください。

例 ​

js
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { Client } from 'pg';
import { failure, success } from './handlers.js';

// todosを取得する
export async function getTodos(event, context) {
  const client = new Client({
    // ...clientOptions
  });

  await client.connect();

  try {
    const result = await client.query('SELECT * FROM todos;');

    client.end();

    return success({
      message: `${result.rowCount} item(s) returned`,
      data: result.rows,
      status: true,
    });
  } catch (e) {
    console.error(e.stack);

    client.end();

    return failure({ message: e, status: false });
  }
}

vi.mock('pg', () => {
  const Client = vi.fn();
  Client.prototype.connect = vi.fn();
  Client.prototype.query = vi.fn();
  Client.prototype.end = vi.fn();

  return { Client };
});

vi.mock('./handlers.js', () => {
  return {
    success: vi.fn(),
    failure: vi.fn(),
  };
});

describe('get a list of todo items', () => {
  let client;

  beforeEach(() => {
    client = new Client();
  });

  afterEach(() => {
    vi.clearAllMocks();
  });

  it('should return items successfully', async () => {
    client.query.mockResolvedValueOnce({ rows: [], rowCount: 0 });

    await getTodos();

    expect(client.connect).toBeCalledTimes(1);
    expect(client.query).toBeCalledWith('SELECT * FROM todos;');
    expect(client.end).toBeCalledTimes(1);

    expect(success).toBeCalledWith({
      message: '0 item(s) returned',
      data: [],
      status: true,
    });
  });

  it('should throw an error', async () => {
    const mError = new Error('Unable to retrieve rows');
    client.query.mockRejectedValueOnce(mError);

    await getTodos();

    expect(client.connect).toBeCalledTimes(1);
    expect(client.query).toBeCalledWith('SELECT * FROM todos;');
    expect(client.end).toBeCalledTimes(1);
    expect(failure).toBeCalledWith({ message: mError, status: false });
  });
});

ファイルシステム ​

ファイルシステムをモックすると、テストが実際のファイルシステムに依存しなくなり、テストの信頼性と予測可能性が向上します。この分離は、以前のテストによる副作用の回避に役立ちます。これにより、アクセス許可の問題、ディスク満杯のシナリオ、読み書きエラーなど、実際のファイルシステムでは再現が困難または不可能なエラー条件やエッジケースをテストできます。

Vitestは、ファイルシステムモックAPIを標準では提供していません。vi.mockを使用してfsモジュールを手動でモックすることはできますが、保守が困難です。代わりに、memfsを使用することをお勧めします。memfsはインメモリファイルシステムを作成し、実際のディスクに触れることなくファイルシステム操作をシミュレートします。このアプローチは高速で安全であり、実際のファイルシステムへの潜在的な副作用を回避できます。

例 ​

すべてのfs呼び出しをmemfsに自動的にリダイレクトするには、プロジェクトのルートに__mocks__/fs.cjsと__mocks__/fs/promises.cjsファイルを作成します。

ts
// `import`も使用できますが、その場合
// すべてのエクスポートを明示的に定義する必要があります

const { fs } = require('memfs');
module.exports = fs;
ts
// `import`も使用できますが、その場合
// すべてのエクスポートを明示的に定義する必要があります

const { fs } = require('memfs');
module.exports = fs.promises;
ts
import { readFileSync } from 'node:fs';

export function readHelloWorld(path) {
  return readFileSync(path, 'utf-8');
}
ts
import { beforeEach, expect, it, vi } from 'vitest';
import { fs, vol } from 'memfs';
import { readHelloWorld } from './read-hello-world.js';

// Vitestに__mocks__フォルダのfsモックを使用するよう指示する
// fsが常にモックされるべき場合は、設定ファイルでこれを行うことができる
vi.mock('node:fs');
vi.mock('node:fs/promises');

beforeEach(() => {
  // インメモリfsの状態をリセットする
  vol.reset();
});

it('should return correct text', () => {
  const path = '/hello-world.txt';
  fs.writeFileSync(path, 'hello world');

  const text = readHelloWorld(path);
  expect(text).toBe('hello world');
});

it('can return a value multiple times', () => {
  // vol.fromJSONを使用して複数のファイルを定義できる
  vol.fromJSON(
    {
      './dir1/hw.txt': 'hello dir1',
      './dir2/hw.txt': 'hello dir2',
    },
    // デフォルトのcwd
    '/tmp'
  );

  expect(readHelloWorld('/tmp/dir1/hw.txt')).toBe('hello dir1');
  expect(readHelloWorld('/tmp/dir2/hw.txt')).toBe('hello dir2');
});

リクエスト ​

VitestはNodeで実行されるため、ネットワークリクエストのモックは複雑です。Web APIが利用できないため、ネットワーク動作を模倣する何かが必要になります。これにはMock Service Workerを使用することをお勧めします。これにより、http、WebSocket、GraphQLのネットワークリクエストをモックでき、フレームワークに依存しません。

Mock Service Worker (MSW) は、テストが行うリクエストをインターセプトすることで機能します。そのため、アプリケーションコードを変更することなく使用できます。ブラウザでは、Service Worker APIを使用します。Node.jsおよびVitestの場合、@mswjs/interceptorsライブラリを使用します。MSWの詳細については、導入を参照してください。

設定 ​

設定ファイルで以下のように使用できます。

js
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { http, HttpResponse } from 'msw';

const posts = [
  {
    userId: 1,
    id: 1,
    title: 'first post title',
    body: 'first post body',
  },
  // ...
];

export const restHandlers = [
  http.get('https://rest-endpoint.example/path/to/posts', () => {
    return HttpResponse.json(posts);
  }),
];

const server = setupServer(...restHandlers);

// すべてのテストの前にサーバーを起動
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));

// すべてのテストの後にサーバーを閉じる
afterAll(() => server.close());

// テストの分離のため、各テストの後にハンドラーをリセットする
afterEach(() => server.resetHandlers());
js
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { graphql, HttpResponse } from 'msw';

const posts = [
  {
    userId: 1,
    id: 1,
    title: 'first post title',
    body: 'first post body',
  },
  // ...
];

const graphqlHandlers = [
  graphql.query('ListPosts', () => {
    return HttpResponse.json({
      data: { posts },
    });
  }),
];

const server = setupServer(...graphqlHandlers);

// すべてのテストの前にサーバーを起動
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));

// すべてのテストの後にサーバーを閉じる
afterAll(() => server.close());

// テストの分離のため、各テストの後にハンドラーをリセットする
afterEach(() => server.resetHandlers());
js
import { afterAll, afterEach, beforeAll } from 'vitest';
import { setupServer } from 'msw/node';
import { ws } from 'msw';

const chat = ws.link('wss://chat.example.com');

const wsHandlers = [
  chat.addEventListener('connection', ({ client }) => {
    client.addEventListener('message', event => {
      console.log('Received message from client:', event.data);
      // 受信したメッセージをクライアントにエコーする
      client.send(`Server received: ${event.data}`);
    });
  }),
];

const server = setupServer(...wsHandlers);

// すべてのテストの前にサーバーを起動
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));

// すべてのテストの後にサーバーを閉じる
afterAll(() => server.close());

// テストの分離のため、各テストの後にハンドラーをリセットする
afterEach(() => server.resetHandlers());

onUnhandledRequest: 'error'でサーバーを設定すると、対応するリクエストハンドラーがないリクエストがあった場合にエラーがスローされます。

その他 ​

MSWにはさらに多くの機能があります。クッキーやクエリパラメータへのアクセス、モックエラーレスポンスの定義など、さまざまなことができます!MSWでできることすべてを見るには、ドキュメントを参照してください。

タイマー ​

タイムアウトやインターバルを含むコードをテストする場合、テストが完了を待ったりタイムアウトしたりする代わりに、setTimeoutやsetIntervalへの呼び出しをモックする「フェイク」タイマーを使用することで、テストを高速化できます。

より詳細なAPIの説明については、vi.useFakeTimers API項目を参照してください。

例 ​

js
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

function executeAfterTwoHours(func) {
  setTimeout(func, 1000 * 60 * 60 * 2); // 2時間
}

function executeEveryMinute(func) {
  setInterval(func, 1000 * 60); // 1分
}

const mock = vi.fn(() => console.log('executed'));

describe('delayed execution', () => {
  beforeEach(() => {
    vi.useFakeTimers();
  });
  afterEach(() => {
    vi.restoreAllMocks();
  });
  it('should execute the function', () => {
    executeAfterTwoHours(mock);
    vi.runAllTimers();
    expect(mock).toHaveBeenCalledTimes(1);
  });
  it('should not execute the function', () => {
    executeAfterTwoHours(mock);
    // 2ms進めても関数はトリガーされない
    vi.advanceTimersByTime(2);
    expect(mock).not.toHaveBeenCalled();
  });
  it('should execute every minute', () => {
    executeEveryMinute(mock);
    vi.advanceTimersToNextTimer();
    expect(mock).toHaveBeenCalledTimes(1);
    vi.advanceTimersToNextTimer();
    expect(mock).toHaveBeenCalledTimes(2);
  });
});

クラス ​

クラス全体をvi.fnの単一の呼び出しでモックできます。すべてのクラスも関数であるため、これはすぐに機能します。現在、Vitestはnewキーワードを考慮しないため、関数の本体ではnew.targetが常にundefinedであることに注意してください。

ts
class Dog {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  static getType(): string {
    return 'animal';
  }

  greet = (): string => {
    return `Hi! My name is ${this.name}!`;
  };

  speak(): string {
    return 'bark!';
  }

  isHungry() {}
  feed() {}
}

このクラスをES5関数で再作成できます。

ts
const Dog = vi.fn(function (name) {
  this.name = name;
  // コンストラクタでインスタンスメソッドをモックする。各インスタンスは独自のスパイを持つことになります。
  this.greet = vi.fn(() => `Hi! My name is ${this.name}!`);
});

// 静的メソッドは関数に直接モックされることに注意してください。
// クラスのインスタンスにはモックされないことに注意してください。
Dog.getType = vi.fn(() => 'mocked animal');

// クラスのすべてのインスタンスで"speak"と"feed"メソッドをモックする
// すべての`new Dog()`インスタンスはこれらのスパイを継承し、共有する
Dog.prototype.speak = vi.fn(() => 'loud bark!');
Dog.prototype.feed = vi.fn();

WARNING

コンストラクタ関数から非プリミティブが返された場合、その値がnew式の結果となります。この場合、[[Prototype]]が正しくバインドされない可能性があります。

ts
const CorrectDogClass = vi.fn(function (name) {
  this.name = name;
});

const IncorrectDogClass = vi.fn(name => ({
  name,
}));

const Marti = new CorrectDogClass('Marti');
const Newt = new IncorrectDogClass('Newt');

Marti instanceof CorrectDogClass; // ✅ true
Newt instanceof IncorrectDogClass; // ❌ false!

いつ使うか?

一般的に、クラスが別のモジュールから再エクスポートされている場合、モジュールファクトリ内でこのようにクラスを再作成することになります。

ts
import { Dog } from './dog.js';

vi.mock(import('./dog.js'), () => {
  const Dog = vi.fn();
  Dog.prototype.feed = vi.fn();
  // ... その他のモック
  return { Dog };
});

このメソッドは、同じインターフェースを受け取る関数にクラスのインスタンスを渡すためにも使用できます。

ts
function feed(dog: Dog) {
  // ...
}
ts
import { expect, test, vi } from 'vitest';
import { feed } from '../src/feed.js';

const Dog = vi.fn();
Dog.prototype.feed = vi.fn();

test('can feed dogs', () => {
  const dogMax = new Dog('Max');

  feed(dogMax);

  expect(dogMax.feed).toHaveBeenCalled();
  expect(dogMax.isHungry()).toBe(false);
});

これで、Dogクラスの新しいインスタンスを作成すると、そのspeakメソッド(feedとgreetとともに)はすでにモックされています。

ts
const Cooper = new Dog('Cooper');
Cooper.speak(); // loud bark!
Cooper.greet(); // Hi! My name is Cooper!

// 組み込みのアサーションを使用して呼び出しの有効性を確認できます。
expect(Cooper.speak).toHaveBeenCalled();
expect(Cooper.greet).toHaveBeenCalled();

const Max = new Dog('Max');

// プロトタイプに割り当てられたメソッドはインスタンス間で共有されます。
expect(Max.speak).toHaveBeenCalled();
expect(Max.greet).not.toHaveBeenCalled();

特定のインスタンスの戻り値を再割り当てできます。

ts
const dog = new Dog('Cooper');

// "vi.mocked"は型ヘルパーです。
// TypeScriptはDogがモックされたクラスであることを認識しないため、
// 関数がモックであるかどうかを検証せずに、任意の関数をMockInstance<T>型でラップします。
vi.mocked(dog.speak).mockReturnValue('woof woof');

dog.speak(); // woof woof

プロパティをモックするには、vi.spyOn(dog, 'name', 'get')メソッドを使用できます。これにより、モックされたプロパティに対してスパイアサーションを使用することが可能になります。

ts
const dog = new Dog('Cooper');

const nameSpy = vi.spyOn(dog, 'name', 'get').mockReturnValue('Max');

expect(dog.name).toBe('Max');
expect(nameSpy).toHaveBeenCalledTimes(1);

TIP

同じメソッドを使用して、ゲッターとセッターをスパイすることもできます。

チートシート ​

INFO

以下の例のviはvitestから直接インポートされています。configでglobalsをtrueに設定すると、グローバルに利用することも可能です。

私は…したい

エクスポートされた変数をモックする ​

js
export const getter = 'variable';
ts
import * as exports from './example.js';

vi.spyOn(exports, 'getter', 'get').mockReturnValue('mocked');

エクスポートされた関数をモックする ​

  1. vi.mockの例:

WARNING

vi.mockの呼び出しはファイルの先頭に巻き上げられることに注意してください。常にすべてのインポートの前に実行されます。

ts
export function method() {}
ts
import { method } from './example.js';

vi.mock('./example.js', () => ({
  method: vi.fn(),
}));
  1. vi.spyOnの例:
ts
import * as exports from './example.js';

vi.spyOn(exports, 'method').mockImplementation(() => {});

エクスポートされたクラスの実装をモックする ​

  1. vi.mockと.prototypeの例:
ts
export class SomeClass {}
ts
import { SomeClass } from './example.js';

vi.mock(import('./example.js'), () => {
  const SomeClass = vi.fn();
  SomeClass.prototype.someMethod = vi.fn();
  return { SomeClass };
});
// SomeClass.mock.instancesはSomeClassのインスタンスを持つ
  1. vi.spyOnの例:
ts
import * as mod from './example.js';

const SomeClass = vi.fn();
SomeClass.prototype.someMethod = vi.fn();

vi.spyOn(mod, 'SomeClass').mockImplementation(SomeClass);

関数から返されたオブジェクトをスパイする ​

  1. キャッシュを使用した例:
ts
export function useObject() {
  return { method: () => true };
}
ts
import { useObject } from './example.js';

const obj = useObject();
obj.method();
ts
import { useObject } from './example.js';

vi.mock(import('./example.js'), () => {
  let _cache;
  const useObject = () => {
    if (!_cache) {
      _cache = {
        method: vi.fn(),
      };
    }
    // これでuseObject()が呼び出されるたびに、
    // 同じオブジェクト参照が返されます。
    return _cache;
  };
  return { useObject };
});

const obj = useObject();
// obj.methodはsome-path内で呼び出されました。
expect(obj.method).toHaveBeenCalled();

モジュールの一部をモックする ​

ts
import { mocked, original } from './some-path.js';

vi.mock(import('./some-path.js'), async importOriginal => {
  const mod = await importOriginal();
  return {
    ...mod,
    mocked: vi.fn(),
  };
});
original(); // 元の動作をする
mocked(); // スパイ関数です。

WARNING

これは外部アクセスのみをモックすることを忘れないでください。この例では、originalが内部でmockedを呼び出す場合、モックファクトリではなく、モジュールで定義された関数が常に呼び出されます。

現在の日付をモックする ​

Dateの時間をモックするには、vi.setSystemTimeヘルパー関数を使用できます。この値は、異なるテスト間で自動的にリセットされません。

vi.useFakeTimersを使用すると、Dateの時間も変更される点に注意してください。

ts
const mockDate = new Date(2022, 0, 1);
vi.setSystemTime(mockDate);
const now = new Date();
expect(now.valueOf()).toBe(mockDate.valueOf());
// モックされた時間をリセットする
vi.useRealTimers();

グローバル変数をモックする ​

globalThisに値を割り当てるか、vi.stubGlobalヘルパーを使用してグローバル変数を設定できます。vi.stubGlobalを使用する場合、unstubGlobals設定オプションを有効にするか、vi.unstubAllGlobalsを手動で呼び出さない限り、異なるテスト間で自動的にリセットされません。

ts
vi.stubGlobal('__VERSION__', '1.0.0');
expect(__VERSION__).toBe('1.0.0');

import.meta.envをモックする ​

  1. 環境変数を変更するには、新しい値を割り当てるだけで済みます。

WARNING

環境変数の値は、異なるテスト間で自動的にリセットされません。

ts
import { beforeEach, expect, it } from 'vitest';

// beforeEachフックで手動でリセットできます。
const originalViteEnv = import.meta.env.VITE_ENV;

beforeEach(() => {
  import.meta.env.VITE_ENV = originalViteEnv;
});

it('changes value', () => {
  import.meta.env.VITE_ENV = 'staging';
  expect(import.meta.env.VITE_ENV).toBe('staging');
});
  1. 値を自動的にリセットしたい場合は、unstubEnvs設定オプションを有効にして(またはbeforeEachフックでvi.unstubAllEnvsを手動で呼び出して)、vi.stubEnvヘルパーを使用できます。
ts
import { expect, it, vi } from 'vitest';

// テスト実行前は"VITE_ENV"は"test"です。
import.meta.env.VITE_ENV === 'test';

it('changes value', () => {
  vi.stubEnv('VITE_ENV', 'staging');
  expect(import.meta.env.VITE_ENV).toBe('staging');
});

it('別のテストを実行する前に値が復元される', () => {
  expect(import.meta.env.VITE_ENV).toBe('test');
});
ts
export default defineConfig({
  test: {
    unstubEnvs: true,
  },
});
Pager
前のページスナップショット
次のページ並列処理

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

Copyright (c) 2021-Present Vitest Team

https://vitest.dev/guide/mocking

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

Copyright (c) 2021-Present Vitest Team