# 帳票設計書 2-spec

## 概要

本ドキュメントは、Node.jsテストランナーの「specレポーター」の設計仕様を記載したものである。テスト結果を人間が読みやすい詳細形式で出力するレポーター機能の実装詳細、出力形式、処理フローについて説明する。

### 本帳票の処理概要

specレポーターは、Node.jsテストランナーが実行したテスト結果を、階層構造を保持した詳細な形式で標準出力に表示する帳票である。テストの成功/失敗状態、診断メッセージ、カバレッジ情報を色分けして表示し、開発者がテスト結果を直感的に把握できるようにする。

**業務上の目的・背景**：開発者がテスト実行時に、各テストの詳細な実行結果、テストの階層構造、エラー詳細、診断メッセージを確認する必要がある。specレポーターは、RSpecやMochaのspec形式に類似した出力を提供し、テスト結果の可読性を最大化する。特にデバッグ時やテスト失敗時の原因特定において、詳細な情報が求められる場面で有用である。

**帳票の利用シーン**：
- ローカル開発環境での詳細なテスト結果確認
- テスト失敗時の原因調査・デバッグ
- テストカバレッジの確認
- テストスイートの階層構造の可視化
- ウォッチモードでのテスト再実行監視

**主要な出力内容**：
1. テストの階層構造（ネスト表示）
2. 成功テスト（緑色チェックマーク）
3. 失敗テスト（赤色Xマーク）とエラー詳細
4. スキップ/TODOテスト（グレー表示）
5. 診断メッセージ（青色）
6. コードカバレッジ情報
7. 失敗テストのサマリー（ファイル位置含む）

**帳票の出力タイミング**：
- テストランナーがテストを実行中、各テストの完了時にリアルタイムで出力
- 診断メッセージ発生時に即時出力
- カバレッジ情報はテスト完了後に出力
- ウォッチモード時は再起動時刻を表示

**帳票の利用者**：
- ソフトウェア開発者
- QAエンジニア
- テスト自動化エンジニア

## 帳票種別

テストレポート / コンソール出力形式（詳細形式）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | CLIターミナル | `node --test --test-reporter=spec` | テスト実行コマンド |
| - | CLIターミナル | `node --test` | デフォルトレポーター（spec） |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト（標準出力） |
| 用紙サイズ | N/A（コンソール出力） |
| 向き | N/A |
| ファイル名 | N/A（標準出力へ直接出力） |
| 出力方法 | 標準出力（stdout） |
| 文字コード | UTF-8 |

### コンソール出力固有設定

| 項目 | 内容 |
|-----|------|
| ANSIカラー対応 | 有（緑/赤/青/黄/グレー/白） |
| 階層インデント | 2スペース × ネストレベル |
| Unicodeシンボル | 有（✔ ✖ ℹ ▶ ﹣） |

## 帳票レイアウト

### レイアウト概要

specレポーターは、テストの階層構造を保持しながら結果を出力し、最後に失敗テストのサマリーとカバレッジ情報を表示する。

```
┌─────────────────────────────────────┐
│          テスト階層出力部            │
│  ▶ TestSuite                       │
│    ✔ test case 1 (10ms)            │
│    ✖ test case 2 (5ms)             │
│      [エラー詳細]                   │
├─────────────────────────────────────┤
│          診断・カバレッジ部          │
│  ℹ coverage report...              │
├─────────────────────────────────────┤
│          失敗サマリー部              │
│  ✖ failing tests:                   │
│    test at file.js:10:5            │
└─────────────────────────────────────┘
```

### テスト階層出力部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | テスト開始 | テストスイート/ケース開始 | test:start イベント | `▶ {name}` |
| 2 | 成功テスト | テスト成功 | test:pass イベント | 緑 `✔ {name} ({duration}ms)` |
| 3 | 失敗テスト | テスト失敗 | test:fail イベント | 赤 `✖ {name} ({duration}ms)` |
| 4 | スキップテスト | スキップされたテスト | skip属性 | グレー `﹣ {name} # SKIP` |
| 5 | TODOテスト | TODO指定テスト | todo属性 | `{name} # TODO` |

### 診断・カバレッジ部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | 診断メッセージ | テスト診断情報 | test:diagnostic イベント | 青 `ℹ {message}` |
| 2 | カバレッジ | コードカバレッジ情報 | test:coverage イベント | getCoverageReport関数 |
| 3 | 再起動通知 | ウォッチモード再起動 | test:watch:restarted イベント | `Restarted at {datetime}` |

