Jest入門：JavaScriptのテストフレームワーク

## Jestとは？

**Jest**はFacebookが開発したJavaScriptのテスティングフレームワークで、Reactアプリケーションをはじめとする多くのJavaScriptプロジェクトで利用されています。設定が少なく、シンプルな構文でテストを書けることから、人気の高いテストツールです。

- **公式サイト**: [https://jestjs.io/](https://jestjs.io/)
- **対応言語**: JavaScript, TypeScript

## 特徴

- ✅ ゼロコンフィグで即利用可能  
- ✅ テストの高速実行（並列処理）  
- ✅ スナップショットテストによるUI検証  
- ✅ 柔軟なモック機能  
- ✅ TypeScript対応（`ts-jest`との併用）

---

## Jestのインストール方法

### JavaScriptプロジェクトの場合

```bash
$ npm install --save-dev jest
            or
$ yarn add --dev jest
```

### TypeScriptとの連携
TypeScriptを使っている場合、ts-jestを使って簡単に統合できます。

```bash
$ npm install --save-dev ts-jest @types/jest
```
```bash
$ npx ts-jest config:init
```
## package.jsonの設定

```json:package.json
{
  "scripts": {
    "test": "jest"
  }
}
```
----


## テストしてみる
ここでは、`sum.js`ファイル内の`sum`関数をテストしてみる

```js:sum.js
function sum(a, b) {
  return a + b;
}
module.exports = sum;
```

```js:sum.test.js
const sum = require('./sum');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});
```
### テストの実行
```bash
$ npm test
```
---
## Jest基本構文（`describe`, `test`, `expect`の使い方）

Jestでは、テストコードを読みやすく整理し、目的ごとにグルーピングして書けます。

### 1. `describe` : テストのグルーピング
`describe` ブロックは、テストをグループ化して**意味のある単位**にまとめるのに使います。

```js
describe('配列の操作', () => {
  test('配列に要素を追加できる', () => {
    const arr = [];
    arr.push(1);
    expect(arr).toHaveLength(1);
  });

  test('配列から要素を削除できる', () => {
    const arr = [1, 2];
    arr.pop();
    expect(arr).toEqual([1]);
  });
});
```
####  ✔ メリット
- テストの構造が明確になる
- テストの出力に階層構造が反映され、読みやすくなる

---

### 2. `test` と `it` : テストケースの定義
```js
test('1 + 2 = 3になる', () => {
  expect(1 + 2).toBe(3);
});
```
test と it は完全に同じ動作をします。好みに応じて使い分けられます。

```js
it('1 + 2 = 3になる', () => {
  expect(1 + 2).toBe(3);
});
```
it は「〇〇すべきだ（it should...）」というBDDスタイルで好まれる

### 3. `expect` : アサーション（期待値）
expect は、ある値がどうなるべきかを定義するテストの核心部分です。

```js
expect(actual).matcher(expected);
```
---

#### 主な matcher 一覧
|Matcher|説明|例
|---|---|---|
toBe(value)|厳密な一致（===）|expect(1 + 2).toBe(3)
toEqual(obj)|オブジェクト/配列の再帰的一致	|expect({a: 1}).toEqual({a: 1})
toContain(item)|配列や文字列に含まれる	|expect(['a', 'b']).toContain('a')
toHaveLength(n)|.lengthが特定の値	|expect([1, 2]).toHaveLength(2)
toBeTruthy()|trueとして扱われる	|expect(value).toBeTruthy()
toBeFalsy()|falseとして扱われる	|expect('').toBeFalsy()
toThrow()|例外がスローされる	|expect(() => fn()).toThrow()
resolves, rejects|Promiseに対するアサーション	|await expect(Promise.resolve(1)).resolves.toBe(1)

###  4. 非同期テストの書き方
#### async/await を使う
```js
test('データを非同期に取得', async () => {
  const data = await fetchData();
  expect(data).toBeDefined();
});
```
#### Promiseで書く
```js
test('Promiseが成功する', () => {
  return expect(Promise.resolve(5)).resolves.toBe(5);
});
```
### 5. beforeEach / afterEach などのフック
テストごとの事前・事後処理に使います。

```js
beforeEach(() => {
  // 各テストの前に実行
});

afterEach(() => {
  // 各テストの後に実行
});
```
また、1回だけ実行したい場合は beforeAll / afterAll を使います。

### ✅ 実例：すべての構文をまとめたサンプル
```js
describe('User モジュール', () => {
  let users = [];

  beforeEach(() => {
    users = ['Taro', 'Hanako'];
  });

  test('ユーザーを追加できる', () => {
    users.push('Ichiro');
    expect(users).toContain('Ichiro');
  });

  test('ユーザーを削除できる', () => {
    users.pop();
    expect(users).not.toContain('Hanako');
  });
});
```

## スナップショットテスト
ReactなどのUIコンポーネントの出力が変化していないかを検証できます。

```js
import renderer from 'react-test-renderer';
import MyComponent from './MyComponent';

test('snapshot test', () => {
  const tree = renderer.create(<MyComponent />).toJSON();
  expect(tree).toMatchSnapshot();
});
```

## モックの使い方
関数やモジュールの動作をモック（偽の動作）に置き換えて、依存を排除してテストできます。

- ### 関数のモック
    ```js
    const fetchData = jest.fn(() => 'mocked data');
    
    test('returns mocked data', () => {
      expect(fetchData()).toBe('mocked data');
    });
    ```
- ### モジュールのモック
    ```js
    jest.mock('./api');
    
    import { fetchUser } from './api';
    
    fetchUser.mockResolvedValue({ name: 'Taro' });
    
    test('mock API response', async () => {
      const user = await fetchUser();
      expect(user.name).toBe('Taro');
    });
    ```