# 機能設計書 16-jest-snapshot

## 概要

本ドキュメントは、Jestテスティングフレームワークにおける`jest-snapshot`パッケージの機能設計を記述する。このパッケージは、スナップショットテストのコア機能を提供し、テスト実行時の値を記録・比較する機能を実現する。

### 本機能の処理概要

**業務上の目的・背景**：UIコンポーネントやAPIレスポンスなど、複雑なデータ構造の変更を追跡することは重要である。スナップショットテストは、テスト対象の出力を「スナップショット」として保存し、以降のテスト実行時に比較することで、意図しない変更（リグレッション）を検出する。これにより、手動での期待値記述を省略しつつ、変更検知の精度を高めることができる。

**機能の利用シーン**：
- Reactコンポーネントのレンダリング結果の検証
- シリアライズ可能なデータ構造の変更追跡
- エラーメッセージのスナップショットテスト
- インラインスナップショットによるコード内での期待値記述

**主要な処理内容**：
1. `toMatchSnapshot()` - 外部ファイルへのスナップショット保存・比較
2. `toMatchInlineSnapshot()` - テストコード内へのスナップショット埋め込み
3. `toThrowErrorMatchingSnapshot()` - エラーメッセージのスナップショット
4. `SnapshotState` - スナップショットファイルの状態管理
5. `SnapshotResolver` - スナップショットファイルパスの解決
6. カスタムシリアライザーのサポート

**関連システム・外部連携**：`@jest/snapshot-utils`（ユーティリティ）、`pretty-format`（シリアライズ）、Prettier（インラインスナップショット整形）と連携する。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 4 | Snapshot Testingページ | 参照画面 | スナップショットテストの概念・使い方説明 |
| 19 | Expect APIページ | 参照画面 | toMatchSnapshot等のマッチャー説明 |

## 機能種別

スナップショットテスト / アサーション / ファイル管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| received | unknown | Yes | テスト対象の値 | 任意の型 |
| propertiesOrHint | object\|string | No | プロパティマッチャーまたはヒント | オブジェクトまたは文字列 |
| hint | string | No | スナップショット名のヒント | 文字列 |
| inlineSnapshot | string | No | インラインスナップショット文字列 | 文字列 |

### 入力データソース

テストコードからの引数、既存スナップショットファイル

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| pass | boolean | マッチ結果 |
| message | () => string | エラーメッセージ生成関数 |
| actual | string | 実際の値（シリアライズ済み） |
| expected | string | 期待値（スナップショット） |

### 出力先

テストレポーター、スナップショットファイル（*.snap）

## 処理フロー

### 処理シーケンス

```
1. toMatchSnapshot()呼び出し
2. received値のシリアライズ（pretty-format使用）
3. スナップショットキー生成（テスト名 + カウンター）
4. 既存スナップショットの取得
5. 比較実行
6. 結果に応じて処理分岐
   ├─ 一致: pass=true
   ├─ 不一致: pass=false, 差分メッセージ生成
   └─ 新規: updateモードに応じてスナップショット保存
7. テスト終了時にスナップショットファイル書き込み
```

### フローチャート

```mermaid
flowchart TD
    A[toMatchSnapshot呼び出し] --> B[値のシリアライズ]
    B --> C[スナップショットキー生成]
    C --> D{既存スナップショット?}
    D -->|Yes| E[比較実行]
    D -->|No| F{updateモード?}
    E --> G{一致?}
    G -->|Yes| H[pass=true]
    G -->|No| I{updateモード?}
    I -->|Yes| J[スナップショット更新]
    I -->|No| K[pass=false, 差分表示]
    F -->|Yes/new| L[スナップショット追加]
    F -->|No| M[pass=false, 新規メッセージ]
    J --> H
    L --> H
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | スナップショットキー形式 | `テスト名 カウンター`（例: "test name 1"） | 常時 |
| BR-02 | 更新モード | --updateSnapshot=all で全更新、=new で新規のみ | CLI引数に応じて |
| BR-03 | 廃止スナップショット | 未使用スナップショットは--updateSnapshot=allで削除 | テスト終了時 |
| BR-04 | インライン優先 | インラインスナップショットがある場合は外部ファイルより優先 | インライン指定時 |

### 計算ロジック

スナップショットキー: `testNameToKey(testName, count)` = `${testName} ${count}`

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

該当なし（ファイルシステム使用）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| N/A | Error | snapshotStateが未初期化 | テスト環境の設定確認 |
| N/A | Error | .not修飾子との併用 | スナップショットマッチャーは.notと使用不可 |
| N/A | Error | propertiesが非オブジェクト | オブジェクトを渡す |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

スナップショットファイルはテスト終了時に一括書き込みし、I/Oを最小化。

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

特になし

## 備考

- スナップショットファイルは`__snapshots__`ディレクトリに保存
- ファイル拡張子は`.snap`
- インラインスナップショットはPrettierで整形

---

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

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

### 推奨読解順序

#### Step 1: マッチャー関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/jest-snapshot/src/index.ts` | toMatchSnapshot, toMatchInlineSnapshot |

