--- name: frontend-typescript-testing description: リポジトリで設定済みのReactテスト・ブラウザハーネスを使用してフロントエンドテストを設計。RTL、MSW、Vitest、Playwrightが存在する場合に適用。コンポーネント、loading/error state、統合、フロントエンドE2Eテストの追加・レビュー時に使用。 --- # TypeScript テストルール(フロントエンド) ## 前提条件の検出 フレームワークやコマンドを選択する前に、`package.json`、ロックファイル、テスト設定、既存テストのimportを確認する。Vitest、React Testing Library、MSW、Playwright固有のルールは、依存または設定が存在する場合にのみ適用する。異なるフレームワークが設定されている場合は、リポジトリの同等機能を使用する。実行可能なハーネスを特定できない場合は、作り出さずに、確認したpathと不足しているフレームワークまたはコマンドを報告する。 ## 参照 | テスト種別 | 参照先 | 用途 | |-----------|--------|------| | **ユニット / 統合** | 本ドキュメント | RTL + Vitest + MSW での React コンポーネントテスト | | **E2E** | [references/e2e.md](references/e2e.md) | Playwright によるブラウザレベル E2E テスト | ## テストフレームワーク - **Vitest**: リポジトリ設定または既存テストで選択されている場合に使用 - **React Testing Library**: コンポーネントテスト用 - **MSW (Mock Service Worker)**: APIモック用 - テストのインポート: `import { describe, it, expect, beforeEach, vi } from 'vitest'` - コンポーネントテストのインポート: `import { render, screen } from '@testing-library/react'` - ユーザー操作: `import userEvent from '@testing-library/user-event'` - モックの作成: `vi.mock()` を使用 ## テストの基本方針 ### 品質要件 - **リグレッション保護**: クリティカルパスと再利用度の高いコンポーネントでは、明記された受け入れ結果、公開分岐、失敗状態を検証する - **独立性**: 各テストは他のテストに依存せず実行可能 - **再現性**: 時刻、乱数、環境値、ネットワークレスポンス、ブラウザstateを制御し、同一の入力から同一の観測可能な結果を得る - **可読性**: 各テストはユーザーから見える振る舞いを1つだけ名前で示し、setup・action・assertionを分け、その振る舞いで使用する値だけをfixtureに含める ### テストの重点配分 複数の機能で再利用される共有コンポーネント、Custom hook、utilityは、リグレッションの影響範囲が広いため、公開分岐、error state、境界の契約を検証する。振る舞いが複数のrender済みユニットに依存するページ単位の構成は、統合/E2Eテストで検証する。 ### テストの種類と範囲 1. **単体テスト(React Testing Library)** - 個々のコンポーネントや関数の動作を検証 - 外部依存はすべてモック化 - 最も数が多く、細かい粒度で実施 - ユーザーから観測可能な振る舞いに焦点を当てる 2. **統合テスト(React Testing Library + MSW)** - 複数のコンポーネントの連携を検証 - MSW(Mock Service Worker)でAPIをモック - 実際のDB接続なし(DBはバックエンドが管理) - 主要な受け入れ基準を実装するフロー、または複数のrender済みコンポーネントが連携するフローを検証 3. **機能横断検証** - 新機能が共有の統合ポイントに及び、その失敗が主要なユーザージャーニーまたは契約を壊す、あるいは副次的な観測可能な振る舞いを劣化させる場合は、既存機能の継続性を証明義務とする。その失敗を露出できる最も安い境界で証明する - 検証パターン: 既存機能動作 → 新機能有効化 → 既存機能の継続性確認 - 判定基準: 元の受け入れ基準で指定された表示内容とインタラクションの振る舞いを維持する。レンダリング時間のしきい値は、プロジェクト設定または要件で値と計測方法が定義されている場合にのみ適用する - CI/CDでの自動実行を前提とした設計 ## テストの実装規約 ### ディレクトリ構造と命名規則 - コンポーネントのテストはそのコンポーネント自身のディレクトリに置き、実装とテストが一緒に移動する状態を保つ(Co-location原則) - テストファイル: `{ComponentName}.test.tsx` - 統合テストファイル: `{FeatureName}.integration.test.tsx` - テストスイート: 対象のコンポーネントや機能を説明する名前 - テストケース: ユーザー視点から期待される動作を説明する名前 ### テストコードの品質ルール コミットするテストはすべて有効に保つ。現行の振る舞いを保護するテストは修復する。テストを削除するのは、対象の振る舞いが不要になったことを元の要件または実装契約で確認できる場合に限る。 ## モックの型安全性の徹底 MSWハンドラーのresponse bodyは、それが代表するドメイン型に対して `satisfies` で制約する。契約から乖離したfixtureをコンパイル時に落とし、アプリが実際には受け取らない形に対してテストが通ってしまう状態を防ぐ。 コンポーネントや依存のモックには、テスト対象が実際に利用する範囲だけを型付けする(`Pick`、`Pick`)。インターフェース全体は型付けせず、リテラルは `satisfies` で制約して余分なメンバーや誤った名前をコンパイル時に落とす。 ## テスト設計パターン 実装詳細ではなくユーザーから見える結果を検証する。クエリはユーザーが認識できるroleとaccessible name(`getByRole`/`getByLabelText`/`getByText`)で行い、`getByTestId` や `container.querySelector` に依存しない。操作は生のイベント発火ではなく、テストごとに `userEvent.setup()` した `userEvent` 経由で行い、ブラウザのイベント列を再現する。操作と非同期アサーションはすべて `await` する — awaitしない操作は更新前のrender結果に対してアサーションすることになるため、非同期UIは `findBy*` で待機する。 正常系だけでなく空・エラー・ローディング/非同期の状態も網羅する。error stateは共有ハンドラ集合を変更せず、そのテスト1件だけMSWハンドラを上書きして作る。 必要なUI state、accessible name、外部契約が不明な場合は、そのアサーションのテスト設計を止め、必要なUI Spec、受け入れ基準、実装契約、ユーザー判断を具体的に示す。期待する振る舞いを確認済みの独立したアサーションは継続する。