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は使ったコンポーネントのユニットテストができるようになると、比較的低コストでコンポーネントのテストができていいですね✨