### 失敗サマリー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | 失敗ヘッダー | 失敗テスト一覧のヘッダー | 固定 | 赤 `✖ failing tests:` |
| 2 | ファイル位置 | 失敗テストのファイル位置 | data.file, line, column | `test at {relPath}:{line}:{column}` |
| 3 | エラー詳細 | 失敗の詳細 | formatTestReport関数 | エラーメッセージ |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| テスト結果イベント | test:pass/fail/start/diagnostic等のイベント | Yes |
| 失敗サマリー | test:summary イベント（file === undefined の場合のみ） | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | イベント発生順 | 昇順（時系列） |

### 改ページ条件

なし（連続出力）

## データベース参照仕様

### 参照テーブル一覧

本帳票はデータベースを参照しない。テストランナーからのイベントストリームを入力として使用する。

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| N/A | - | - |

### イベントデータ構造

#### test:start イベント

| 参照項目 | 帳票項目との対応 | 取得条件 | 備考 |
|---------|----------------|---------|------|
| data.name | テスト名 | - | スタックにプッシュ |
| data.nesting | ネストレベル | - | インデント計算用 |

#### test:pass / test:fail イベント

| 参照項目 | 帳票項目との対応 | 取得条件 | 備考 |
|---------|----------------|---------|------|
| data.name | テスト名 | - | 表示用 |
| data.nesting | ネストレベル | - | インデント計算用 |
| data.details.duration_ms | 実行時間 | - | ミリ秒表示 |
| data.details.error | エラー情報 | test:fail時 | エラー詳細表示 |
| data.skip | スキップ理由 | スキップ時 | `# SKIP` 表示 |
| data.todo | TODO理由 | TODO時 | `# TODO` 表示 |
| data.file | ファイルパス | - | 失敗サマリー用 |
| data.line | 行番号 | - | 失敗サマリー用 |
| data.column | 列番号 | - | 失敗サマリー用 |

#### test:diagnostic イベント

| 参照項目 | 帳票項目との対応 | 取得条件 | 備考 |
|---------|----------------|---------|------|
| data.message | 診断メッセージ | - | 表示用 |
| data.nesting | ネストレベル | - | インデント計算用 |
| data.level | 診断レベル | - | 色分け用（info/warn/error） |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| インデント | `'  ' × nesting` | N/A | 2スペース × ネストレベル |
| 相対パス | `relative(cwd, file)` | N/A | カレントディレクトリからの相対パス |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[テストイベント受信] --> B{イベントタイプ判定}
    B -->|test:start| C[スタックにプッシュ]
    B -->|test:pass| D[handleTestReportEvent]
    B -->|test:fail| E[handleTestReportEvent]
    E --> F[失敗テスト配列に追加]
    B -->|test:diagnostic| G[診断メッセージ出力]
    B -->|test:coverage| H[カバレッジレポート出力]
    B -->|test:summary| I{file === undefined?}
    I -->|Yes| J[失敗サマリー出力]
    I -->|No| K[何もしない]
    B -->|test:watch:restarted| L[再起動時刻出力]
    B -->|test:stdout/stderr| M[メッセージ出力]
    D --> N[親テスト出力]
    N --> O[テスト結果整形出力]
    F --> N
```

### handleTestReportEvent処理

```mermaid
flowchart TD
    A[イベント受信] --> B[スタックから対応するtest:startをpop]
    B --> C{スタックに親あり?}
    C -->|Yes| D[親のtest:startを出力]
    D --> E[reportedに追加]
    E --> C
    C -->|No| F[インデント計算]
    F --> G[formatTestReportで整形]
    G --> H[結果を返却]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| サブテスト失敗 | kSubtestsFailed | 失敗詳細は出力しない | failedTestsに追加しない |
| 出力エラー | 標準出力への書き込み失敗 | - | Transformストリームが例外をスロー |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 無制限（ストリーム処理） |
| 目標出力時間 | イベント受信後即時出力 |
| 同時出力数上限 | 1（シングルストリーム） |

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

- テスト名、エラーメッセージ、診断メッセージに含まれる機密情報がそのまま出力される可能性がある
- ファイルパスが相対パスで表示されるが、ディレクトリ構造が露出する
- ターミナルへの出力のため、出力内容は実行環境のコンソールログに残る

## 備考

- Node.jsテストランナーのデフォルトレポーター
- Transformストリームとして実装され、オブジェクトモードで動作
- colors.refresh()を呼び出して色設定を初期化
- kSubtestsFailed でマークされた失敗は、親テストの失敗として扱われ、個別の失敗詳細は出力しない

---

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

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

### 推奨読解順序

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

テストイベントの構造とレポーターで使用されるシンボル・色定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | utils.js | `lib/internal/test_runner/reporter/utils.js` | reporterUnicodeSymbolMap, reporterColorMap, formatTestReport関数 |
| 1-2 | test.js | `lib/internal/test_runner/test.js` | kSubtestsFailed定数の定義と意味 |

