はじめに
フロントエンド開発でテストを書くとき、「テストの実行が遅い」「設定が面倒」という悩みを抱えていませんか。
正直なところ、Jestでそこまで困っていなかったんですよ。でもVitestを使い始めたら、もう戻れなくなりました。GitHubで15,600スター以上を獲得していて、毎月7,700万ダウンロードという数字が人気を物語っています。
Vitestは、Viteで駆動される次世代テストフレームワークです。Viteを使っているプロジェクトなら、設定をそのまま再利用できるのがポイント。テストのためだけに別の設定を書く必要がないんですよね。
特徴・メリット
1. とにかく速い
これ、体感で全然違います。Viteのインフラを活用しているので、テストの起動から実行まで爆速。
特にウォッチモードが優秀で、変更したファイルに関連するテストだけを再実行してくれる。HMRみたいに即座にフィードバックが返ってくるので、TDDがストレスなくできます。
30代になって思うのは、こういう「待ち時間」の積み重ねが馬鹿にならないということ。テスト実行のたびに数秒待つのと、ほぼ即座に結果が返ってくるのでは、開発効率が全然違う。
2. Jest互換のAPI
個人的にはこれが一番助かりました。expect、describe、test、it...Jestと同じ書き方でテストが書けます。
スナップショットテストもそのまま使えるし、モックもviオブジェクトで同じような感覚で書ける。既存のJestテストをほぼそのまま移行できるのは大きいですね。
3. TypeScript/ESM対応がネイティブ
esbuildで動作するので、TypeScriptやJSX、ESMがそのまま使えます。Jestだとts-jestやbabel-jestの設定が必要だったりしますが、Vitestなら追加設定不要。
これ、意外と地味に嬉しいポイントです。設定ファイルと格闘する時間が減る。
4. Viteの設定を再利用
Viteを使っているプロジェクトなら、vite.config.tsの設定がそのままテストでも使えます。プラグイン、リゾルバ、エイリアス...全部共有できる。
アプリケーションとテストで設定が乖離しないので、「テスト環境だけ動かない」みたいな問題が起きにくいですね。
5. 充実したテスト機能
コードカバレッジはv8またはIstanbulでネイティブサポート。ブラウザモードでコンポーネントテストも実行できる。ベンチマークテストもTinybenchで対応。
Vue、React、Svelte、Lit、Marko...主要なフレームワークのコンポーネントテストに対応しているのも心強い。
インストール方法
前提条件
Vite ≧ v6.0.0、Node.js ≧ v20.0.0が必要です。
インストール
お好みのパッケージマネージャーでインストールできます。
# npm
npm install -D vitest
# yarn
yarn add -D vitest
# pnpm
pnpm add -D vitest
# bun
bun add -D vitest
package.jsonの設定
テスト実行用のスクリプトを追加します。
{
"scripts": {
"test": "vitest",
"test:run": "vitest run",
"coverage": "vitest run --coverage"
}
}
test: ウォッチモードでテスト実行test:run: 一度だけテスト実行coverage: カバレッジ付きでテスト実行
基本的な使い方
テストファイルの命名規則
以下のパターンがデフォルトで認識されます。
*.test.ts/*.test.js*.spec.ts/*.spec.js__tests__ディレクトリ内のファイル
基本的なテストの書き方
テスト対象のコード:
// sum.ts
export function sum(a: number, b: number): number {
return a + b
}
テストコード:
// sum.test.ts
import { describe, it, expect } from 'vitest'
import { sum } from './sum'
describe('sum', () => {
it('1 + 2 は 3 になる', () => {
expect(sum(1, 2)).toBe(3)
})
it('負の数も正しく計算できる', () => {
expect(sum(-1, -2)).toBe(-3)
})
})
vitest.config.ts
設定ファイルはvite.config.tsを拡張するか、別ファイルで定義できます。
// vitest.config.ts
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
globals: true, // describe, itなどをグローバルで使用
environment: 'jsdom', // DOMテスト用の環境
include: ['src/**/*.{test,spec}.{ts,tsx}'],
coverage: {
provider: 'v8', // カバレッジプロバイダー
reporter: ['text', 'json', 'html'],
},
},
})
モック
viオブジェクトを使ってモックを作成します。
import { vi, describe, it, expect } from 'vitest'
// 関数のモック
const mockFn = vi.fn()
mockFn.mockReturnValue('mocked')
// モジュールのモック
vi.mock('./api', () => ({
fetchData: vi.fn().mockResolvedValue({ data: 'test' })
}))
describe('モックのテスト', () => {
it('モック関数が呼ばれる', () => {
mockFn()
expect(mockFn).toHaveBeenCalled()
})
})
非同期テスト
import { describe, it, expect } from 'vitest'
async function fetchUser(id: number) {
const response = await fetch(`/api/users/${id}`)
return response.json()
}
describe('非同期処理のテスト', () => {
it('ユーザーデータを取得できる', async () => {
const user = await fetchUser(1)
expect(user).toHaveProperty('name')
})
})
実践的なユースケース
Reactコンポーネントのテスト
npm install -D @testing-library/react jsdom
// Button.test.tsx
import { describe, it, expect } from 'vitest'
import { render, screen, fireEvent } from '@testing-library/react'
import { Button } from './Button'
describe('Button', () => {
it('クリックでハンドラーが呼ばれる', () => {
const handleClick = vi.fn()
render(<Button onClick={handleClick}>Click me</Button>)
fireEvent.click(screen.getByText('Click me'))
expect(handleClick).toHaveBeenCalledTimes(1)
})
})
スナップショットテスト
import { describe, it, expect } from 'vitest'
import { render } from '@testing-library/react'
import { Card } from './Card'
describe('Card', () => {
it('スナップショットと一致する', () => {
const { container } = render(
<Card title="Test" description="Description" />
)
expect(container).toMatchSnapshot()
})
})
カバレッジの確認
npm run coverage
これでターミナルにカバレッジが表示され、coverage/ディレクトリにHTML形式のレポートも生成されます。
Jestからの移行
コスパ的に、Jestからの移行は十分価値があります。
移行のポイント:
jest.fn()をvi.fn()に置き換えjest.mock()をvi.mock()に置き換え@jest/globalsをvitestからimportに変更- 設定ファイルを
vitest.config.tsに移行
ほとんどのテストコードはそのまま動きます。時短になる。
まとめ
Vitestを導入して感じた変化:
- テスト実行: 体感で2〜3倍速くなった
- 設定ファイル: Viteと共有できて大幅に簡素化
- 移行コスト: Jestからほぼそのまま移行できた
- QOL: 確実に上がった
正直なところ、Viteを使っているプロジェクトでJestを選ぶ理由はもうないと思います。設定の二重管理がなくなるだけでも十分な理由になる。
特にTypeScriptとの相性が良くて、追加設定なしでそのまま動く。テストを書くハードルが確実に下がります。
まだ試していない人は、まず小さなプロジェクトで使ってみてください。ウォッチモードの速さに感動しますよ。