Madogiwa Blog

主に技術系の学習メモに使っていきます。

Vue✕TypeScriptなプロジェクトにJestを導入する方法MEMO👢

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 = {
  // 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",
  },
};

設定ファイルの各種設定値の詳細はこちら

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.jstransform"^.+\\.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-configJSONファイルとしては不正なカンマが入っていたため削除

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