# バッチ設計書 2-Node CI - E2Eテスト

## 概要

本ドキュメントは、Decap CMSプロジェクトにおけるNode CI（E2Eテスト）ワークフローのバッチ設計書である。GitHub Actionsで定義されたCI/CDパイプラインのうち、Cypress E2Eテストを4台のマシンで並列実行するジョブについて記述する。

### 本バッチの処理概要

本バッチは、Decap CMSのEnd-to-End（E2E）テストを自動的に実行するCI/CDバッチである。コードの変更がmain/masterブランチへのpushまたはPull Request時に自動トリガーされ、デモサイトをビルドした上でCypress E2Eテストを4台のマシンで並列シャーディング実行することで、UIレベルでの機能検証を行う。

**業務上の目的・背景**：ユニットテストだけでは検出できないUIレベルの不具合や、コンポーネント間の統合上の問題を検出するために、ブラウザベースのE2Eテストが必要である。Decap CMSはCMSのUI操作（エディタ、メディアライブラリ、認証フロー等）が多いため、E2Eテストによりユーザー操作レベルでの品質を担保する。テストスイートが大きいため、4台のマシンに分散して実行時間を短縮している。

**バッチの実行タイミング**：main/masterブランチへのpush時、およびPull Requestのオープン・同期・再オープン時にイベント駆動で自動実行される。

**主要な処理内容**：
1. dorny/paths-filterによる変更ファイルのフィルタリング（website以外の変更を検出）
2. 4台のマシンによる並列ジョブ起動（matrix.machine: [1,2,3,4]）
3. リポジトリのチェックアウトとNode.js 24.xセットアップ
4. Nxキャッシュ・Cypressバイナリキャッシュの復元
5. npm ciによる依存関係のインストール
6. npm run build:demoによるデモサイトのビルド
7. cypress/run.mjsによるスペックのシャーディングとCypress E2Eテスト実行

**前後の処理との関連**：同一ワークフロー内のchangesジョブ（パスフィルタ）の結果に依存する。No.1（ビルド・ユニットテスト）ジョブとは並列で実行される。No.9（build:demo）のスクリプトを内部で使用してデモサイトをビルドする。

**影響範囲**：本バッチはCypress E2Eテストスイート全体に対して実行される。テスト結果はGitHub上のステータスチェックとして報告され、失敗時にはスクリーンショットとビデオがアーティファクトとしてアップロードされる。

## バッチ種別

CI/CD（継続的インテグレーション - E2Eテスト）

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | イベント駆動（随時） |
| 実行時刻 | 該当なし（イベント発生時） |
| 実行曜日 | 該当なし |
| 実行日 | 該当なし |
| トリガー | main/masterブランチへのpush、Pull Requestのopened/synchronize/reopened |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| GitHubリポジトリへのアクセス | actions/checkout@v4でリポジトリをチェックアウト可能であること |
| Node.js 24.xランタイム | actions/setup-node@v4でNode.js 24.xがセットアップ可能であること |
| Cypressバイナリ | Cypressバイナリがキャッシュまたはインストール可能であること |
| npm依存関係 | npm ciが正常に完了すること |
| 変更ファイルの存在 | dorny/paths-filterでwebsite以外のファイルに変更が検出されること |

### 実行可否判定