**読解のコツ**: reporterUnicodeSymbolMapとreporterColorMapは遅延評価（getter）を使用しており、colors.refresh()後に正しい値が取得される。

#### Step 2: エントリーポイントを理解する

SpecReporterクラスの構造とTransformストリームとしての実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | spec.js | `lib/internal/test_runner/reporter/spec.js` | SpecReporterクラス全体 |

**主要処理フロー**:
1. **24行目**: `class SpecReporter extends Transform` - Transformストリームを継承
2. **25-28行目**: プライベートフィールド（#stack, #reported, #failedTests, #cwd）
3. **30-33行目**: コンストラクタ - writableObjectModeを有効化、colors.refresh()呼び出し
4. **35-59行目**: `#formatFailedTestResults` - 失敗テストのサマリー整形
5. **60-78行目**: `#handleTestReportEvent` - テスト結果イベントの処理
6. **79-110行目**: `#handleEvent` - イベントタイプ別の分岐処理
7. **111-113行目**: `_transform` - Transformストリームの実装
8. **114-116行目**: `_flush` - ストリーム終了時の処理

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

各イベントタイプの処理ロジックを詳細に理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | spec.js | `lib/internal/test_runner/reporter/spec.js` | #handleEvent メソッド（79-110行目） |

**主要処理フロー**:
- **81-85行目**: test:fail - kSubtestsFailed以外を失敗配列に追加
- **86-87行目**: test:pass - handleTestReportEventを呼び出し
- **88-90行目**: test:start - スタックにプッシュ
- **91-93行目**: test:stderr/stdout - メッセージをそのまま出力
- **94-97行目**: test:diagnostic - 診断レベルに応じた色でメッセージ出力
- **98-100行目**: test:coverage - getCoverageReportで整形出力
- **101-106行目**: test:summary - ルートサマリーのみ失敗詳細を出力
- **107-108行目**: test:watch:restarted - 再起動時刻を出力

#### Step 4: ユーティリティ関数を理解する

レポーターで使用される共通ユーティリティを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | utils.js | `lib/internal/test_runner/reporter/utils.js` | formatTestReport, indent関数 |
| 4-2 | utils.js | `lib/internal/test_runner/utils.js` | getCoverageReport関数 |

**主要処理フロー**:
- **70-92行目** (reporter/utils.js): formatTestReport - テスト結果の整形
- **481-626行目** (utils.js): getCoverageReport - カバレッジレポート生成

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

```
node --test --test-reporter=spec
    │
    ├─ lib/internal/test_runner/runner.js
    │      └─ parseCommandLine() → getReportersMap()
    │              └─ require('internal/test_runner/reporter/spec')
    │
    └─ lib/internal/test_runner/reporter/spec.js
           │
           ├─ SpecReporter (Transform)
           │      ├─ _transform() → #handleEvent()
           │      │      ├─ #handleTestReportEvent()
           │      │      └─ getCoverageReport()
           │      └─ _flush() → #formatFailedTestResults()
           │
           ├─ formatTestReport()
           │      └─ lib/internal/test_runner/reporter/utils.js
           │
           ├─ getCoverageReport()
           │      └─ lib/internal/test_runner/utils.js
           │
           └─ colors / relative
                  └─ lib/internal/util/colors.js / path
```

### データフロー図

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

テストイベント ───▶ SpecReporter._transform() ───▶ 標準出力(stdout)
  ストリーム              │
                         ├─ test:start → スタックにプッシュ
                         ├─ test:pass → 整形出力
                         ├─ test:fail → 整形出力 + 失敗配列追加
                         ├─ test:diagnostic → 診断メッセージ出力
                         ├─ test:coverage → カバレッジレポート出力
                         └─ test:summary → 失敗サマリー出力
                                │
                         _flush() → 残りの失敗サマリー出力
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| spec.js | `lib/internal/test_runner/reporter/spec.js` | ソース | specレポーターのメイン実装 |
| utils.js | `lib/internal/test_runner/reporter/utils.js` | ソース | レポーター共通ユーティリティ |
| utils.js | `lib/internal/test_runner/utils.js` | ソース | テストランナーユーティリティ（カバレッジレポート含む） |
| colors.js | `lib/internal/util/colors.js` | ソース | ANSIカラーコード定義 |
| test.js | `lib/internal/test_runner/test.js` | ソース | テスト定義とkSubtestsFailed定数 |
| runner.js | `lib/internal/test_runner/runner.js` | ソース | テストランナーのメイン処理 |
| transform.js | `lib/internal/streams/transform.js` | ソース | Transformストリーム基底クラス |
