Jest に入門した話

#あらすじ
JavaScript のユニットテストフレームワークである Jest に入門しました。


#インデックス
- [Vue + TypeScript + Jest やってみた](#vue--typescript--jest-やってみた)


#Vue + TypeScript + Jest やってみた

#####参考
- https://vue-test-utils.vuejs.org/ja/installation/testing-single-file-components-with-jest.html
- https://jestjs.io/docs/ja/getting-started
- https://tech.recruit-mp.co.jp/front-end/post-14752/
- https://qiita.com/bathtimefish/items/c4db014b8b214d45162a

###環境設定の前に
Vue + Vuetify + TypeScript のプロジェクトを前提にしてます。
Jest のインストール方法は 3 種類あります。

1. Vue プロジェクト作成時に入れる
2. Vue プロジェクト作成後に vue add で入れる
3. Vue プロジェクト作成後に npm or yarn で入れる

1, 2 は正直おすすめできません。
package.json や jest.config.js の設定が反映されないためです。

https://github.com/vuejs/vue-cli/issues/1067
上の issue をみると、 Vue CLI が修正済みみたいなのですが上手く出来ませんでした。
2 の方法だと作成時に jest.config.js が作成されるのですが、そこに設定を入れても反映されませんでした。
（ Vue CLI ちょこちょこめんどくさい気がする...）

###環境設定
3 の方法でやっていきます。

#####Vue プロジェクトの作成
Babel, TypeScript, Lint を追加しておきます。

```
vue create {YOUR_PROJECT_NAME}
```

#####Vuetify の追加
```
vue add vuetify
```

tsconfig.json の types に vuetify と jest を入れるのを忘れずに。

#####Jest をインストール
```
yarn add --dev jest
```

#####Vue.js 向けの公式単体テストライブラリをインストール
https://vue-test-utils.vuejs.org/ja/

```
yarn add --dev @vue/test-utils
```

#####vue-jest プリプロセッサをインストール
```
yarn add --dev vue-jest
```

#####jest の型ファイル、 jest のプラグインをインストール
```
yarn add --dev ts-jest @types/jest
```

#####babel preset, babel core をインストール
- https://qiita.com/kawadumax/items/48568f8bdff7a65e3f46

3 系の vue-jest では、 6 系の babel を使う or babel-core@bridge を使う必要があります。

```
yarn add --dev @babel/preset-typescript @babel/core babel-core@bridge
```

#####babel-jest をインストール
```
yarn add --dev babel-jest
```

#####packagejson を編集
Jest を実行するためのコマンドを追加します。
Jest ブロックの記載内容については以下を参考に。

- https://doc.ebichu.cc/jest/docs/ja/configuration.html

何を記載するかは [Vue 公式の Jest のページ](https://vue-test-utils.vuejs.org/ja/installation/testing-single-file-components-with-jest.html)を見れば ok です。
Jest にトランスパイルの設定、テスト対象ファイルに `~.test.ts` or `~.spec.ts` を追加、テスト対象の拡張子の追加を行います。
カバレッジ計測対象に `ts` を含めれば ok です。
`*.d.ts` の型定義が含まれるとエラーになるらしい？ので除外します。

```json:package.json
"scripts": {
    "test": "jest"
  },
"jest": {
    "moduleFileExtensions": [
      "ts",
      "tsx",
      "js",
      "jsx",
      "json",
      "node"
    ],
    "transform": {
      ".*\\.(vue)$": "vue-jest",
      "^.+\\.js$": "<rootDir>/node_modules/babel-jest",
      "^.+\\.tsx?$": "ts-jest"
    },
    "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
    "moduleNameMapper": {
      "^@/(.*)$": "<rootDir>/src/$1"
    },
    "collectCoverage": true,
    "collectCoverageFrom": [
      "**/*.{js,vue}",
      "!**/node_modules/**",
      "src/**/*.ts",
      "!src/**/*.d.ts"
    ],
    "coverageReporters": [
      "html",
      "text-summary"
    ]
  }
```

※一部抜粋。

#####babel.config.js を編集
- https://qiita.com/riversun/items/6c30a0d0897194677a3

```javascript:babel.config.js
module.exports = {
  presets: [["@vue/cli-plugin-babel/preset"],
    ['@babel/preset-env', { targets: { node: 'current' } }]
    , '@babel/preset-typescript',],
};
```

###お試しテスト
せっかくなので vue ファイルのテストをします。
テスト対象は以下のファイルです。

```vue:HelloWorld.vue
<template>
  <div>HelloWorld.vue</div>
</template>

<script lang="ts">
import Vue from "vue";

export default Vue.extend({
  name: "HelloWorld",

  data: () => ({})
});
</script>
```

テストコードは以下のファイルです。

```javascript:HelloWorld.test.ts
import { mount } from '@vue/test-utils';
import HelloWorld from '@/components/HelloWorld.vue';

describe('Component', () => {
    it('is a Vue instance', () => {
        const wrapper = mount(HelloWorld);
        expect(wrapper.isVueInstance()).toBeTruthy();
    });
});
```

HelloWorld コンポーネントが vue インスタンスであるかテストしてます。

`yarn test` してみましょう。
テスト対象のファイルは config で設定出来ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557096/169e0441-3b6e-be59-b746-fbb50b653291.png)

`isVueInstance` は次のメジャーアップデートで非推奨になる、との警告が出てはいますがテストは pass してます。

また Jest ではカバレッジも出してくれます。
以下はカバレッジの Web レポートです。
![スクリーンショット 2020-12-03 23.55.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557096/3c214887-34ad-f51f-2430-cb907f2cf46f.png)

すべてグリーンだと気持ちが良いですね！
TypeScript 化もすんなりいけました！ (Cypress は大変だったけど)

#まとめ
導入が簡単なのがとても良い。