create-react-appでjestを使う方法

create-react-appにてJestを導入するのにエラーや手順がわからず困ったので、成功した方法をここに書き残しておく。

主に参考にしたもの👇

https://jestjs.io/docs/getting-started

https://babeljs.io/docs/en/configuration#whats-your-use-case


## 環境
- jest: 27.0.6
- babel-jest: 27.0.6
- @babel/preset-env: 7.14.9
- @babel/preset-react: 7.14.5
- react: 17.0.2
 
## やったこと
兎にも角にもまずは`create-react-app`を実行

```
$ npx create-react-app jest-practice
$ cd jest-practice
```

まずはドキュメント通りに手順を踏んでみる

https://jestjs.io/docs/getting-started

```
1. npm install --save-dev jest
2. package.jsonのscriptsに` "test": "jest" `を追加
3. テストを書く
4. npm test
```

```package.json
{
  "scripts": {
    "test": "jest"
  },
  "devDependencies": {
    "jest": "^27.0.6"
  },
}
```

```App.jsx
export const add = (x, y) => x + y
```

```App.test.js
import { add } from "./App"

test("add 1 + 2 equal 3", () => {
  expect(add(1, 2)).toBe(3)
})
```

## 結果　

```javascript
jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.

Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.

By default "node_modules" folder is ignored by transformers.

// 省略

SyntaxError: Cannot use import statement outside a module
```

importの部分でsyntaxエラーが出ると思います。

## 何が原因か
エラー文からは、構文エラーで、`importが使えないよ`と言われています。
これはjestは現時点でES Modulesに対応していないので、ES Modulesを使用する場合はbabelの導入が必要になります。

jestはBabelの設定に基づいて、ファイルを有効なJSに変換します。
なので、Babelを使ってimportを使えるようにしていきましょう。

https://babeljs.io/docs/en/configuration#whats-your-use-case

> You want to compile node_modules?

とあるので、

> babel.config.json
Create a file called babel.config.json with the following content at the root of your project (where the package.json is).

を参考にして、package.jsonがある階層に `babel.config.json`　を作ります。

```
$ touch babel.config.json
```

次に中身はこのように書くとあります。

```json
{
  "presets": [...],
  "plugins": [...]
}
```

まずは、`presets`に`@babel/preset-react`を記述します。今回は`plugins`には何も書きません。
`Babel　Presets`は、指定されたモードでトランスパイルするように指示するbabel-transpilerの構成の詳細設定を行います。

```
$ npm install --save-dev @babel/preset-env
```

package.jsonの`devDependencies`に`@babel/preset-env`が追加されていることを確認します。

```package.json
{
  "devDependencies": {
    "jest": "^27.0.6",
    "@babel/preset-env": "^7.14.9"
  },
}
```

`babel.config.json`の`presets`の配列に`@babel/preset-env`を追加します。

```babel.config.json
{
  "presets": ["@babel/preset-env"]
}
```

@babel/preset-envは、ES2015-ES2020で追加された新しい書き方を、
どのブラウザでも動くようにES5にトランスパイルしてくれることをサポートしてくれます。
つまり、`@babel/preset-env`は、すべてのES2015-ES2020コードをES5互換に変換するためのプリセットです。

これでもう一回`npm test`を実行します。

```
SyntaxError: /Users/****/Desktop/practice/src/App.js: Support for the experimental syntax 'jsx' isn't currently enabled (5:5):

      3 | export const App = () => {
      4 |   return (
    > 5 |     <p>{add(1, 2)}</p>
        |     ^
      6 |   );
      7 | }
      8 |
```

> Support for the experimental syntax 'jsx' isn't currently enabled
実験的な構文である「jsx」のサポートは現在有効ではありません。

とまたsyntaxエラーがでます。
これを解決するためには、`@babel/preset-env`を使います。
@babel/preset-reactは、`jsx記法`をサポートしてくれるものです。

```
$ npm install @babel/preset-react
```

package.jsonの`devDependencies`に`@babel/preset-react`が追加されていることを確認します。

```package.json
{
  "devDependencies": {
    "@babel/preset-env": "^7.14.9",
    "@babel/preset-react": "^7.14.5",
    "jest": "^27.0.6"
  }
}
```

`babel.config.json`の`presets`の配列に`@babel/preset-react`を追加します。

```babel.config.json
{
  "presets": ["@babel/preset-env","@babel/preset-react"]
}
```

これでもう一回`npm test`を実行します。

```
 PASS  src/App.test.js
  ✓ add 1 + 2 equal 3 (3 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        4.89 s, estimated 6 s
Ran all test suites.
```

テストが通りました。


#紹介
私が所属している「もりけん塾」は、[もりけん先生](https://twitter.com/terrace_tech)が運営するJavaScriptに特化したコミュニティーです。（とは言ってもいろんな方がいらっしゃいます。）
フロントエンドエンジニアになりたい方にむけて、先生が道標となって初学者が迷わないように導いてくれます。コードの書き方、自走力を身に着けるにはとても良い環境です。
毎月1日に募集をかけていたのですが、ここ最近は募集かけなくても入塾したいとDMがくるそうです...!!（大人気）

[先生のブログ](https://kenjimorita.jp/)
[先生のTwitter](https://twitter.com/terrace_tech)