**主要処理フロー**:
- **157-212行目**: toMatchSnapshot関数 - プロパティとヒントの処理
- **214-275行目**: toMatchInlineSnapshot関数 - インラインスナップショット処理
- **277-417行目**: _toMatchSnapshot内部関数 - コア比較ロジック
- **419-438行目**: toThrowErrorMatchingSnapshot
- **440-475行目**: toThrowErrorMatchingInlineSnapshot
- **477-551行目**: _toThrowErrorMatchingSnapshot

#### Step 2: SnapshotStateクラスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | State.ts | `packages/jest-snapshot/src/State.ts` | スナップショット状態管理 |

**主要処理フロー**:
- **57-101行目**: コンストラクタ - スナップショットデータ読み込み
- **111-136行目**: _addSnapshot - スナップショット追加
- **149-179行目**: save - ファイル書き込み
- **197-314行目**: match - スナップショット比較ロジック
- **316-327行目**: fail - 失敗記録

**読解のコツ**: `_updateSnapshot`の値（'all', 'new', 'none'）によって動作が変わる。

#### Step 3: スナップショット解決を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | SnapshotResolver.ts | `packages/jest-snapshot/src/SnapshotResolver.ts` | パス解決 |

**主要処理フロー**:
- **buildSnapshotResolver**: テストファイルパスからスナップショットファイルパスを解決
- **resolveSnapshotPath**: デフォルトのパス解決ロジック（__snapshots__ディレクトリ）

#### Step 4: シリアライズ処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | plugins.ts | `packages/jest-snapshot/src/plugins.ts` | シリアライザー管理 |
| 4-2 | utils.ts | `packages/jest-snapshot/src/utils.ts` | serialize関数 |

**主要処理フロー**:
- plugins.ts: addSerializer, getSerializers
- utils.ts: serialize - pretty-formatを使用した値のシリアライズ

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

```
toMatchSnapshot (index.ts:157)
    │
    └─ _toMatchSnapshot (index.ts:277)
           │
           ├─ snapshotState.match() (State.ts:197)
           │      │
           │      ├─ testNameToKey() (@jest/snapshot-utils)
           │      │
           │      ├─ serialize() (utils.ts)
           │      │      └─ prettyFormat (pretty-format)
           │      │
           │      └─ 比較実行
           │
           └─ printSnapshotAndReceived (printSnapshot.ts)
                  └─ diffStringsUnified (jest-diff)

SnapshotState.save() (State.ts:149)
    │
    ├─ saveSnapshotFile() (@jest/snapshot-utils)
    │
    └─ saveInlineSnapshots() (InlineSnapshots.ts)
           └─ Prettier統合
```

### データフロー図

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

received値 ─────────────▶ serialize() ──────────────▶ シリアライズ文字列
                              │
                              └─ pretty-format適用

テスト名, カウンター ───▶ testNameToKey() ──────────▶ スナップショットキー

スナップショットキー ───▶ snapshotState.match() ──▶ 比較結果
    │                         │
    │                         ├── 既存スナップショット取得
    │                         │
    │                         └── 文字列比較
    │
SnapshotState ──────────▶ save() ───────────────────▶ .snapファイル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/jest-snapshot/src/index.ts` | ソース | マッチャー関数エクスポート |
| State.ts | `packages/jest-snapshot/src/State.ts` | ソース | SnapshotStateクラス |
| SnapshotResolver.ts | `packages/jest-snapshot/src/SnapshotResolver.ts` | ソース | パス解決 |
| InlineSnapshots.ts | `packages/jest-snapshot/src/InlineSnapshots.ts` | ソース | インラインスナップショット処理 |
| plugins.ts | `packages/jest-snapshot/src/plugins.ts` | ソース | シリアライザー管理 |
| utils.ts | `packages/jest-snapshot/src/utils.ts` | ソース | ユーティリティ関数 |
| printSnapshot.ts | `packages/jest-snapshot/src/printSnapshot.ts` | ソース | 差分表示 |
| types.ts | `packages/jest-snapshot/src/types.ts` | ソース | 型定義 |
