# 機能設計書 7-jest-circus

## 概要

本ドキュメントは、Jestのデフォルトテストランナー「jest-circus」の機能設計を記述したものである。

### 本機能の処理概要

jest-circusパッケージは、Jest 27以降のデフォルトテストランナーであり、describe、it/test、beforeAll/afterAll、beforeEach/afterEachなどのテストDSL（Domain Specific Language）を提供する。イベント駆動型のアーキテクチャを採用し、テストの定義と実行を分離することで、より柔軟で拡張性の高いテスト実行を実現する。

**業務上の目的・背景**：従来のjest-jasmine2ランナーは、Jasmineライブラリをベースとしており、Jestの要件に完全に最適化されていなかった。jest-circusは、Jest専用に設計されたテストランナーであり、より良いエラーメッセージ、test.concurrent、test.failing、リトライ機能など、jasmine2では実現困難だった機能を提供する。

**機能の利用シーン**：
- 通常のテスト実行（describe/it/test）
- セットアップ/ティアダウン（beforeAll/afterAll/beforeEach/afterEach）
- 並行テスト実行（test.concurrent）
- 失敗想定テスト（test.failing）
- テストのスキップ（test.skip）
- フォーカス実行（test.only）
- TODOテスト（test.todo）

**主要な処理内容**：
1. テストDSL関数（describe、it、test等）の提供
2. テスト定義のイベントとしてのディスパッチ
3. ステートマシンによるテスト状態の管理
4. フック（beforeAll等）の実行順序制御
5. 並行テストのスケジューリング（test.concurrent）
6. テストリトライ機能
7. テスト結果の集約

**関連システム・外部連携**：
- jest-each: パラメータ化テストのサポート
- @jest/expect: アサーションライブラリ
- jest-runtime: モジュール実行環境
- @jest/environment: テスト環境

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| N/A | N/A | N/A | 本機能はテストフレームワークであり、画面は存在しない |

## 機能種別

テストフレームワーク / イベント駆動型ランナー / DSL提供

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| testName | string | Yes | テスト名 | 空でないこと |
| fn | Function | Yes | テスト関数 | 関数であること |
| timeout | number | No | タイムアウト時間 | 正の整数 |

### 入力データソース

- テストファイル内のdescribe/it/test呼び出し
- jest.config.jsからのtestTimeout設定

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| RunResult | Object | テスト実行結果 |
| passed | boolean | テスト成功フラグ |
| numPassingTests | number | 成功テスト数 |
| numFailingTests | number | 失敗テスト数 |
| testResults | Array | 個別テスト結果 |

### 出力先

jest-runner経由でTestSchedulerへ

## 処理フロー

### 処理シーケンス

```
1. テスト定義フェーズ
   └─ describe/it/testの呼び出しをイベントとしてディスパッチ
2. 実行準備
   └─ ステート（rootDescribeBlock）の構築
3. 実行フェーズ
   └─ run関数によるテスト実行
4. フック実行
   └─ beforeAll/beforeEach/afterEach/afterAllの順次実行
5. テスト実行
   └─ 各テスト関数の実行
6. 結果集約
   └─ 実行結果の収集とRunResultの生成
```

### フローチャート

```mermaid
flowchart TD
    A[テストファイル読み込み] --> B[describe ブロック定義]
    B --> C[test/it 定義]
    C --> D[フック定義]
    D --> E[run 関数呼び出し]
    E --> F[run_start イベント]
    F --> G[beforeAll 実行]
    G --> H[各テストの実行ループ]
    H --> I[beforeEach 実行]
    I --> J[test_fn 実行]
    J --> K[afterEach 実行]
    K --> L{次のテスト?}
    L -->|Yes| I
    L -->|No| M[afterAll 実行]
    M --> N[run_finish イベント]
    N --> O[RunResult 生成]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | フック実行順 | beforeAll → beforeEach → test → afterEach → afterAll | 常時 |
| BR-002 | スキップ判定 | test.skip()またはdescribe.skip()内のテストはスキップ | skip指定時 |
| BR-003 | フォーカス実行 | test.only()指定時、onlyテストのみ実行 | only指定時 |
| BR-004 | 並行実行 | test.concurrent()は並行実行される | concurrent指定時 |
| BR-005 | リトライ | jest.retryTimes()で失敗テストをリトライ | 設定時 |
| BR-006 | 失敗想定 | test.failing()は失敗を期待する | failing指定時 |

### 計算ロジック

タイムアウト判定:
- 個別テストのtimeout指定が優先
- 未指定時はjest.setTimeout()またはtestTimeout設定を使用

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

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

データベース操作は本パッケージでは行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| TEST_TIMEOUT | タイムアウト | テストがタイムアウト時間を超過 | タイムアウト値を調整 |
| HOOK_FAILURE | フック失敗 | beforeAll/afterAll等の失敗 | フック処理を修正 |
| CONCURRENT_LIMIT | 並行制限 | maxConcurrency超過 | maxConcurrency調整 |

### リトライ仕様

- jest.retryTimes(n)で最大n回リトライ
- jest.retryTimes(n, {logErrorsBeforeRetry: true})でリトライ前にエラーログ出力
- リトライ間隔はWAIT_BEFORE_RETRYで設定可能

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

トランザクション処理は本パッケージには存在しない

## パフォーマンス要件

- 並行テストはmaxConcurrency設定に従う
- beforeAll/afterAllはdescribeブロック単位で1回のみ実行

## セキュリティ考慮事項

- テストコードは信頼されるコードとして実行される
- グローバル変数へのアクセスが可能

## 備考

- jest-jasmine2からの移行ガイドが公式ドキュメントに存在
- test.failingはjest-circusでのみサポート

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

テスト定義の内部表現を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Circus.ts | `packages/@jest/types/src/Circus.ts` | DescribeBlock、TestEntry、Hook型 |

**読解のコツ**: DescribeBlockはdescribeブロックを表し、childrenに子ブロックとテストを持つツリー構造。

#### Step 2: DSL関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/jest-circus/src/index.ts` | describe、it、test、フックの定義 |

