# テスト方針書

## 概要

本ドキュメントは、Next.js フレームワーク（pnpm モノレポ構成）のテスト方針を定義するものである。Next.js は JavaScript/TypeScript によるフロントエンドフレームワーク本体と、Rust（SWC/Turbopack）によるネイティブモジュールの両方を含む大規模プロジェクトであり、テスト戦略もそれぞれの技術スタックに応じて設計されている。本書では、テストレベル・テスト種別・テスト環境・ツール・CI/CD連携について網羅的に記載する。

## テスト戦略

### テストレベル

| レベル | 目的 | 担当 |
| --- | --- | --- |
| 単体テスト（Unit） | 個々のユーティリティ関数・モジュールの正確性を高速に検証する。ブラウザや Next.js サーバーの起動を伴わない。 | 開発者（各機能の担当者） |
| 結合テスト（Integration） | 複数モジュールの連携動作を検証する。主にレガシーテストスイートとして `test/integration/` に格納されている。モノレポ内で非分離的に実行される。 | 開発者（各機能の担当者） |
| E2Eテスト（End-to-End） | `next dev`、`next start`、Vercel デプロイ環境に対して、実際のブラウザ操作を含む完全なユーザーシナリオを検証する。テストごとに一時ディレクトリに隔離された Next.js インストールが作成される。 | 開発者・QA |
| 開発モードテスト（Development） | `next dev`（開発サーバー）固有の振る舞い（HMR、エラーオーバーレイ等）を検証する。 | 開発者 |
| プロダクションテスト（Production） | `next build` + `next start` による本番モード固有の振る舞い（最適化、プリレンダリング等）を検証する。 | 開発者 |
| Rust 単体テスト（Cargo Unit） | Turbopack および next-swc の Rust クレートに対する単体テストを `cargo nextest` で実行する。 | Rust 担当開発者 |
| デプロイテスト（Deploy） | Vercel にデプロイした状態で E2E テストを実行し、実環境での動作を検証する。 | 開発者・CI |

### テスト種別

| 種別 | 概要 | 実施タイミング |
| --- | --- | --- |
| 機能テスト | App Router、Pages Router、API Routes、ミドルウェア等の各機能が仕様通り動作することを検証する。E2E・Integration・Unit の各レベルで実施。 | PR 作成時・push 時（CI） |
| 回帰テスト | 修正に伴うデグレードがないことを確認する。既存テストスイートの全実行により担保。 | PR 作成時・push 時（CI） |
| フレイクテスト検出 | 新規・変更テストを複数回実行し、不安定なテスト（flaky test）を早期に検出する。`scripts/test-new-tests.mjs --flake-detection` で実施。 | PR 作成時（CI） |
| クロスブラウザテスト | Chrome（デフォルト）に加え、Firefox、Safari（WebKit）、モバイルデバイスでの動作を検証する。 | PR 作成時（CI、特定ジョブ） |
| クロスプラットフォームテスト | Linux（メイン）、Windows での動作を検証する。 | PR 作成時（CI） |
| 性能テスト（ベンチマーク） | `devlow-bench` を用いた開発サーバー起動速度・ビルド速度のベンチマークを実施する。 | canary ブランチへの push 時（CI） |
| Rustチェック | `cargo fmt`、`cargo check`、`rustdoc` による Rust コードの静的検証を実施する。 | PR 作成時・push 時（CI） |
| 静的解析・Lint | ESLint、Prettier、ast-grep、TypeScript 型チェックを実施する。 | PR 作成時・push 時（CI） |
| マルチReactバージョンテスト | デフォルト React バージョン（19.x）と React 18.3.1 の両方でテストを実行し、後方互換性を検証する。 | PR 作成時・canary push 時（CI） |

## テスト環境

| 環境 | 用途 | 構成 |
| --- | --- | --- |
| ローカル開発環境 | 開発者による手動テスト実行 | macOS / Linux / Windows、Node.js 20 または 22、pnpm |
| CI（GitHub Actions - Linux） | メインのテスト実行環境 | self-hosted Linux x64 metal ランナー、Node.js 20.9.0 / 20 / 22 |
| CI（GitHub Actions - Windows） | Windows 固有の問題検証 | self-hosted Windows x64 ランナー、Node.js 20 / 22 |
| Vercel デプロイ環境 | デプロイテスト用 | Vercel プラットフォーム上にデプロイされた Next.js アプリケーション |

## テストツール

