Vite環境のVue 3 + TypeScript にJest + Vue Test Utils 最新テスト環境構築

みなさんテストしてますか？
例え個人プロジェクトでどこにも公開しなくてもテストを欠かしてはいけません。欠かしてはいけないからです。
今回ようやく重い腰を上げてvueに手を出し、Viteで環境構築したVue3の個人プロジェクトでユニットテストしようとして環境構築に盛大に躓いてテストどころじゃなかったので記録。~~CLIで構築してればどれだけ楽だったか~~


## 実行環境
- macOS: 12.6.3
- node:16.18.0
- vite: 4.1.0
- vue: 3.2.45
- typescript: 4.9.3

## インストールするもの
@babel/preset-env: 7.20.2
@babel/preset-typescript: 7.21.0
@types/jest: 29.4.0
@vue/test-utils: 2.3.1
@vue/vue3-jest: 29.2.3
babel-jest: 29.5.0
jest: 29.5.0
jest-environment-jsdom: 29.5.0
ts-jest: 29.0.5


## 手順
### 上記パッケージのインストール
```:terminal
yarn add -D @babel/preset-env @babel/preset-typescript @types/jest @vue/test-utils @vue/vue3-jest babel-jest jest ts-jest vue-jest@next jest-environment-jsdom
```
* 万が一、上記バージョンが`29`で揃っているパッケージの中で、インストールした際にずれているものがあれば互換性の関係でエラーを起こすため`yarn add -D jest@^29`等コマンドでインストールし直し、バージョンを統一させる。

### jest.config.cjs を作成。
```diff_javascript:jest.config.cjs
module.exports = {
  moduleFileExtensions: ["vue", "js", "ts", "tsx" ],
  moduleNameMapper: {
    "\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$":
      "<rootDir>/__mocks__/fileMock.js",
  },
  preset: "ts-jest",
  testEnvironment: "jest-environment-jsdom",
  testEnvironmentOptions: {
    customExportConditions: ["node", "node-addons"],
  },
  transform: {
    "^.+\\.(t|j)s?$": "babel-jest",
    "^.+\\.vue$": "@vue/vue3-jest",
  },
};
```
* `transform`: Jestで`.vue`を扱えるようにするため、BabelでES6以降のコードをトランスパイルするための設定の記述。
* `moduleFileExtensions`: テスト対象の拡張子の設定
*  `preset: "ts-jest"`: TypeScriptで書かれたコードをテストするための設定。
* `testEnvironment: "jest-environment-jsdom"`: Jest v27以降、dom操作を行うJSDOMが別途インストール、設定する必要があるので記述。

#### 以下、テスト実行時エラーが起きた為に追加設定。
* `moduleNameMapper`: Jestが画像ファイルをjavascriptとして読み込もうとしていたためSyntaxErrorが発生。下記記事を参考にconfig設定 + `__mocks__`フォルダと中に`fileMock.js`を作成し、画像をモック化して対応。
```diff_javascript:__mocks__/fileMock.js
module.exports = '';
```


https://qiita.com/Amsel/items/8a4859d06a8de551abf8

* `testEnvironmentOptions`： Jest v27以降で起こるエラーの様。下記記事を参考に設定で解消。

https://stackoverflow.com/questions/72428323/jest-referenceerror-vue-is-not-defined

### babel.config.cjs を作成。
　Jestを実行する環境がNode.jsなので、Node.jsのバージョンを指定。
```diff_javascript:babel.config.cjs
module.exports = {
  env: {
    test: {
      presets: [
        ["@babel/preset-env", { targets: { node: "current" } }],
        "@babel/preset-typescript",
      ],
    },
  },
};
```

### package.json にテスト用コマンドの追加
```diff_javascript:package.json
  "scripts": {
    // 省略
+   "test": "jest"
  }
```

yarn test でテスト実行。


### 余談

とりあえず jest, vue-jest, @vue/test-utilsを入れてシンプルなテストをかけようとしたら下記エラーに当たる。
```diff_javascript
  ● Test suite failed to run

    Jest encountered an unexpected token

    This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.

    By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".
```
どうやら、、
JestはNode.js側で動くため、CommonJSが使われており、ES６から追加された`import`や`export`などのモジュール機能をサポートしていないため、ECMAScriptで書かれているコードはトランスパイルしないといけない。(CommonJsでは`require`を用いてモジュールを読み込む。)

ようなので、公式を参考に`babel`を入れることに。
上記手順の`jest.config.cjs`, `babel.config.cjs`を追記しテストを実行するとひとまず成功！


当初Jest v27で使っていた為、[こんなエラー](https://github.com/vuejs/vue-jest/issues/351)に引っかかったり、vue test utilsを過去の記事を参考にして`@vue/test-utils@next`でインストールしたがために少し古いバージョンで使っており、[こんなエラー](https://github.com/vuejs/test-utils/issues/1859)に引っかかって何度バージョンを変えたかわからないです、、、お陰で曖昧で放置していたyarnなどのパッケージ周りに少し強くなれました笑

疲れたのでこれで締めますが後日上記のエラーなどについても詳しく書きたいと思います、、、


#### その他の参考
https://github.com/vuejs/vue-jest

https://qiita.com/yukihiro-hyakuta/items/4515df3ca61299214509

https://zenn.dev/dozo/articles/0091f1a3e790d6