本記事の執筆にはAIを使用しています。
はじめに
Vitestの特徴、基本的な使い方、主要な関数を紹介します。
初めてVitestを使う方が、テストを書いて実行できるところまでを扱います。
「Vitest」とは?
Viteを利用したJavaScript・TypeScript向けのテストフレームワークです。
「Vitest」は「ヴィーテスト」と読みます。
Viteを使っていないプロジェクトでも利用できます。
環境
- Node.js: 24.13.0
- npm: 11.10.0
- Vitest: 4.1.10
Vitest 4.1.10は、Node.js 22.12.0以上とVite 6.4.0以上を必要とします。
特徴
Viteの設定を共有できる
Vitestは、デフォルトで vite.config.* を読み込みます。
Viteのプラグインやエイリアスなどを、テストでもそのまま使えます。
開発・ビルド・テストで設定が分かれにくいのがメリットです。
TypeScriptとJSXをそのまま扱える
TypeScriptやJSXを追加設定なしで変換できます。
ES Modulesにも対応しています。
変更に関係するテストだけを再実行できる
開発環境で vitest を実行すると、デフォルトでウォッチモードになります。
ソースコードやテストを変更すると、Viteのモジュールグラフを使って関係するテストだけを再実行します。
CIでは、環境変数 CI が存在すると自動で1回だけ実行します。
Jestに近いAPIを使える
テストの書き方、アサーション、モック、スナップショットはJestと互換性のあるAPIです。
Jestを使ったことがあれば、似た書き方で始められます。
テストに必要な機能が揃っている
主に次の機能があります。
- V8またはIstanbulによるカバレッジ計測
-
viによるモック、スタブ、スパイ - スナップショットテスト
-
jsdomまたはhappy-domを使ったDOMのモック - 実ブラウザでテストするBrowser Mode
- テストファイルの並列実行
- 型テスト
- ベンチマーク
基本的な使い方
インストールする
プロジェクトへVitestをインストールします。
$ npm install --save-dev vitest
テスト対象を作る
例として、2つの数値を足す関数を作ります。
export function sum(a: number, b: number): number {
return a + b
}
テストを書く
ファイル名に .test. または .spec. を含めると、デフォルトでテストファイルとして認識されます。
import { describe, expect, test } from 'vitest'
import { sum } from './sum'
describe('sum()', () => {
test('2つの数値を足す', () => {
expect(sum(1, 2)).toBe(3)
})
})
describe() で関連するテストをまとめます。
test() でテストケースを定義し、 expect() で結果を検証します。
npmスクリプトを追加する
package.json へテスト用のスクリプトを追加します。
{
"scripts": {
"test": "vitest",
"test:run": "vitest run"
}
}
テストを実行する
開発中はウォッチモードで実行します。
$ npm test
1回だけ実行する場合は、 vitest run を使います。
CIではこちらを使うと、実行後にプロセスが終了することが明確です。
$ npm run test:run
ファイル名を指定すると、実行するテストを絞れます。
$ npm run test:run -- src/sum.test.ts
主要な関数一覧
テストを定義する関数
| 関数 | 説明 |
|---|---|
test(name, fn) |
テストケースを定義する。 it() は別名 |
describe(name, fn) |
関連するテストをまとめる。 suite() は別名 |
expect(value) |
値を受け取り、マッチャーで検証する |
assert.* |
Chaiのアサーションで検証する |
expectTypeOf(value) |
TypeScriptの型を検証する |
assertType(value) |
値が指定したTypeScriptの型に一致するか検証する |
bench(name, fn) |
実験的なAPIでベンチマークを定義する |
test() と describe() には、実行方法を変える修飾子があります。
| 修飾子 | 説明 |
|---|---|
.only |
指定したテストやスイートだけを実行する |
.skip |
指定したテストやスイートを実行しない |
.todo |
未実装のテストとして記録する |
.concurrent |
複数のテストを並行して実行する |
.fails |
失敗することを想定したテストとして記録する |
.each |
表形式のデータを使って、同じテストを繰り返す |
例えば test.each() を使うと、複数の入力を短く書けます。
test.each([
[1, 2, 3],
[2, 3, 5],
])('sum(%i, %i)は%iを返す', (a, b, expected) => {
expect(sum(a, b)).toBe(expected)
})
セットアップと後片付けをする関数
| 関数 | 実行するタイミング |
|---|---|
beforeAll(fn) |
スイート内の全テストを実行する前に1回 |
afterAll(fn) |
スイート内の全テストを実行したあとに1回 |
beforeEach(fn) |
スイート内の各テストを実行する前 |
afterEach(fn) |
スイート内の各テストを実行したあと |
onTestFinished(fn) |
現在のテストが終了したあと |
onTestFailed(fn) |
現在のテストが失敗したあと |
describe() の中で呼ぶと、そのスイート内のテストにだけ適用されます。
非同期の処理では、Promiseを返すか async 関数を渡します。
import { afterEach, beforeEach, describe, expect, test } from 'vitest'
describe('users', () => {
beforeEach(async () => {
await seedUsers()
})
afterEach(async () => {
await clearUsers()
})
test('ユーザーを取得する', async () => {
await expect(fetchUsers()).resolves.toHaveLength(1)
})
})
よく使うマッチャー
| マッチャー | 説明 |
|---|---|
toBe(expected) |
プリミティブ値や同じオブジェクトかを比較する |
toEqual(expected) |
オブジェクトの中身を再帰的に比較する |
toStrictEqual(expected) |
オブジェクトの型や未定義のプロパティも含めて厳密に比較する |
toBeTruthy() / toBeFalsy()
|
真または偽として扱われる値かを検証する |
toBeNull() / toBeUndefined()
|
null または undefined かを検証する |
toContain(value) |
配列や文字列に値が含まれるかを検証する |
toMatch(pattern) |
文字列が文字列または正規表現に一致するかを検証する |
toHaveLength(length) |
文字列や配列の長さを検証する |
toHaveProperty(key, value?) |
オブジェクトがプロパティを持つかを検証する |
toThrow(error?) |
関数が例外を投げるかを検証する |
toMatchSnapshot() |
値が保存済みのスナップショットと一致するかを検証する |
toHaveBeenCalled() |
モック関数が呼ばれたかを検証する |
toHaveBeenCalledWith(...args) |
モック関数が指定した引数で呼ばれたかを検証する |
否定するときは .not を付けます。
Promiseの成功を検証するときは .resolves 、失敗を検証するときは .rejects を付けて await します。
expect(sum(1, 2)).not.toBe(4)
await expect(Promise.resolve('OK')).resolves.toBe('OK')
await expect(Promise.reject(new Error('失敗'))).rejects.toThrow('失敗')
モックを扱う主な関数
モック関連の関数は、 vi オブジェクトにまとまっています。
| 関数 | 説明 |
|---|---|
vi.fn(implementation?) |
モック関数を作る |
vi.spyOn(object, method) |
既存オブジェクトのメソッドを監視する |
vi.mock(path, factory?) |
モジュールをモックする |
vi.mocked(value) |
TypeScript上でモックの型を付ける |
vi.clearAllMocks() |
すべてのモックの呼び出し履歴を消す |
vi.resetAllMocks() |
履歴を消し、モックの実装をリセットする |
vi.restoreAllMocks() |
vi.spyOn() で置き換えたメソッドを元へ戻す |
vi.useFakeTimers() |
日時やタイマーをテスト用の偽物へ置き換える |
vi.useRealTimers() |
本物の日時やタイマーへ戻す |
vi.stubGlobal(name, value) |
グローバル変数を一時的に置き換える |
vi.stubEnv(name, value) |
環境変数を一時的に置き換える |
import { expect, test, vi } from 'vitest'
test('コールバックを1回呼ぶ', () => {
const callback = vi.fn()
callback('hello')
expect(callback).toHaveBeenCalledOnce()
expect(callback).toHaveBeenCalledWith('hello')
})
おわりに
Vitestは、短い設定でTypeScriptのテストを始められます。
まずは test() 、 describe() 、 expect() から使い、必要に応じてフックやモックを追加してみてください ![]()