Vue、TypeScriptが導入時されているプロジェクトにJestを導入したので、そのあたりの手順をMEMOしておきます📝
前提として環境は以下の通りです
node
: 14.16.1
yarn
: 1.22.4
vue
: 2.6.12
typescript
: 4.2.4
jest
: 26.6.3
基本的には以下のドキュメントに従って導入しました📕
vue-test-utils.vuejs.org
関連ライブラリのinstall
まずは必要なライブラリをinstallします。
$ yarn add -D jest ts-jest babel-jest babel-core@bridge @vue/test-utils vue-jest @types/jest
それぞれの概要は以下の通り
jest
: Jest本体
ts-jext
: .ts
のコードをテストする場合に必要
babel-jest
: JestはWebpackでbuildするわけではないのでJestでもBabelを利用する場合に必要
babel-core@bridge
: 後述しますが無いとエラーになるので。。。
@vue/test-utils
: 単一ファイルコンポーネントのテスト用のAPIを利用するためのライブラリ
vue-jest
: .vue
のコードをテストする場合に必要
@types/jest
: Jestの型定義ファイル
Jestの設定ファイル作成
Jestの設定ファイルは以下のコマンドで作成できます。
$ jest --init
いくつか質問されるので自身の環境に合わせて設定します⚙
生成されたファイルに関して私は以下のことを行いました👷♂️
moduleFileExtensions
にテスト対象となりうる拡張子を指定
moduleNameMapper
をWebpackの設定ファイルと合わせて修正しaliasの解決ができるように
testMatch
をテスト対象のファイルに合わせて正規表現を見直してfoo.spec.ts
のみが対象となるように
testPathIgnorePatterns
にライブラリ関連のディレクトリを指定しテスト対象外に
transform
でファイル別に使用するライブラリを指定
最終的な設定ファイルは以下のような形になりました📝
module.exports = {
clearMocks: true,
moduleFileExtensions: ["js", "ts", "vue"],
moduleNameMapper: {
"^@js(.*)$": "<rootDir>/app/javascript/$1",
"^@css(.*)$": "<rootDir>/app/javascript/stylesheets/$1"
},
testMatch: ["**/?(*.)+(spec).[tj]s"],
testPathIgnorePatterns: ["/node_modules/", "/vendor/bundle/"],
transform: {
"^.+\\.js$": "babel-jest",
"^.+\\.ts$": "ts-jest",
".*\\.(vue)$": "vue-jest",
},
};
設定ファイルの各種設定値の詳細はこちら
jestjs.io
Jest実行用のコマンドをpackage.json
に追加
私は以下のようなコマンドを用意しました👷♂️
"scripts": {
"test": "jest --verbose",
"test:coverage": "yarn test --coverage"
}
--verbose
:テストごとの結果を表示する
--coverage
:実行後にカバレッジレポートを表示
CLI時のオプションの詳細はこちら
jestjs.io
適当なテスト用のコードを作成して正常に実行できればOKです🙆♂️
import { mount } from "@vue/test-utils";
import Component from "@js/components/Component.vue";
describe("components/Component.vue", () => {
it("snapshot", () => {
const wrapper = mount(Component);
expect(wrapper.element).toMatchSnapshot();
});
});
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 1 updated, 1 total
Time: 2.014 s
Ran all test suites.
✨ Done in 3.20s.
CIでJestを実行する
以下のようなgithub actions用のyamlを用意してpush時にJestによるテストを実行するようにしました🤖
name: node_test
on: [push]
jobs:
run-node-test:
runs-on: ubuntu-latest
env:
TZ: Asia/Tokyo
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: '14'
- name: cache node deps
uses: actions/cache@v1
with:
path: node_modules
key: ${{ runner.os }}-node_modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-node_modules-
- name: install node deps
run: yarn install
- name: test js
run: yarn test:coverage
導入時に発生したエラー解消ログ
実行時にSyntaxError: Cannot use import statement outside a module
が発生する
以下のようなエラーが発生
● Test suite failed to run
Jest encountered an unexpected token
Details:
SyntaxError: Cannot use import statement outside a module
ts-jest
を導入し、
yarn add -D ts-jest
jest.config.js
のtransform
に"^.+\\.ts$": "ts-jest"
を設定
transform: {
"^.+\\.js$": "babel-jest",
"^.+\\.ts$": "ts-jest",
".*\\.(vue)$": "vue-jest",
},
参考
github.com
実行時にCannot find module 'babel-core'
が発生する
以下のようなエラーが発生
● Test suite failed to run
Cannot find module 'babel-core'
babel-core@bridge
をinstallして解決
yarn add --D babel-core@bridge
参考
qiita.com
実行時にSyntaxError: Unexpected token } in JSON at position 545
が発生する
以下のようなエラーが発生
● Test suite failed to run
Jest encountered an unexpected token
SyntaxError: Unexpected token } in JSON at position 545
at JSON.parse (<anonymous>)
at parse (node_modules/tsconfig/src/tsconfig.ts:195:15)
ts-config
にJSONファイルとしては不正なカンマが入っていたため削除
before
"paths": {
"@js/*": ["app/javascript/*"],
"@css/*": ["app/javascript/stylesheets/*"],
}
after
"paths": {
"@js/*": ["app/javascript/*"],
"@css/*": ["app/javascript/stylesheets/*"]
}
参考
zenn.dev
おまけ:Jestで時間を固定する
jest-date-mock
が便利✨
github.com
以下のような形でadvanceTo
を使って引数で渡した時間に固定できる🕛
import { advanceTo } from "jest-date-mock";
advanceTo(new Date("2021-05-03T15:35:47+09:00"));
参考
qiita.com
おわりに
Jestを導入して、SnapShotは使ったコンポーネントのユニットテストができるようになると、比較的低コストでコンポーネントのテストができていいですね✨