changesジョブのdorny/paths-filterステップで、website/ディレクトリ以外のファイルに変更があるかを判定する。`needs.changes.outputs.cms == 'true'`の場合のみe2eジョブが実行される。concurrencyグループにより、同一ブランチでの重複実行はキャンセルされる。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| CI_BUILD_ID | 環境変数 | No | ${{ github.run_id }}-${{ github.run_attempt }} | CI実行の一意識別子 |
| IS_FORK | 環境変数 | No | 自動判定 | ForkからのPRかどうかの判定 |
| MACHINE_INDEX | 環境変数 | Yes | - | マシンインデックス（1-4） |
| MACHINE_COUNT | 環境変数 | Yes | 4 | マシン総数 |
| CYPRESS_RECORD_KEY | シークレット | No | secrets.CYPRESS_RECORD_KEY | Cypress Dashboardの記録用キー |
| NODE_OPTIONS | 環境変数 | No | --max-old-space-size=4096 | Node.jsのメモリ上限設定 |
| TZ | 環境変数 | No | Europe/Amsterdam | タイムゾーン設定 |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| GitHubリポジトリ（ソースコード） | Git | チェックアウト対象のソースコード一式 |
| cypress/e2e/*spec*.js | JavaScript | Cypress E2Eテストスペックファイル |
| dev-test/ | HTML/JS | デモサイト用のテスト環境 |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| GitHubステータスチェック | GitHub API | ジョブの成功/失敗ステータスがPRに報告される |
| GitHub Actionsログ | テキスト | E2Eテストの実行ログ |
| アーティファクト（失敗時のみ） | PNG/MP4 | Cypressのスクリーンショットとビデオ |

### 出力ファイル仕様

| 項目 | 内容 |
|-----|------|
| ファイル名 | cypress-results-${{ matrix.machine }}（アーティファクト名） |
| 出力先 | cypress/screenshots, cypress/videos（失敗時のみアップロード） |
| 文字コード | 該当なし（バイナリファイル） |
| 区切り文字 | 該当なし |

## 処理フロー

### 処理シーケンス

```
1. changesジョブ（パスフィルタリング）
   └─ dorny/paths-filter@v2でwebsite以外の変更を検出
2. e2eジョブ開始（changesジョブの結果がtrueの場合）
   └─ 4台のマシンで並列実行（matrix.machine: [1,2,3,4]）
3. リポジトリチェックアウト
   └─ actions/checkout@v4
4. Node.js 24.xセットアップ
   └─ actions/setup-node@v4（npmキャッシュ有効）
5. Nxキャッシュ復元
   └─ actions/cache@v4（.nx/cache）
6. Cypressバイナリキャッシュ復元
   └─ actions/cache@v4（~/.cache/Cypress）
7. 依存関係インストール
   └─ npm ci
8. デモサイトビルド
   └─ npm run build:demo
       ├─ npm run build（ESM + UMDビルド）
       └─ ncp packages/decap-cms/dist dev-test/dist/
9. E2Eテスト実行
   └─ npm run test:e2e:run-ci
       ├─ start-server-and-test でdev-testサーバー起動（ポート8080）
       └─ cypress/run.mjs でスペックをシャーディング実行
           ├─ globbyでcypress/e2e/*spec*.jsを取得
           ├─ MACHINE_INDEX/MACHINE_COUNTでスペックを分割
           └─ cypress run --browser chrome --headless --spec <分割スペック>
10. 失敗時アーティファクトアップロード
    └─ actions/upload-artifact@v4（スクリーンショットとビデオ）
```

### フローチャート

```mermaid
flowchart TD
    A[ワークフロートリガー: push/PR] --> B[changesジョブ: パスフィルタ]
    B --> C{website以外の変更あり?}
    C -->|なし| D[スキップ]
    C -->|あり| E[e2eジョブ開始: 4台並列]
    E --> F[リポジトリチェックアウト]
    F --> G[Node.js 24.xセットアップ]
    G --> H[Nxキャッシュ復元]
    H --> I[Cypressバイナリキャッシュ復元]
    I --> J[npm ci: 依存関係インストール]
    J --> K[npm run build:demo]
    K --> L[デモサイト構築完了]
    L --> M[start-server-and-test: サーバー起動]
    M --> N[cypress/run.mjs: スペックシャーディング]
    N --> O[Cypress E2Eテスト実行]
    O --> P{全テスト成功?}
    P -->|成功| Q[ジョブ成功]
    P -->|失敗| R[スクリーンショット・ビデオをアーティファクトアップロード]
    R --> S[ジョブ失敗]
    D --> T[ワークフロー終了]
    Q --> T
    S --> T
```

## データベース操作仕様

### 操作別データベース影響一覧

本バッチではデータベース操作は行わない。

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 該当なし | 該当なし | 該当なし | 該当なし |

### テーブル別操作詳細

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | デモサイトビルド失敗 | build:demoが失敗した場合 | ビルドエラーのログを確認し、ソースコードを修正する |
| - | E2Eテスト失敗 | Cypressテストがfailした場合 | アーティファクトのスクリーンショット・ビデオを確認し、テストまたはソースコードを修正する |
| - | テストスペック未検出 | cypress/e2e/*spec*.jsにマッチするファイルが0件の場合 | テストファイルの配置を確認する（exit code 1で終了） |
| - | サーバー起動失敗 | dev-testサーバーがポート8080で起動できない場合 | ポートの競合やビルド成果物の存在を確認する |
| - | タイムアウト | Cypress実行が1時間（60*60*1000ms）を超えた場合 | テストスイートの最適化またはマシン数の増加を検討する |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 自動リトライなし（GitHub Actions UIから手動で再実行可能） |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

### 障害時対応

バッチ（ワークフロー）失敗時は以下の手順で対応する：
1. GitHub Actionsのログでどのステップでエラーが発生したかを確認する
2. テスト失敗の場合、アーティファクトとしてアップロードされたスクリーンショット・ビデオを確認する
3. 一時的な問題（ネットワーク、フレーキーテスト）の場合はGitHub Actions UIから再実行する
4. fail-fast: trueのため、1台のマシンで失敗すると他のマシンのジョブもキャンセルされる

## トランザクション仕様

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | 該当なし（データベース操作なし） |
| コミットタイミング | 該当なし |
| ロールバック条件 | 該当なし |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | cypress/e2e配下の全スペックファイルを4台でシャーディング |
| 目標処理時間 | 1時間以内（Cypressのtimeout: 60*60*1000ms） |
| メモリ使用量上限 | 4096MB（NODE_OPTIONS: --max-old-space-size=4096） |

## 排他制御

concurrencyグループ`ci-${{ github.workflow }}-${{ github.ref }}`により、同一ブランチで同一ワークフローの重複実行が防止される。`cancel-in-progress: true`が設定されているため、新しい実行がトリガーされると進行中の古い実行はキャンセルされる。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 開始ログ | ジョブ開始時 | GitHub Actionsにより自動的にジョブ開始が記録される |
| シャーディング情報ログ | テスト実行前 | `Sharding specs manually: machine X/4 running N specs` |
| Cypress実行コマンドログ | テスト実行前 | `Running Cypress with args: <args>` |
| テスト結果ログ | テスト実行後 | Cypressの実行結果（テスト件数・成功/失敗・スクリーンショット等） |
| 終了ログ | ジョブ終了時 | GitHub Actionsにより自動的にジョブ完了ステータスが記録される |
| エラーログ | テスト失敗時 | Cypressのエラー詳細およびスクリーンショット・ビデオのパス |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| ジョブ成功/失敗 | 失敗時 | GitHub PRステータスチェック、PRレビュアーへの通知 |
| テスト実行時間 | 1時間超 | Cypressプロセスタイムアウトによる自動終了 |

## 備考

- 4台のマシンでスペックを手動シャーディングしている（MACHINE_INDEX/MACHINE_COUNT環境変数で制御）
- 最後のマシン（machine=4）には余りのスペックが割り当てられる（specs.slice(start)で残り全部を取得）
- Nxキャッシュ（.nx/cache）とCypressバイナリキャッシュ（~/.cache/Cypress）の両方がキャッシュされる
- 失敗時のみスクリーンショットとビデオがアーティファクトとしてアップロードされる（if: failure()条件）
- タイムゾーンがEurope/Amsterdamに設定されている（テスト内の日時処理に影響）
- NODE_OPTIONSで--max-old-space-size=4096が設定されており、メモリ上限が4GBに拡張されている
