Featured image of post VitestとTesting Libraryによる効率的なフロントエンドテストFeatured image of post VitestとTesting Libraryによる効率的なフロントエンドテスト

VitestとTesting Libraryによる効率的なフロントエンドテスト

Viteネイティブなテスト環境がもたらす開発速度の跳ね上がり

フロントエンドのテストといえば長年Jestが主流でしたが、設定の複雑さやオーバーヘッドが課題でした。Viteの設定を共有する「Vitest」と「React Testing Library」を組み合わせることで、爆速のテスト環境が手に入ります。

保守性が高く壊れにくいテストスイートを構築するための実戦原則をまとめました。


原則:「実装の詳細」ではなく「ユーザーの振る舞い」をテストする

コンポーネントの内部stateを直接テストすると、リファクタリングのたびに壊れる脆いテストになります。ユーザーに見える画面の振る舞いを検証するのが基本です。

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { LoginForm } from './LoginForm';

test('入力からログイン完了までのフローを検証', async () => {
  const user = userEvent.setup();
  render(<LoginForm />);

  await user.type(screen.getByLabelText('メールアドレス'), 'test@example.com');
  await user.click(screen.getByRole('button', { name: 'ログイン' }));

  expect(await screen.findByText('ようこそ')).toBeInTheDocument();
});

非同期更新での落とし穴:クエリ関数の使い分け

  • getBy*: 要素が「今すぐ存在する」ことを同期検証。存在しない場合は即座にエラー。
  • findBy*: API取得など「非同期で遅れて表示される」要素を待機(Promiseを返す)。
  • queryBy*: 要素が「画面に存在しないこと」をアサートする際に使用(nullを返す)。

CI実行時間を削減する並列化のポイント

Vitestはデフォルトでスレッド並列実行を行います。DOM操作を伴うテストでは、テストケースごとに独立性を保つよう afterEach で適切にモックをリセットし、テスト並列数を最大化してCIコストを抑えましょう。