Vue、TypeScriptが導入時されているプロジェクトにJestを導入したので、そのあたりの手順をMEMOしておきます📝
- 関連ライブラリのinstall
- Jestの設定ファイル作成
- Jest実行用のコマンドをpackage.jsonに追加
- CIでJestを実行する
- 導入時に発生したエラー解消ログ
- おまけ:Jestで時間を固定する
- おわりに
前提として環境は以下の通りです
node
: 14.16.1yarn
: 1.22.4vue
: 2.6.12typescript
: 4.2.4jest
: 26.6.3
基本的には以下のドキュメントに従って導入しました📕
関連ライブラリの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 = { // Automatically clear mock calls and instances between every test clearMocks: true, // An array of file extensions your modules use moduleFileExtensions: ["js", "ts", "vue"], // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module moduleNameMapper: { "^@js(.*)$": "<rootDir>/app/javascript/$1", "^@css(.*)$": "<rootDir>/app/javascript/stylesheets/$1" }, // The glob patterns Jest uses to detect test files testMatch: ["**/?(*.)+(spec).[tj]s"], // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped testPathIgnorePatterns: ["/node_modules/", "/vendor/bundle/"], // A map from regular expressions to paths to transformers transform: { "^.+\\.js$": "babel-jest", "^.+\\.ts$": "ts-jest", ".*\\.(vue)$": "vue-jest", }, };
設定ファイルの各種設定値の詳細はこちら
Jest実行用のコマンドをpackage.json
に追加
私は以下のようなコマンドを用意しました👷♂️
"scripts": { "test": "jest --verbose", "test:coverage": "yarn test --coverage" }
--verbose
:テストごとの結果を表示する--coverage
:実行後にカバレッジレポートを表示
CLI時のオプションの詳細はこちら
適当なテスト用のコードを作成して正常に実行できれば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", },
参考
実行時に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
参考
実行時に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/*"] }
参考
おまけ:Jestで時間を固定する
jest-date-mock
が便利✨
以下のような形でadvanceTo
を使って引数で渡した時間に固定できる🕛
import { advanceTo } from "jest-date-mock"; advanceTo(new Date("2021-05-03T15:35:47+09:00"));
参考
おわりに
Jestを導入して、SnapShotは使ったコンポーネントのユニットテストができるようになると、比較的低コストでコンポーネントのテストができていいですね✨