# 通知設計書 8-スナップショット状態通知

## 概要

本ドキュメントは、Jestテストフレームワークにおけるコンソール出力機能のうち、スナップショットテストの状態（追加/更新/削除/不一致）をコンソールへ出力する「スナップショット状態通知」の設計を記載する。

### 本通知の処理概要

スナップショット状態通知は、全テスト実行完了時にスナップショットテストの全体的な状態サマリーをコンソールへ出力する機能である。SummaryReporter._printSnapshotSummaryメソッドで実行され、追加・更新・削除・不一致・廃止されたスナップショットの件数と詳細を表示する。

**業務上の目的・背景**：スナップショットテストはUIコンポーネントやデータ構造の回帰テストに広く使用される。スナップショット状態通知により、開発者はスナップショットの変更状況を一目で把握でき、意図しない変更の検出や、スナップショットの更新が必要かどうかの判断を支援する。

**通知の送信タイミング**：全テスト実行が完了した時点（onRunComplete）で、スナップショットに変更がある場合に出力される。

**通知の受信者**：テストを実行した開発者のコンソール（標準エラー出力）に表示される。

**通知内容の概要**：「Snapshot Summary」というヘッダーの下に、追加されたスナップショット数、更新されたスナップショット数、失敗（不一致）したスナップショット数、廃止されたスナップショット数が表示される。廃止スナップショットがある場合は、更新コマンドの案内も表示される。

**期待されるアクション**：開発者はスナップショットの状態を確認し、必要に応じて`-u`オプションでスナップショットを更新するか、不一致の原因を調査して修正する。

## 通知種別

コンソール出力（標準エラー出力）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（_printSnapshotSummary内で直接呼び出し） |
| 優先度 | 中 |
| リトライ | なし |

### 送信先決定ロジック

logメソッドを通じて標準エラー出力（process.stderr）に対して出力する。

## 通知テンプレート

### コンソール出力の場合

| 項目 | 内容 |
|-----|------|
| 出力先 | process.stderr |
| ヘッダー | `Snapshot Summary`（太字） |
| 追加 | 緑色太字 |
| 更新 | 緑色太字 |
| 失敗 | 赤色太字 |
| 廃止 | 黄色太字 |
| 削除 | 緑色太字 |

### 本文テンプレート

```
Snapshot Summary
 › X snapshots written from Y test suites.
 › X snapshots updated from Y test suites.
 › X snapshots failed from Y test suites. Inspect your code changes or {updateCommand} to update them.
 › X snapshot files obsolete from Y test suites. To remove them all, {updateCommand}.
   ↳ • {filePath}
 › X snapshots obsolete from Y test suites. To remove them all, {updateCommand}.
   ↳ {filePath}
     • {snapshotKey}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| snapshots.added | 追加されたスナップショット数 | SnapshotSummary.added | No |
| snapshots.filesAdded | 追加されたファイル数 | SnapshotSummary.filesAdded | No |
| snapshots.updated | 更新されたスナップショット数 | SnapshotSummary.updated | No |
| snapshots.filesUpdated | 更新されたファイル数 | SnapshotSummary.filesUpdated | No |
| snapshots.unmatched | 不一致のスナップショット数 | SnapshotSummary.unmatched | No |
| snapshots.filesUnmatched | 不一致のファイル数 | SnapshotSummary.filesUnmatched | No |
| snapshots.filesRemoved | 削除されたファイル数 | SnapshotSummary.filesRemoved | No |
| snapshots.filesRemovedList | 削除されたファイルリスト | SnapshotSummary.filesRemovedList | No |
| snapshots.unchecked | 未チェックのスナップショット数 | SnapshotSummary.unchecked | No |
| snapshots.uncheckedKeysByFile | 未チェックスナップショットの詳細 | SnapshotSummary.uncheckedKeysByFile | No |
| updateCommand | 更新コマンド | 環境に応じて動的生成 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| イベント | onRunComplete | スナップショット変更あり | 全テスト完了時に発火 |

### 送信条件詳細

以下のいずれかの条件を満たす場合に出力される：
- `snapshots.added > 0`
- `snapshots.filesRemoved > 0`
- `snapshots.unchecked > 0`
- `snapshots.unmatched > 0`
- `snapshots.updated > 0`

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 上記全てが0 | スナップショットに変更がない場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[onRunComplete発火] --> B[_printSnapshotSummary呼び出し]
    B --> C{スナップショット変更あり?}
    C -->|No| Z[終了]
    C -->|Yes| D[updateCommand生成]
    D --> E[getSnapshotSummary呼び出し]
    E --> F[サマリー配列をループ出力]
    F --> G[空行出力]
    G --> Z
```

## データベース参照・更新仕様

### 参照テーブル一覧

本通知はデータベースを使用しない。メモリ上のデータ構造からデータを取得する。

| データソース | 用途 | 備考 |
|-----------|------|------|
| AggregatedResult.snapshot | スナップショットサマリー | onRunComplete引数から取得 |
| GlobalConfig | グローバル設定 | watch/watchAllモード判定、updateCommand生成 |
| 環境変数 | npm/yarn判定 | npm_config_user_agent、npm_lifecycle_event等 |

### 参照項目詳細

#### SnapshotSummary

