モック関数
vi.fn
メソッドを使用すると、モック関数を作成し、その実行を追跡できます。既存のオブジェクトのメソッドを追跡したい場合は、vi.spyOn
メソッドを使用します。
import { vi } from 'vitest';
const fn = vi.fn();
fn('hello world');
fn.mock.calls[0] === ['hello world'];
const market = {
getApples: () => 100,
};
const getApplesSpy = vi.spyOn(market, 'getApples');
market.getApples();
getApplesSpy.mock.calls.length === 1;
モックの結果を検証するには、expect
のモックアサーション(例: toHaveBeenCalled
)を使用します。このAPIリファレンスでは、モックの動作を制御するために利用できるプロパティとメソッドについて説明します。
TIP
以下の型におけるカスタム関数実装は、ジェネリック <T>
でマークされています。
getMockImplementation
function getMockImplementation(): T | undefined;
現在のモック実装が存在する場合、それを返します。
モックが vi.fn
で作成された場合、提供されたメソッドがモック実装として使用されます。
モックが vi.spyOn
で作成された場合、カスタム実装が提供されない限り undefined
を返します。
getMockName
function getMockName(): string;
.mockName(name)
メソッドでモックに割り当てられた名前を返します。デフォルトでは、vi.fn()
を返します。
mockClear
function mockClear(): MockInstance<T>;
すべての呼び出しに関する情報をクリアします。このメソッドを呼び出した後、.mock
のすべてのプロパティは初期状態に戻ります。ただし、このメソッドは実装をリセットしません。異なる検証の間でモックを整理するのに役立ちます。
const person = {
greet: (name: string) => `Hello ${name}`,
};
const spy = vi.spyOn(person, 'greet').mockImplementation(() => 'mocked');
expect(person.greet('Alice')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Alice']]);
// 呼び出し履歴をクリアするが、モック実装は保持する
spy.mockClear();
expect(spy.mock.calls).toEqual([]);
expect(person.greet('Bob')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Bob']]);
各テストの前にこのメソッドを自動的に呼び出すには、設定で clearMocks
設定を有効にします。
mockName
function mockName(name: string): MockInstance<T>;
内部モック名を設定します。これは、アサーションが失敗したときにモックを識別するのに役立ちます。
mockImplementation
function mockImplementation(fn: T): MockInstance<T>;
モック実装として使用する関数を受け入れます。TypeScript は、引数と戻り値の型が元の関数と一致することを期待します。
const mockFn = vi.fn().mockImplementation((apples: number) => apples + 1);
// or: vi.fn(apples => apples + 1);
const NelliesBucket = mockFn(0);
const BobsBucket = mockFn(1);
NelliesBucket === 1; // true
BobsBucket === 2; // true
mockFn.mock.calls[0][0] === 0; // true
mockFn.mock.calls[1][0] === 1; // true
mockImplementationOnce
function mockImplementationOnce(fn: T): MockInstance<T>;
モック実装として使用する関数を受け入れます。TypeScript は、引数と戻り値の型が元の関数と一致することを期待します。このメソッドは、複数の関数呼び出しに対して異なる結果を生成するためにチェーンできます。
const myMockFn = vi
.fn()
.mockImplementationOnce(() => true) // 1st call
.mockImplementationOnce(() => false); // 2nd call
myMockFn(); // 1st call: true
myMockFn(); // 2nd call: false
モックされた関数に実装がなくなった場合、vi.fn(() => defaultValue)
または .mockImplementation(() => defaultValue)
が呼び出されていれば、それらで設定されたデフォルトの実装を呼び出します。
const myMockFn = vi
.fn(() => 'default')
.mockImplementationOnce(() => 'first call')
.mockImplementationOnce(() => 'second call');
// 'first call', 'second call', 'default', 'default'
console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());
withImplementation
function withImplementation(fn: T, cb: () => void): MockInstance<T>;
function withImplementation(
fn: T,
cb: () => Promise<void>
): Promise<MockInstance<T>>;
コールバックが実行されている間、元のモック実装を一時的にオーバーライドします。
const myMockFn = vi.fn(() => 'original');
myMockFn.withImplementation(
() => 'temp',
() => {
myMockFn(); // 'temp'
}
);
myMockFn(); // 'original'
非同期コールバックと一緒に使用できます。元の実装を後で使用するには、このメソッドを await
する必要があります。
test('async callback', async () => {
const myMockFn = vi.fn(() => 'original');
// コールバックが非同期なので、この呼び出しを待機します
await myMockFn.withImplementation(
() => 'temp',
async () => {
myMockFn(); // 'temp'
}
);
myMockFn(); // 'original'
});
このメソッドは mockImplementationOnce
より優先的に適用されることに注意してください。
mockRejectedValue
function mockRejectedValue(value: unknown): MockInstance<T>;
非同期関数が呼び出されたときに拒否されるエラーを指定します。
const asyncMock = vi.fn().mockRejectedValue(new Error('Async error'));
await asyncMock(); // throws Error<'Async error'>
mockRejectedValueOnce
function mockRejectedValueOnce(value: unknown): MockInstance<T>;
次の関数呼び出しで拒否される値を指定します。チェーンされている場合、連続する各呼び出しは指定された値を拒否します。
const asyncMock = vi
.fn()
.mockResolvedValueOnce('first call')
.mockRejectedValueOnce(new Error('Async error'));
await asyncMock(); // 'first call'
await asyncMock(); // throws Error<'Async error'>
mockReset
function mockReset(): MockInstance<T>;
mockClear
と同様に、内部実装を元の関数にリセットします。 これにより、すべての一度限りの実装もリセットされます。
vi.fn()
からのモックをリセットすると、実装は undefined
を返す空の関数に設定されることに注意してください。 vi.fn(impl)
からのモックをリセットすると、実装は impl
に復元されます。
これは、モックを元の状態にリセットしたい場合に役立ちます。
const person = {
greet: (name: string) => `Hello ${name}`,
};
const spy = vi.spyOn(person, 'greet').mockImplementation(() => 'mocked');
expect(person.greet('Alice')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Alice']]);
// 呼び出し履歴をクリアし、実装をリセットするが、メソッドはまだスパイされている
spy.mockReset();
expect(spy.mock.calls).toEqual([]);
expect(person.greet).toBe(spy);
expect(person.greet('Bob')).toBe('Hello Bob');
expect(spy.mock.calls).toEqual([['Bob']]);
各テストの前にこのメソッドを自動的に呼び出すには、設定で mockReset
設定を有効にします。
mockRestore
function mockRestore(): MockInstance<T>;
mockReset
と同様に、スパイされたオブジェクトの元のディスクリプタを復元します。
vi.fn()
で作成されたモックを復元すると、実装は undefined
を返す空の関数に設定されることに注意してください。 vi.fn(impl)
で作成されたモックを復元すると、実装は impl
に復元されます。
const person = {
greet: (name: string) => `Hello ${name}`,
};
const spy = vi.spyOn(person, 'greet').mockImplementation(() => 'mocked');
expect(person.greet('Alice')).toBe('mocked');
expect(spy.mock.calls).toEqual([['Alice']]);
// 呼び出し履歴をクリアし、スパイされたオブジェクトメソッドを復元する
spy.mockRestore();
expect(spy.mock.calls).toEqual([]);
expect(person.greet).not.toBe(spy);
expect(person.greet('Bob')).toBe('Hello Bob');
expect(spy.mock.calls).toEqual([]);
各テストの前にこのメソッドを自動的に呼び出すには、設定で restoreMocks
設定を有効にします。
mockResolvedValue
function mockResolvedValue(value: Awaited<ReturnType<T>>): MockInstance<T>;
非同期関数が呼び出されたときに解決される値を指定します。TypeScript は、元の関数の戻り値の型と一致する値のみを受け入れます。
const asyncMock = vi.fn().mockResolvedValue(42);
await asyncMock(); // 42
mockResolvedValueOnce
function mockResolvedValueOnce(value: Awaited<ReturnType<T>>): MockInstance<T>;
次の関数呼び出しで解決される値を指定します。TypeScript は、元の関数の戻り値の型と一致する値のみを受け入れます。チェーンされている場合、連続する各呼び出しは指定された値を解決します。
const asyncMock = vi
.fn()
.mockResolvedValue('default')
.mockResolvedValueOnce('first call')
.mockResolvedValueOnce('second call');
await asyncMock(); // first call
await asyncMock(); // second call
await asyncMock(); // default
await asyncMock(); // default
mockReturnThis
function mockReturnThis(): MockInstance<T>;
実際の実装を呼び出さずに、メソッドから this
コンテキストを返す必要がある場合に使用します。これは次の省略形です。
spy.mockImplementation(function () {
return this;
});
mockReturnValue
function mockReturnValue(value: ReturnType<T>): MockInstance<T>;
モック関数が呼び出されるたびに返される値を指定します。TypeScript は、元の関数の戻り値の型と一致する値のみを受け入れます。
const mock = vi.fn();
mock.mockReturnValue(42);
mock(); // 42
mock.mockReturnValue(43);
mock(); // 43
mockReturnValueOnce
function mockReturnValueOnce(value: ReturnType<T>): MockInstance<T>;
モック関数が呼び出されるたびに返される値を指定します。TypeScript は、元の関数の戻り値の型と一致する値のみを受け入れます。
モックされた関数に実装がなくなった場合、vi.fn(() => defaultValue)
または .mockImplementation(() => defaultValue)
が呼び出されていれば、それらで設定されたデフォルトの実装を呼び出します。
const myMockFn = vi
.fn()
.mockReturnValue('default')
.mockReturnValueOnce('first call')
.mockReturnValueOnce('second call');
// 'first call', 'second call', 'default', 'default'
console.log(myMockFn(), myMockFn(), myMockFn(), myMockFn());
mock.calls
const calls: Parameters<T>[];
これは、各呼び出しの引数をすべて含む配列です。配列の各項目は、それぞれの呼び出しの引数です。
const fn = vi.fn();
fn('arg1', 'arg2');
fn('arg3');
fn.mock.calls ===
[
['arg1', 'arg2'], // first call
['arg3'], // second call
];
mock.lastCall
const lastCall: Parameters<T> | undefined;
最後の呼び出しの引数が含まれます。モックが呼び出されなかった場合、undefined
を返します。
mock.results
interface MockResultReturn<T> {
type: 'return';
/**
* 関数から返された値。
* 関数がPromiseを返した場合、これは解決された値になります。
*/
value: T;
}
interface MockResultIncomplete {
type: 'incomplete';
value: undefined;
}
interface MockResultThrow {
type: 'throw';
/**
* 関数実行中にスローされたエラー。
*/
value: any;
}
type MockResult<T> =
| MockResultReturn<T>
| MockResultThrow
| MockResultIncomplete;
const results: MockResult<ReturnType<T>>[];
これは、関数から返されたすべての値を含む配列です。配列の各項目は、type
と value
プロパティを持つオブジェクトです。利用可能な型は次のとおりです。
'return'
- 関数が例外をスローせずに返された。'throw'
- 関数が値をスローした。
value
プロパティには、返された値またはスローされたエラーが含まれます。関数が Promise
を返した場合、Promise が拒否された場合でも result
は常に 'return'
になります。
const fn = vi
.fn()
.mockReturnValueOnce('result')
.mockImplementationOnce(() => {
throw new Error('thrown error');
});
const result = fn(); // returned 'result'
try {
fn(); // threw Error
} catch {}
fn.mock.results ===
[
// first result
{
type: 'return',
value: 'result',
},
// last result
{
type: 'throw',
value: Error,
},
];
mock.settledResults
interface MockSettledResultFulfilled<T> {
type: 'fulfilled';
value: T;
}
interface MockSettledResultRejected {
type: 'rejected';
value: any;
}
export type MockSettledResult<T> =
| MockSettledResultFulfilled<T>
| MockSettledResultRejected;
const settledResults: MockSettledResult<Awaited<ReturnType<T>>>[];
関数から解決または拒否されたすべての値を含む配列です。
関数が解決または拒否されなかった場合、この配列は空になります。
const fn = vi.fn().mockResolvedValueOnce('result');
const result = fn();
fn.mock.settledResults === [];
await result;
fn.mock.settledResults ===
[
{
type: 'fulfilled',
value: 'result',
},
];
mock.invocationCallOrder
const invocationCallOrder: number[];
このプロパティはモック関数の実行順序を示します。これは、定義されたすべてのモック間で共有される数値の配列です。
const fn1 = vi.fn();
const fn2 = vi.fn();
fn1();
fn2();
fn1();
fn1.mock.invocationCallOrder === [1, 3];
fn2.mock.invocationCallOrder === [2];
mock.contexts
const contexts: ThisParameterType<T>[];
このプロパティは、モック関数への各呼び出し中に使用された this
値の配列です。
const fn = vi.fn();
const context = {};
fn.apply(context);
fn.call(context);
fn.mock.contexts[0] === context;
fn.mock.contexts[1] === context;
mock.instances
const instances: ReturnType<T>[];
このプロパティは、モックが new
キーワードで呼び出されたときに作成されたすべてのインスタンスを含む配列です。これは関数の実際のコンテキスト (this
) であり、戻り値ではないことに注意してください。
WARNING
モックが new MyClass()
でインスタンス化された場合、mock.instances
は1つの値を持つ配列になります。
const MyClass = vi.fn();
const a = new MyClass();
MyClass.mock.instances[0] === a;
コンストラクタから値を返した場合、それは instances
配列には含まれず、代わりに results
に含まれます。
const Spy = vi.fn(() => ({ method: vi.fn() }));
const a = new Spy();
Spy.mock.instances[0] !== a;
Spy.mock.results[0] === a;