**主要処理フロー**:
1. **28-45行目**: describe関数の実装
2. **47-91行目**: _dispatchDescribe（describeイベントのディスパッチ）
3. **93-109行目**: _addHook（フック登録）
4. **121-248行目**: test関数とそのバリエーション（skip、only、concurrent等）

#### Step 3: 状態管理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | state.ts | `packages/jest-circus/src/state.ts` | グローバルステートの管理 |

**主要処理フロー**:
- getState(): 現在のテスト状態を取得
- setState(): テスト状態を更新
- dispatchSync(): 同期イベントのディスパッチ
- dispatch(): 非同期イベントのディスパッチ

#### Step 4: 実行ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | run.ts | `packages/jest-circus/src/run.ts` | テスト実行のメインロジック |

**主要処理フロー**:
- **33-46行目**: run関数（エントリポイント）
- **72-195行目**: _runTestsForDescribeBlock（describeブロック実行）
- **197-244行目**: _runTest（単一テスト実行）
- **246-269行目**: _callCircusHook（フック呼び出し）
- **271-306行目**: _callCircusTest（テスト関数呼び出し）

#### Step 5: イベントハンドリングを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | eventHandler.ts | `packages/jest-circus/src/eventHandler.ts` | イベントに対応する状態更新 |

**主要処理フロー**:
- 各イベント（start_describe_definition、add_test等）に対する状態更新ロジック

### プログラム呼び出し階層図

```
jest-circus/src/index.ts (DSL関数)
    │
    ├─ describe()
    │      └─ dispatchSync('start_describe_definition')
    │      └─ blockFn() 実行
    │      └─ dispatchSync('finish_describe_definition')
    │
    ├─ test() / it()
    │      └─ dispatchSync('add_test')
    │
    ├─ beforeAll/beforeEach/afterEach/afterAll
    │      └─ dispatchSync('add_hook')
    │
    └─ run.ts
           │
           ├─ dispatch('run_start')
           │
           ├─ _runTestsForDescribeBlock
           │      │
           │      ├─ _callCircusHook (beforeAll)
           │      │
           │      ├─ _runTest (各テスト)
           │      │      ├─ _callCircusHook (beforeEach)
           │      │      ├─ _callCircusTest
           │      │      └─ _callCircusHook (afterEach)
           │      │
           │      └─ _callCircusHook (afterAll)
           │
           └─ dispatch('run_finish')
```

### データフロー図

```
[入力]                        [処理]                         [出力]

テストファイル ───────────▶ describe/test呼び出し ────▶ イベントディスパッチ
        │                        │
        ▼                        ▼
イベント ────────────────▶ eventHandler ─────────────▶ State更新
        │                        │
        ▼                        ▼
State ───────────────────▶ run() ───────────────────▶ テスト実行
        │                        │
        ▼                        ▼
テスト関数 ──────────────▶ callAsyncCircusFn ───────▶ 成功/失敗
        │                        │
        ▼                        ▼
実行結果 ────────────────▶ makeRunResult ───────────▶ RunResult
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/jest-circus/src/index.ts` | ソース | DSL関数定義 |
| run.ts | `packages/jest-circus/src/run.ts` | ソース | テスト実行ロジック |
| state.ts | `packages/jest-circus/src/state.ts` | ソース | 状態管理 |
| eventHandler.ts | `packages/jest-circus/src/eventHandler.ts` | ソース | イベント処理 |
| utils.ts | `packages/jest-circus/src/utils.ts` | ソース | ユーティリティ関数 |
| types.ts | `packages/jest-circus/src/types.ts` | 型定義 | 内部型定義 |
| runner.ts | `packages/jest-circus/runner.ts` | ソース | jest-runnerとの接続 |