| ツール | 用途 | バージョン |
| --- | --- | --- |
| Jest | JavaScript/TypeScript テストランナー（Unit、Integration、E2E、Development、Production テスト全般） | 29.7.0 |
| Playwright | ブラウザ自動化（E2E テストにおける Chrome、Firefox、Safari での操作） | 1.48.0 |
| jest-extended | Jest のカスタムマッチャー拡張 | 4.0.2 |
| jest-junit | JUnit XML 形式のテストレポート出力（CI でのテスト結果収集） | 16.0.0 |
| next/jest | Next.js 向け Jest 設定プリセット（SWC トランスフォーム統合） | workspace 内蔵 |
| @testing-library/react | React コンポーネントのテストユーティリティ | ^15.0.5 |
| @testing-library/jest-dom | DOM マッチャー拡張 | 6.1.2 |
| @edge-runtime/jest-environment | Edge Runtime 環境でのテスト実行 | 4.0.0 |
| cargo nextest | Rust クレートのテストランナー（Turbopack / next-swc） | CI で動的インストール |
| devlow-bench | 開発サーバー・ビルドのパフォーマンスベンチマーク | workspace 内蔵 |
| cross-env | 環境変数のクロスプラットフォーム設定 | テストスクリプト全般で使用 |
| node-fetch | HTTP リクエストによるサーバーレスポンス検証 | テストユーティリティ内で使用 |
| cheerio | HTML パース・アサーション | テストユーティリティ内で使用 |
| tree-kill | テスト後のプロセスクリーンアップ | テストユーティリティ内で使用 |

## カバレッジ目標

| 対象 | 目標値 |
| --- | --- |
| 行カバレッジ | 明示的な数値目標の設定なし（テストスイートの網羅性により担保） |
| 分岐カバレッジ | 明示的な数値目標の設定なし（テストスイートの網羅性により担保） |

備考: Next.js プロジェクトでは、カバレッジの数値目標よりも、テストの種類・数・実行パターンの網羅性でコード品質を担保するアプローチを採用している。テストファイル数は合計約 1,620 ファイル以上（Unit: 約95、E2E: 約801、Integration: 約352、Development: 約207、Production: 約165）であり、複数バンドラー（Webpack、Turbopack、Rspack）、複数 React バージョン、複数 OS での並列マトリクステストにより広範なカバレッジを実現している。

## テストデータ

テストデータは以下の方針で準備される。

1. **フィクスチャディレクトリ方式（推奨）**: 各テストスイートのディレクトリ内に Next.js アプリケーションのフィクスチャファイル（`app/page.tsx`、`next.config.js` 等）を配置する。`nextTestSetup({ files: __dirname })` により参照される。
2. **インラインファイル定義方式（非推奨）**: `nextTestSetup({ files: { ... } })` によりテストコード内にファイル内容を直接記述する。保守性の観点から非推奨。
3. **テスト分離**: E2E / Development / Production テストは、システムの一時フォルダ（例: `/tmp`）に隔離された Next.js インストールが自動作成される。`nextTestSetup` ユーティリティがセットアップ・ティアダウンを自動管理する。
4. **テストマニフェスト**: バンドラー固有のテストフィルタリングのため、マニフェスト JSON ファイル（`turbopack-dev-tests-manifest.json`、`rspack-build-tests-manifest.json` 等）が使用される。

## 不具合管理

1. **GitHub Issues**: 不具合は GitHub Issues で管理される。
2. **フレイクテスト対応**: CI で新規テストに対して `--flake-detection` を実施し、不安定テストを PR マージ前に検出する。
3. **テストリトライ**: CI では `DEFAULT_NUM_RETRIES = 2` が設定されており、一時的な失敗に対して自動リトライが行われる。`retry_test.yml` ワークフローによる追加リトライメカニズムも存在する。
4. **JUnit レポート**: `jest-junit` によりテスト結果が JUnit XML 形式で出力され、CI 上でのテスト結果の可視化・集計に利用される。リトライされたテストは二重カウントを避けるため、フレイクテストの結果はリトライなしの失敗として報告される。

## CI/CD連携

### ワークフロー構成

メインのテスト実行は `.github/workflows/build_and_test.yml` で定義され、以下のジョブ構成で実行される。

**トリガー条件**:
- `canary` ブランチへの push
- Pull Request の作成・更新（opened, synchronize）

**ビルドフェーズ**:
1. `build-native`: Rust ネイティブモジュール（SWC バインディング）のビルド
2. `build-native-windows`: Windows 向けネイティブモジュールのビルド
3. `build-next`: Next.js パッケージのビルド

**静的検証フェーズ**:
- `lint`: ESLint、Prettier、ast-grep、ドキュメントバリデーション
- `check-types-precompiled`: TypeScript 型チェック、プリコンパイル済みファイルの検証
- `rust-check`: Rust コードの `cargo check` / `cargo fmt`
- `rustdoc-check`: Rust ドキュメントの検証
- `ast-grep`: AST パターンマッチングによる Lint

**テスト実行フェーズ（並列マトリクス）**:

