スナップショットテスト
コンポーネントの出力を保存し、変更時に差分を検出するテスト手法
テストフロントエンド
スナップショットテストとは
スナップショットテスト (Snapshot Test) は、コンポーネントやデータの出力を .snap ファイルに保存し、次回のテスト実行時に差分を検出する手法である。意図しない UI の変更を検知するが、意図的な変更時はスナップショットを更新する。
Vitest でのスナップショットテスト
import { describe, it, expect } from 'vitest';
import { render } from '@testing-library/react';
import { UserCard } from './UserCard';
describe('UserCard', () => {
it('renders correctly', () => {
const { container } = render(
<UserCard name="Alice" email="alice@example.com" />
);
expect(container).toMatchSnapshot();
});
});
初回実行時に .snap ファイルが生成される:
// __snapshots__/UserCard.test.tsx.snap
exports[`UserCard renders correctly 1`] = `
<div>
<div class="card">
<h2>Alice</h2>
<p>alice@example.com</p>
</div>
</div>
`;
インラインスナップショット
it('formats price correctly', () => {
expect(formatPrice(1234)).toMatchInlineSnapshot(`"¥1,234"`);
});
.snap ファイルではなく、テストコード内にスナップショットを埋め込む。小さな出力に適している。
スナップショットの更新
# 意図的な変更後にスナップショットを更新
npx vitest --update
メリットとデメリット
| メリット | デメリット |
|---|---|
| 意図しない変更を検知 | 大きなスナップショットはレビューが困難 |
| テストの記述が簡単 | 「とりあえず更新」で形骸化しやすい |
| リグレッション防止 | 実装の詳細に依存 |
効果的な使い方
| ✅ 適する | ❌ 適さない |
|---|---|
| 小さなコンポーネントの出力 | 大きなページ全体 |
| シリアライズ結果 (JSON) | 頻繁に変わる UI |
| エラーメッセージ | 動的なデータ (日時、ID) |
ビジュアルリグレッションテストとの違い
| 観点 | スナップショットテスト | ビジュアルリグレッション |
|---|---|---|
| 比較対象 | HTML / テキスト | スクリーンショット (画像) |
| CSS の変更検知 | ❌ | ✅ |
| ツール | Vitest | Chromatic, Percy |
| 速度 | 高速 | 低速 |
スナップショットテストは HTML 構造の変更を検知するが、CSS の変更 (色、レイアウト) は検知しない。CSS の変更も検知するにはビジュアルリグレッションテスト (Chromatic) を使う。
現場での応用を知るには関連書籍も役立つ。