ReactコンポーネントのテストにJest Snapshotを使いませんか？

# はじめに

Reactコンポーネントのテストしてますか？

僕は最近はじめました。

テスト初心者です。
僕でもできる簡単なテストからやっていこうと思います。

---

# 今回の内容

- Jestが何者か知る
- Jest Snapshotでできることを知る
- React Nativeでどう使うか
- まとめ

---

# Jestとは？

テストプラットフォームです。
最近ドキュメントが日本語化されました。
[公式ページ](http://facebook.github.io/jest/ja/)を参照すると

> FacebookではReactアプリケーションを含む全てのJavaScriptコードをテストするのに利用されています。

---

# Jest Snapshotとは？

Jestの機能の1つです。

[公式ページ](http://facebook.github.io/jest/docs/ja/snapshot-testing.html#content)を参照すると

> スナップショットのテストはUI が予期せず変更されていないかを確かめるのに非常に有用なツールです。

---

下記のようなタグがあったとして

```html
<a href="http://www.facebook.com">Facebook</a>
```

スナップショットはこんな感じで出力される

```text:__tests__/__snapshots__/link.react.test.js.snap
exports[`renders correctly 1`] = `
<a
  href="http://www.facebook.com"
>
  Facebook
</a>
`;
```

---

# React Nativeでどう使うか

---

## セットアップ方法

[公式ページ](https://facebook.github.io/react-native/docs/getting-started.html#getting-started)のセットアップ方法にある `react-native-cli` を利用すると、デフォで設定されている。
(ゼロ・コンフィギュレーションを目指してる)

```shell-session
$ react-native init AwesomeProject
```

```json:package.json
  "scripts": {
    "test": "jest"
  },
  "jest": {
    "preset": "react-native"
  }
```

---

## 今回テスト対象とするコンポーネント

<img src=https://qiita-image-store.s3.amazonaws.com/0/82745/07b4afee-f0c5-650d-c7c4-5a6abd9d8cc6.png width=50% />

---

```js:Intro.js
import React, {Component} from 'react';
import {
  StyleSheet,
  Text,
  View,
} from 'react-native';

const styles = StyleSheet.create({
  container: {
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
    flex: 1,
    justifyContent: 'center',
  },
  instructions: {
    color: '#333333',
    marginBottom: 5,
    textAlign: 'center',
  },
  welcome: {
    fontSize: 20,
    margin: 10,
    textAlign: 'center',
  },
});

export default class Intro extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to React Native!
        </Text>
        <Text style={styles.instructions}>
          This is a React Native snapshot test.
        </Text>
      </View>
    );
  }
}
```

---

## テストコード

```js:__tests__/Intro-test.js
import 'react-native';
import React from 'react';
import Intro from '../Intro';

// test renderer は react-native の後で import します
import renderer from 'react-test-renderer';

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

---

## テストを実行

スナップショットが存在しない場合は、自動的に生成されます。
次回からはスナップショットとの比較が行われて変更がないことを確認できます。

```shell-session
$ yarn test
```

コンポーネントを修正した場合はスナップショットをアップデートします。

```shell-session
$ yarn test -- -u
```

---

## 生成されたスナップショット

```text:__tests__/__snapshots__/Intro-test.js.snap
exports[`Intro renders correctly 1`] = `
<View
  style={
    Object {
      "alignItems": "center",
      "backgroundColor": "#F5FCFF",
      "flex": 1,
      "justifyContent": "center",
    }
  }>
  <Text
    style={
      Object {
        "fontSize": 20,
        "margin": 10,
        "textAlign": "center",
      }
    }>
    Welcome to React Native!
  </Text>
  <Text
    style={
      Object {
        "color": "#333333",
        "marginBottom": 5,
        "textAlign": "center",
      }
    }>
    This is a React Native snapshot test.
  </Text>
</View>
`;
```

---

# まとめ

とりあえずコンポーネントの表示が変わっていないことを確認できるテストを作ることができた。

Screenshotテストを導入したことで `react-native-elements` のバージョンアップ時に一部コンポーネントに変更があったことに気づくことができた。

Jest Screenshot 神!

---

しかし、Jestにはまだまだ機能があるので使いこなせるように頑張りましょう！

例）
- プリセット設定
- jest.mock を使ってネイティブモジュールをモック化
- 非同期処理のテスト

---

# 参考サイト

- https://github.com/facebook/jest/tree/master/examples/react-native/__tests__
- http://facebook.github.io/jest/ja/
- https://blog.callstack.io/unit-testing-react-native-with-the-new-jest-i-snapshots-come-into-play-68ba19b1b9fe