【Jest】Jest概要学習備忘録

# はじめに
Jestについて学習したことを整理して備忘録としてまとめました。

# 学習内容
## Jestの特徴
- 設定がほとんど不要で導入が簡単
- 依存関係のモック化が簡単
- スナップショットテストが簡単
- 並列テストで高速なテスト
- カバレッジレポート
- 柔軟なマッチャー

## インストールと設定
`$ npm install --save-dev jest`
`--save-dev`は、開発環境用のインストールであることを表す。
デフォルトの`package.json`の"scripts"内の"test"の値を"jest"にする。

## マッチャー
jestにおける一般的なマッチャーの例（`toBe()`は厳密等価）
```js
test('adds 1 + 2 to equal 3', () => {
    expect(sum(1, 2)).toBe(3);
});
```
なお、`toBe`の前に`.not`をはさむと、逆をテストできる。
その他の例は次のとおり。
- `toBeNull` は null のみ一致
- `toBeUndefined` は undefined のみ一致
- `toBeDefined` は toBeUndefined の反対です
- `toBeTruthy` は if ステートメントが真であるとみなすものに一致
- `toBeFalsy` は if ステートメントが偽であるとみなすものに一致
- 数値の比較は、数学記号に対応するマッチャーが用意されている。例｜`toBeGreaterThanOrEqual`　など
- 文字列では、正規表現でマッチできる。マッチャーは、`toMatch`
- 配列などに、ある要素が含まれるかどうかをテストするには、`toContain`を使う
- ある関数が呼び出し時に例外を投げることをテストするには、`toThrow`を用いる。このとき、テスト対象の関数は、ラムダ関数でラッピングしなければならない。 例｜`expect(() => targetThrowExcept()).toThrow`

## 非同期処理のテスト
### Async/Await
Jestで非同期関数をテストするには、Async/Awaitが便利。testに渡す関数に`async`を付け、非同期処理を`await`で待ってから`expect`。`await`しないと、処理完了前にテストが進行するので注意。
### Promise
Jestで非同期処理をPromiseでテストするなら、Promiseをreturnし、メソッドチェーン内でexpectを実行。Promiseがrejectされるとテストは失敗。
`expect`の後に`resolve`マッチャーを付けた上でpromiseをreturnすれば、promiseが解決することをテストできる。rejectも同様。
###　コールバック
非同期処理のコールバックテストは、`test`に`done`を渡して、`expect`後に`done()`を呼ぶ。エラー時は`done(error)`を`catch`で処理。
### アサーションの確認
`expect.assertions(number)`で、特定の回数だけアサーションが実行されたかを確認。非同期コードのテストで、ちゃんとアサーションが呼ばれたかチェックするのに便利。

## モック関数
### モック関数の作成とテスト実行
`jest.fn(callback)`でモック関数作成。mockプロパティで呼び出し時のデータや返り値が確認でき、関数の動作を詳細に追える。モック関数を使ってテスト対象を実行し、モック関数のmockプロパティをexpectでチェック。コールバックが期待通り呼ばれているかをテストできる。
### 戻り値の注入
モック関数は、テスト用の値注入にも便利。モック関数（引数無し）を作成し、その`mockReturnValueOnce`をメソッドチェーンで繋げば、モック関数を呼び出すごとにメソッドチェーンの順で指定した値を返す。
### API利用部分のモック化
APIにアクセスせずにテストするためには、`jest.mock()`で例えばaxiosをモックし、`mockResolvedValue`を使って任意のデータを返すように設定可。これにより、`axios.get('/users.json')`などの呼び出しに対して偽（仮）のレスポンスを返すことが可能。
### 実装のモック化
特定の値を返すだけでなく、実装自体をモックしたい場合は、`jest.fn`やモック関数の`mockImplementationOnce`メソッドを使えば実現できる。
`mockImplementation`はモック関数のデフォルト実装を設定することが可能。
呼び出しごとに異なる結果を返したい場合は`mockImplementationOnce`を使用する。
実装が尽きた場合、`jest.fn`のデフォルト実装が実行される。
### モジュールのモック化
`jest.mock()`の引数にモジュール名を渡すと、モジュール全体をモック化できる。

## Jestの詳細設定
Jestの詳細な設定は、jest.config.js|ts|mjs|cjs|jsonといったファイルで定義するのが推奨されており、これらのファイルは自動的に検出される。設定はオブジェクトとしてエクスポートする。
`testEnvironment`はJestのテスト実行環境を設定するオプション。デフォルトはNode.js環境だが、フロントエンドのテストにはjsdomを使ってブラウザに近い環境で実行できる。
`setupFiles`と`setupFilesAfterEnv`は、Jestでテストを実行する前に特定の設定や処理を行うための設定。jest.config.jsで、テスト前に実行するファイルを指定できる。

## テストカバレッジ
アプリのテストカバレッジを見るにはコンソールで以下コマンドを実行する。
`npm test --coverage`
`coverage/`というディレクトリが生成され、index.htmlに、わかりやすくテストサマリが表示される。

## describe
`describe`は、関連するテストを1つのブロックにまとめるためのメソッドで、その中に関連するテストケースを記述する。

## スナップショットテスト
Jestのスナップショットテストは、テスト対象の出力（UIコンポーネントやオブジェクトの構造、簡単に言うとHTML）を保存し、後のテストでその出力がスナップショットと一致しているか確認する手法。
`expect(UIコンポーネント).toMatchSnapshot();`と実行すると、スナップショットファイルが作成され、以降はこのスナップショットと比較される。不一致ならばテスト失敗。意図的な更新ならば、`jest --updateSnapshot`で更新可。テストファイル内にスナップショットを記述する（インライン）こともできる

## カスタムマッチャー
カスタムマッチャーは、`expect().extend()`に関数をオブジェクトに包んでから渡して(つまり、expect().extend({関数})とする。)作成する。その関数内で条件判定のロジックを書き、最後に`message`と`pass`をキーに持つオブジェクトを返す。`pass`の真偽値がテスト結果となる。
テストを実行する際は、`expect().カスタムマッチャー()`と呼び出す。

# 参考文献
https://jestjs.io/ja/docs/getting-started