# 帳票設計書 6-NotifyReporter

## 概要

本ドキュメントは、Jestテストフレームワークにおけるデスクトップ通知レポーター「NotifyReporter」の設計仕様を定義する。NotifyReporterは、テスト結果をOS標準のデスクトップ通知機能を使用して表示するレポーターであり、node-notifierライブラリを使用してクロスプラットフォームな通知を実現する。

### 本帳票の処理概要

NotifyReporterは、テスト実行完了時にデスクトップ通知としてテスト結果を表示する。成功時は緑のチェックマーク付きで合格テスト数を、失敗時は赤い禁止マーク付きで失敗テスト数を通知する。watchモードでは、通知から直接テストの再実行や終了を選択できるインタラクティブなアクションボタンも提供する。

**業務上の目的・背景**：開発者がテスト実行中に他の作業を行っている場合、テスト完了を見逃すことがある。NotifyReporterは、OSのネイティブ通知機能を使用することで、テスト完了を確実に開発者に伝え、特に失敗時には即座に対応できるようにする。watchモードでは、通知からの直接アクションにより、ターミナルに戻ることなく次のアクションを取ることができる。

**帳票の利用シーン**：ローカル開発環境でのテスト実行時に使用される。特にwatchモードでの継続的なテスト実行、バックグラウンドでのテスト実行時に有用。`--notify`オプションまたは`notify: true`設定で有効化。

**主要な出力内容**：
1. テスト結果タイトル（パッケージ名 + 合格/不合格率）
2. 結果メッセージ（合格/失敗テスト数）
3. Jestロゴアイコン
4. アクションボタン（watchモード時：Run again / Exit tests）

**帳票の出力タイミング**：onRunCompleteイベント時、すべてのテスト実行が完了した後にデスクトップ通知が送信される。

**帳票の利用者**：ソフトウェア開発者

## 帳票種別

通知レポート / デスクトップ通知

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| OS-01 | macOS通知センター | N/A | 通知表示 |
| OS-02 | Windows通知センター | N/A | 通知表示 |
| OS-03 | Linux通知デーモン | N/A | 通知表示 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | OSネイティブ通知 |
| 用紙サイズ | N/A |
| 向き | N/A |
| ファイル名 | N/A |
| 出力方法 | node-notifierによるデスクトップ通知 |
| 文字コード | UTF-8 |

### 通知設定

| 項目 | 内容 |
|-----|------|
| アイコン | Jestロゴ（jest_logo.png） |
| タイムアウト | false（自動消去なし） |
| ヒント | int:transient:1 |

## 帳票レイアウト

### レイアウト概要

デスクトップ通知は、OSごとに異なる表示形式となるが、基本的な構成は以下の通り。

```
┌─────────────────────────────────────┐
│  [Jestロゴ]                         │
│                                     │
│  {パッケージ名} - 100% Passed       │
│  ✅ 50 tests passed                 │
│                                     │
│  [Run again] [Exit tests]           │
└─────────────────────────────────────┘
```

### 成功通知

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | アイコン | Jestロゴ | 固定パス | PNG画像 |
| 2 | タイトル | パッケージ名 + 合格率 | hasteFS + numPassedTests | "{package} - 100% Passed" |
| 3 | メッセージ | 合格テスト数 | numPassedTests | "✅ N tests passed" |

### 失敗通知

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | アイコン | Jestロゴ | 固定パス | PNG画像 |
| 2 | タイトル | パッケージ名 + 失敗率 | hasteFS + 計算 | "{package} - N% Failed" |
| 3 | メッセージ | 失敗テスト数 | numFailedTests, numTotalTests | "⛔️ N of M tests failed" |
| 4 | アクション | 再実行/終了ボタン | watchモード時のみ | [Run again] [Exit tests] |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| テスト存在 | numTotalTests !== 0 | Yes |
| notifyMode設定 | 通知条件に合致 | Yes |

### notifyMode設定一覧

| モード | 成功時通知 | 失敗時通知 | 状態変化時のみ |
|-------|-----------|-----------|--------------|
| always | ○ | ○ | - |
| success | ○ | - | - |
| failure | - | ○ | - |
| change | ○ | ○ | ○ |
| success-change | ○ | ○(状態変化時) | 部分的 |
| failure-change | ○(状態変化時) | ○ | 部分的 |

### 改ページ条件

N/A（デスクトップ通知）

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

### 参照テーブル一覧

N/A（テスト実行結果を使用）