| ジョブ名 | バンドラー | モード | グループ分割 | React バージョン |
| --- | --- | --- | --- | --- |
| test-unit | - | Unit | Node.js 20, 22 | デフォルト |
| test-unit-windows | - | Unit (Windows) | Node.js 20, 22 | デフォルト |
| test-dev | Webpack | Development | 1/10 - 10/10 | デフォルト, 18.3.1 |
| test-prod | Webpack | Production | 1/10 - 10/10 | デフォルト, 18.3.1 |
| test-integration | Webpack | Integration | 1/13 - 13/13 | デフォルト |
| test-turbopack-dev | Turbopack | Development/E2E | 1/7 - 7/7 | デフォルト, 18.3.1 |
| test-turbopack-production | Turbopack | Production | 1/7 - 7/7 | デフォルト, 18.3.1 |
| test-turbopack-integration | Turbopack | Integration | 1/6 - 6/6 | デフォルト |
| test-turbopack-production-integration | Turbopack | Production Integration | 1/10 - 10/10 | デフォルト |
| test-rspack-dev | Rspack | Development/E2E | 1/5 - 5/5 | デフォルト, 18.3.1 |
| test-rspack-production | Rspack | Production | 1/7 - 7/7 | デフォルト, 18.3.1 |
| test-rspack-integration | Rspack | Integration | 1/6 - 6/6 | デフォルト |
| test-rspack-production-integration | Rspack | Production Integration | 1/7 - 7/7 | デフォルト |
| test-firefox-safari | Webpack | クロスブラウザ | - | デフォルト |
| test-dev-windows | Webpack | Development (Windows) | - | デフォルト |
| test-prod-windows | Webpack | Production (Windows) | - | デフォルト |
| test-integration-windows | Webpack | Integration (Windows) | - | デフォルト |
| test-cargo-unit | - | Rust Unit | - | - |
| test-next-swc-wasm | - | WASM | - | デフォルト |
| test-cache-components-dev | Webpack | Cache Components (Dev) | 1/6 - 6/6 | デフォルト |
| test-cache-components-prod | Webpack | Cache Components (Prod) | 1/7 - 7/7 | デフォルト |
| test-cache-components-integration | Webpack | Cache Components (Integration) | - | デフォルト |

**フレイクテスト検出フェーズ**:
- `test-new-tests-dev`: 新規・変更テストを dev モードで複数回実行
- `test-new-tests-start`: 新規・変更テストを start モードで複数回実行
- `test-new-tests-deploy`: 新規・変更テストをデプロイモードで実行

**最終ゲート**:
- `tests-pass`（"thank you, next"）: 全テストジョブの成功を確認するゲートジョブ。いずれかのジョブが失敗またはキャンセルされた場合、全体を失敗とする。

### CI最適化

- **Graphite CI Optimizer**: `graphite_ci_optimizer.yml` による CI 実行の最適化（不要なジョブのスキップ）
- **ドキュメントのみ変更検出**: ドキュメントのみの変更時にはテストジョブをスキップ
- **並行実行制御**: PR ごとに同時実行を1つに制限し、同一 PR の古い実行をキャンセル
- **テストタイミングデータ**: Vercel KV にテスト実行時間データを保存し、グループ分割の最適化に活用
- **ビルド再利用**: `build_reusable.yml` による共通ビルドステップの再利用（Turborepo キャッシュ活用）

## 備考

### テスト実行モード

テスト実行時の環境変数により、テストの動作モードが切り替わる。

| 環境変数 | 説明 |
| --- | --- |
| `NEXT_TEST_MODE` | テストモード（`dev` / `start` / `deploy`） |
| `IS_TURBOPACK_TEST` | Turbopack を使用するテストであることを示す |
| `TURBOPACK_DEV` | Turbopack を開発モードで使用 |
| `TURBOPACK_BUILD` | Turbopack をビルドモードで使用 |
| `IS_WEBPACK_TEST` | Webpack を使用するテストであることを示す |
| `NEXT_RSPACK` / `NEXT_TEST_USE_RSPACK` | Rspack を使用するテストであることを示す |
| `NEXT_TEST_REACT_VERSION` | テスト対象の React バージョンを指定 |
| `HEADLESS` | ヘッドレスブラウザモードで実行（CI デフォルト） |
| `NEXT_SKIP_ISOLATE` | テスト分離をスキップ（ローカル開発高速化用） |
| `NEXT_TEST_SKIP_CLEANUP` | テスト後の一時ファイル削除をスキップ（デバッグ用） |
| `BROWSER_NAME` | テスト対象ブラウザ（`chrome` / `firefox` / `safari`） |
| `DEVICE_NAME` | テスト対象デバイス（例: `iPhone XR`） |

### テストタイムアウト

| 対象 | タイムアウト値 |
| --- | --- |
| 単体テスト（デフォルト） | 60秒（Windows: 180秒） |
| E2E テスト | 120秒（Windows: 240秒） |
| CI ジョブ全体 | 30分（デフォルト）、フレイクテスト検出は60分 |

### テスト生成

新規テストの作成には `pnpm new-test` コマンドを使用する。これにより適切なディレクトリ構造とフィクスチャファイルが自動生成される。非インタラクティブモード（AI エージェント向け）では `pnpm new-test --args <appDir> <name> <type>` 形式で実行する。

### テスト記述のベストプラクティス

- 非同期待機には `retry()` ユーティリティを使用する（`setTimeout` や非推奨の `check()` は使用しない）
- テストは TypeScript（`.ts` / `.tsx`）で記述する
- フィクスチャディレクトリ方式を優先し、インラインファイル定義は避ける
- 修正適用時には、修正なしでテストが失敗することを確認する（回帰テストの有効性担保）
