モック
テストを作成する際、内部または外部サービスの「偽の」バージョンを作成する必要が生じることがよくあります。これは一般的にモックと呼ばれます。Vitestは、vi
ヘルパーを通じて、そのためのユーティリティを提供します。vitest
からインポートするか、global
設定が有効になっている場合はグローバルにアクセスできます。
WARNING
各テスト実行の前後に、必ずモックをクリアまたは復元して、テスト実行間でモックの状態変更が残らないようにしてください。詳細については、mockReset
のドキュメントを参照してください。
vi.fn
、vi.mock
、vi.spyOn
メソッドに慣れていない場合は、まずAPI項目を確認してください。
日付
テストの一貫性を確保するために、日付を制御する必要がある場合があります。Vitestは、タイマーとシステム日付を操作するために@sinonjs/fake-timers
パッケージを使用します。特定のAPIの詳細は、こちらをご覧ください。
例
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()
の戻り値のみが呼び出し可能です。
例
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);
});
});
その他
グローバル変数
jsdom
やnode
に存在しないグローバル変数をモックするには、vi.stubGlobal
ヘルパーを使用できます。これにより、グローバル変数の値がglobalThis
に設定されます。
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に伝える必要があります。そうしないと、パース中に失敗します。これにはいくつかの方法があります。
- エイリアスを提供する
import { defineConfig } from 'vitest/config';
import { resolve } from 'node:path';
export default defineConfig({
test: {
alias: {
'$app/forms': resolve('./mocks/forms.js'),
},
},
});
- 仮想モジュールを解決するプラグインを提供する
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
の影響を受けるため、一意の識別子を使用するようにしてください。
モックの落とし穴
同じファイルの他のメソッド内で呼び出されるメソッドの呼び出しをモックすることはできません。たとえば、このコードでは:
export function foo() {
return 'foo';
}
export function foobar() {
return `${foo()}bar`;
}
foo
メソッドは直接参照されているため、外部からモックすることはできません。そのため、このコードはfoobar
内のfoo
呼び出しには影響しません(ただし、他のモジュール内のfoo
呼び出しには影響します):
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
メソッドに直接実装を提供することで、この動作を確認できます。
import * as mod from './foobar.js';
vi.spyOn(mod, 'foo');
// エクスポートされたfooはモックされたメソッドを参照します。
mod.foobar(mod.foo);
export function foo() {
return 'foo';
}
export function foobar(injectedFoo) {
return injectedFoo === foo; // false
}
これは意図された動作です。このような方法でモックが関与する場合、通常はコードの設計が悪い兆候です。コードを複数のファイルにリファクタリングするか、依存性の注入などの手法を使用してアプリケーションアーキテクチャを改善することを検討してください。
例
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
ファイルを作成します。
// `import`も使用できますが、その場合
// すべてのエクスポートを明示的に定義する必要があります
const { fs } = require('memfs');
module.exports = fs;
// `import`も使用できますが、その場合
// すべてのエクスポートを明示的に定義する必要があります
const { fs } = require('memfs');
module.exports = fs.promises;
import { readFileSync } from 'node:fs';
export function readHelloWorld(path) {
return readFileSync(path, 'utf-8');
}
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の詳細については、導入を参照してください。
設定
設定ファイルで以下のように使用できます。
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());
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());
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項目を参照してください。
例
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
であることに注意してください。
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関数で再作成できます。
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]]
が正しくバインドされない可能性があります。
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!
いつ使うか?
一般的に、クラスが別のモジュールから再エクスポートされている場合、モジュールファクトリ内でこのようにクラスを再作成することになります。
import { Dog } from './dog.js';
vi.mock(import('./dog.js'), () => {
const Dog = vi.fn();
Dog.prototype.feed = vi.fn();
// ... その他のモック
return { Dog };
});
このメソッドは、同じインターフェースを受け取る関数にクラスのインスタンスを渡すためにも使用できます。
function feed(dog: Dog) {
// ...
}
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
とともに)はすでにモックされています。
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();
特定のインスタンスの戻り値を再割り当てできます。
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')
メソッドを使用できます。これにより、モックされたプロパティに対してスパイアサーションを使用することが可能になります。
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
に設定すると、グローバルに利用することも可能です。
私は…したい
エクスポートされた変数をモックする
export const getter = 'variable';
import * as exports from './example.js';
vi.spyOn(exports, 'getter', 'get').mockReturnValue('mocked');
エクスポートされた関数をモックする
vi.mock
の例:
WARNING
vi.mock
の呼び出しはファイルの先頭に巻き上げられることに注意してください。常にすべてのインポートの前に実行されます。
export function method() {}
import { method } from './example.js';
vi.mock('./example.js', () => ({
method: vi.fn(),
}));
vi.spyOn
の例:
import * as exports from './example.js';
vi.spyOn(exports, 'method').mockImplementation(() => {});
エクスポートされたクラスの実装をモックする
vi.mock
と.prototype
の例:
export class SomeClass {}
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のインスタンスを持つ
vi.spyOn
の例:
import * as mod from './example.js';
const SomeClass = vi.fn();
SomeClass.prototype.someMethod = vi.fn();
vi.spyOn(mod, 'SomeClass').mockImplementation(SomeClass);
関数から返されたオブジェクトをスパイする
- キャッシュを使用した例:
export function useObject() {
return { method: () => true };
}
import { useObject } from './example.js';
const obj = useObject();
obj.method();
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();
モジュールの一部をモックする
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
の時間も変更される点に注意してください。
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
を手動で呼び出さない限り、異なるテスト間で自動的にリセットされません。
vi.stubGlobal('__VERSION__', '1.0.0');
expect(__VERSION__).toBe('1.0.0');
import.meta.env
をモックする
- 環境変数を変更するには、新しい値を割り当てるだけで済みます。
WARNING
環境変数の値は、異なるテスト間で自動的にリセットされません。
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');
});
- 値を自動的にリセットしたい場合は、
unstubEnvs
設定オプションを有効にして(またはbeforeEach
フックでvi.unstubAllEnvs
を手動で呼び出して)、vi.stubEnv
ヘルパーを使用できます。
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');
});
export default defineConfig({
test: {
unstubEnvs: true,
},
});