### データ構造参照

#### AggregatedResult

| 参照項目 | 帳票項目との対応 | 用途 |
|---------|----------------|------|
| numTotalTests | テスト存在判定 | 通知条件 |
| numPassedTests | 成功テスト数 | 成功メッセージ |
| numFailedTests | 失敗テスト数 | 失敗メッセージ |
| numRuntimeErrorTestSuites | 失敗判定 | 成功/失敗判定 |

#### ReporterContext

| 参照項目 | 帳票項目との対応 | 用途 |
|---------|----------------|------|
| previousSuccess | 状態変化判定 | notifyMode判定 |
| firstRun | 初回実行判定 | notifyMode判定 |
| startRun | テスト再実行 | アクションボタン |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| 成功率 | 100（固定） | なし | 全テスト成功時 |
| 失敗率 | Math.ceil((numFailedTests / numTotalTests) * 100) | 切り上げ | NaN対策あり |
| 成功判定 | numFailedTests === 0 && numRuntimeErrorTestSuites === 0 | なし | - |
| 状態変化 | previousSuccess !== success \|\| firstRun | なし | - |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[onRunComplete] --> B[成功判定]
    B --> C[パッケージ名取得]
    C --> D{testsHaveRun?}
    D -->|No| E[終了]
    D -->|Yes| F{成功かつnotifyMode条件?}
    F -->|Yes| G[成功通知送信]
    F -->|No| H{失敗かつnotifyMode条件?}
    H -->|Yes| I{watchMode?}
    H -->|No| J[終了]
    I -->|Yes| K[アクション付き失敗通知]
    I -->|No| L[失敗通知送信]
    G --> M[previousSuccess更新]
    K --> M
    L --> M
    M --> N[firstRun = false]
    N --> E
```

### notifyMode判定フロー

```mermaid
flowchart TD
    A[notifyMode判定] --> B{success?}
    B -->|Yes| C{notifyMode?}
    B -->|No| D{notifyMode?}
    C -->|always| E[通知]
    C -->|success| E
    C -->|success-change| E
    C -->|change + 状態変化| E
    C -->|failure-change + 状態変化| E
    C -->|その他| F[スキップ]
    D -->|always| G[通知]
    D -->|failure| G
    D -->|failure-change| G
    D -->|change + 状態変化| G
    D -->|success-change + 状態変化| G
    D -->|その他| F
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| node-notifier未インストール | require失敗 | "notify reporter requires optional peer dependency \"node-notifier\" but it was not found" | Errorをスロー |
| 通知送信エラー | コールバックでerr受信 | - | エラーを無視して続行 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | N/A（単一通知） |
| 目標出力時間 | 即時（非同期通知） |
| 同時出力数上限 | 1 |

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

- 通知にはテスト数のみが含まれ、テスト内容の詳細は表示されない
- パッケージ名が通知に含まれるため、機密プロジェクト名の露出に注意
- 共有ディスプレイ環境では、他者に通知が見える可能性がある

## 備考

- node-notifierはオプションのピア依存関係であり、別途インストールが必要
- macOSでは絵文字（✅、⛔️）がタイトルに含まれる
- watchモードのアクションボタンは、すべてのOSでサポートされているわけではない
- exit-xパッケージを使用してテストを終了する（Exit testsアクション時）

---

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

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

### 推奨読解順序

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

まず、NotifyReporterで使用されるコンテキストデータを理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.ts | `packages/jest-reporters/src/types.ts` | ReporterContext型の定義（58-64行目）を確認 |

**読解のコツ**: ReporterContextのpreviousSuccess、firstRun、startRunがnotifyModeの判定と再実行機能に重要。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | NotifyReporter.ts | `packages/jest-reporters/src/NotifyReporter.ts` | コンストラクタ（28-32行目） |

**主要処理フロー**:
1. **21-26行目**: クラスプロパティ定義（_notifier, _globalConfig, _context）
2. **22行目**: `loadNotifier()` - node-notifierの遅延ロード
3. **28-32行目**: コンストラクタ - globalConfigとcontextの設定

#### Step 3: notifier読み込みを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | NotifyReporter.ts | `packages/jest-reporters/src/NotifyReporter.ts` | loadNotifier（158-170行目） |

**主要処理フロー**:
- **158-170行目**: `loadNotifier` - node-notifierの読み込み
- **160行目**: `require('node-notifier')` - 動的インポート
- **161-168行目**: MODULE_NOT_FOUNDエラー時のカスタムエラーメッセージ