| 参照項目 | 用途 | 取得条件 |
|--------|------|---------|
| added | 追加スナップショット数 | なし |
| filesAdded | 追加ファイル数 | なし |
| updated | 更新スナップショット数 | なし |
| filesUpdated | 更新ファイル数 | なし |
| unmatched | 不一致スナップショット数 | なし |
| filesUnmatched | 不一致ファイル数 | なし |
| filesRemoved | 削除ファイル数 | なし |
| filesRemovedList | 削除ファイルリスト | なし |
| unchecked | 未チェックスナップショット数 | なし |
| uncheckedKeysByFile | 未チェック詳細 | なし |
| didUpdate | 更新実行済みフラグ | なし |

#### GlobalConfig

| 参照項目 | 用途 | 取得条件 |
|--------|------|---------|
| watch | watchモード判定 | なし |
| watchAll | watchAllモード判定 | なし |

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| なし | _printSnapshotSummaryは安全に実行される | - |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | N/A |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（全テスト完了時に出力）

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

- コンソール出力のみのため、外部への情報漏洩リスクはない
- スナップショットファイルパスが表示される
- ローカル環境でのみ表示される

## 備考

- `NPM_EVENTS`定数で定義されたイベント（prepublish、test等）の場合はprefixなし
- yarnの場合は`npm_config_user_agent`に"yarn"が含まれるかで判定
- watchモード時は`press \`u\``、それ以外は`run \`{script} -u\``または`re-run jest with \`-u\``
- `getSnapshotSummary`関数は`packages/jest-reporters/src/getSnapshotSummary.ts`で定義
- `ARROW = ' \u203A '`（›）、`DOWN_ARROW = ' \u21B3 '`（↳）、`DOT = ' \u2022 '`（•）が使用される

---

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

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

### 推奨読解順序

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

まず、通知処理で使用されるデータ構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | SnapshotSummary型 | `packages/jest-test-result` | SnapshotSummaryの構造を確認 |

**読解のコツ**: SnapshotSummaryには追加/更新/不一致/未チェック等の各種カウントと詳細リストが含まれる。

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

処理の起点となるファイル・関数を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | SummaryReporter.ts | `packages/jest-reporters/src/SummaryReporter.ts` | _printSnapshotSummaryメソッド |

**主要処理フロー**:
1. **142-183行目**: `_printSnapshotSummary`メソッド
2. **146-152行目**: 出力条件チェック（いずれかが0より大きい場合）
3. **153-172行目**: updateCommandの動的生成
4. **174-178行目**: `getSnapshotSummary`呼び出しとループ出力
5. **180行目**: 空行出力

#### Step 3: スナップショットサマリー生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | getSnapshotSummary.ts | `packages/jest-reporters/src/getSnapshotSummary.ts` | サマリーメッセージ生成 |

**主要処理フロー**:
- **25-138行目**: `getSnapshotSummary`関数
- **31行目**: ヘッダー "Snapshot Summary" 追加
- **32-38行目**: 追加スナップショットのメッセージ
- **40-51行目**: 不一致スナップショットのメッセージ
- **53-59行目**: 更新スナップショットのメッセージ
- **61-88行目**: 削除ファイルのメッセージ
- **98-135行目**: 未チェックスナップショットのメッセージ

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

```
SummaryReporter.onRunComplete()
    │
    └─ _printSnapshotSummary()
           │
           ├─ 出力条件チェック
           │      └─ added || filesRemoved || unchecked || unmatched || updated
           │
           ├─ updateCommand生成
           │      ├─ [watch/watchAll] "press `u`"
           │      ├─ [npm script] "run `{script} -u`"
           │      └─ [その他] "re-run jest with `-u`"
           │
           └─ getSnapshotSummary()
                  │
                  ├─ "Snapshot Summary" ヘッダー
                  │
                  ├─ [added] "X snapshots written"
                  │
                  ├─ [unmatched] "X snapshots failed"
                  │
                  ├─ [updated] "X snapshots updated"
                  │
                  ├─ [filesRemoved]
                  │      ├─ [didUpdate] "X files removed"
                  │      └─ [!didUpdate] "X files obsolete"
                  │
                  └─ [unchecked]
                         ├─ [didUpdate] "X snapshots removed"
                         └─ [!didUpdate] "X snapshots obsolete"
```

### データフロー図

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

AggregatedResult ───────▶ SummaryReporter._printSnapshotSummary()
  snapshot                      │
    added                       │
    filesAdded                  ├─▶ 条件チェック
    updated                     │
    filesUpdated                │
    unmatched                   ├─▶ updateCommand生成
    filesUnmatched              │       │
    filesRemoved                │       ├─ [watch] "press `u`"
    filesRemovedList            │       └─ [その他] "run ... -u"
    unchecked                   │
    uncheckedKeysByFile         ├─▶ getSnapshotSummary()
    didUpdate                   │       │
                                │       └─▶ サマリー配列
GlobalConfig ───────────────────┤
  watch                         │
  watchAll                      └─▶ for (summary) log() ───▶ stderr
                                           │
環境変数 ───────────────────────────────────┤
  npm_config_user_agent                    └─ "Snapshot Summary\n..."
  npm_lifecycle_event
  npm_lifecycle_script
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SummaryReporter.ts | `packages/jest-reporters/src/SummaryReporter.ts` | ソース | _printSnapshotSummary実装（142-183行目） |
| getSnapshotSummary.ts | `packages/jest-reporters/src/getSnapshotSummary.ts` | ソース | サマリーメッセージ生成 |
| BaseReporter.ts | `packages/jest-reporters/src/BaseReporter.ts` | ソース | log()メソッド |
| formatTestPath.ts | `packages/jest-reporters/src/formatTestPath.ts` | ソース | ファイルパスのフォーマット |
| SnapshotSummary型 | `packages/jest-test-result` | 型定義 | スナップショットサマリー構造 |