#### Step 4: 通知処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | NotifyReporter.ts | `packages/jest-reporters/src/NotifyReporter.ts` | onRunComplete（34-155行目） |

**主要処理フロー**:
- **34-155行目**: `onRunComplete` - メインの通知処理
- **38-39行目**: 成功判定（`numFailedTests === 0 && numRuntimeErrorTestSuites === 0`）
- **41-57行目**: パッケージ名の取得（hasteFS使用）
- **61-64行目**: 状態変化とテスト実行の判定

#### Step 5: 成功通知を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | NotifyReporter.ts | `packages/jest-reporters/src/NotifyReporter.ts` | 成功通知部分（66-87行目） |

**主要処理フロー**:
- **66-74行目**: 成功時のnotifyMode条件判定
- **75-76行目**: タイトル生成（`${packageName}100% Passed`）
- **76-79行目**: メッセージ生成（macOSは✅絵文字付き）
- **81-87行目**: 通知送信（icon, message, timeout, title, hint）

#### Step 6: 失敗通知を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | NotifyReporter.ts | `packages/jest-reporters/src/NotifyReporter.ts` | 失敗通知部分（88-151行目） |

**主要処理フロー**:
- **88-96行目**: 失敗時のnotifyMode条件判定
- **97-103行目**: 失敗率とタイトル生成
- **104-108行目**: メッセージ生成（macOSは⛔️絵文字付き）
- **110-112行目**: watchMode判定とアクションボタン
- **114-141行目**: watchMode時のアクション付き通知
- **126-139行目**: アクションコールバック（Exit tests / Run again）
- **142-150行目**: 非watchMode時の通常通知

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 7-1 | NotifyReporter.ts | `packages/jest-reporters/src/NotifyReporter.ts` | 状態更新部分（153-154行目） |

**主要処理フロー**:
- **153行目**: `this._context.previousSuccess = success` - 成功状態の保存
- **154行目**: `this._context.firstRun = false` - 初回実行フラグをfalseに

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

```
NotifyReporter
    │
    ├─ BaseReporter (継承)
    │
    ├─ loadNotifier
    │      └─ require('node-notifier')
    │
    ├─ onRunComplete
    │      │
    │      ├─ 成功判定
    │      │      └─ numFailedTests + numRuntimeErrorTestSuites
    │      │
    │      ├─ パッケージ名取得
    │      │      └─ hasteFS.matchFiles / getModuleName
    │      │
    │      ├─ notifyMode判定
    │      │      └─ statusChanged + notifyMode条件
    │      │
    │      ├─ _notifier.notify (成功時)
    │      │      └─ icon, message, timeout, title, hint
    │      │
    │      └─ _notifier.notify (失敗時)
    │             ├─ actions (watchMode時)
    │             └─ コールバック
    │                    ├─ exit (Exit tests)
    │                    └─ startRun (Run again)
    │
    └─ pluralize (jest-util)
```

### データフロー図

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

AggregatedResult ───────▶ onRunComplete
       │                       │
       ├─▶ numFailedTests      ├─▶ success判定
       │                       │
       ├─▶ numTotalTests       ├─▶ testsHaveRun判定
       │                       │
       └─▶ numPassedTests      │
                               │
TestContext ───────────────────┤
       │                       │
       └─▶ hasteFS ────────────┴─▶ パッケージ名取得
                               │
ReporterContext ───────────────┤
       │                       │
       ├─▶ previousSuccess     ├─▶ statusChanged判定
       │                       │
       ├─▶ firstRun            │
       │                       │
       └─▶ startRun ───────────┴─▶ Run again アクション
                               │
GlobalConfig ──────────────────┤
       │                       │
       ├─▶ notifyMode          ├─▶ 通知条件判定
       │                       │
       └─▶ watch/watchAll      └─▶ アクションボタン表示 ─────▶ デスクトップ通知
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| NotifyReporter.ts | `packages/jest-reporters/src/NotifyReporter.ts` | ソース | 通知レポーター実装 |
| BaseReporter.ts | `packages/jest-reporters/src/BaseReporter.ts` | ソース | 基底クラス |
| types.ts | `packages/jest-reporters/src/types.ts` | ソース | 型定義（ReporterContext） |
| index.ts | `packages/jest-reporters/src/index.ts` | ソース | エクスポート定義 |
| jest_logo.png | `packages/jest-reporters/assets/jest_logo.png` | アセット | 通知アイコン |
