UUUM攻殻機動隊(エンジニアブログ)

UUUMのエンジニアによる技術ブログです

Jestをvue-test-utilと組み合わせてスナップショットテストやってみた

フロンエンドエンジニアごーです。

vue-test-utilsのドキュメントを読んでいて、Jestというテストフレームワークが紹介されていたので、どんな機能があるのか試してみました。

Jestとは

Facebook社製の快適なJavascriptのテストを実現するためのフレームワーク。

Reactアプリケーションを含む全ての JavaScriptコードのテストに利用可能で、複雑な設定ナシで高速に動作する。

  • githubのstar: 13,840 (2017/12/04の時点で)
  • 2014年から開発が行われている

facebook/jest

単一ファイルコンポーネント(SFC)をテストする

  • 事前コンパイルが必要
  • Jestプリプロセッサを使用するので、テスト過程でwebpackは不要
  • 基本的なSFC(StatelessFunctionalComponent)機能をサポートしているがvue-loaderでサポートされている、スタイルブロックやカスタムブロックは評価していない

スナップショットテスト

初回テストでUIコンポーネントをレンダリングし、結果を.snapshot というファイルが生成される。

ファイル名は、テストファイルに対応する。

初回移行は、生成されたコンポーネントツリーを以前と比較してUI が予期せず変更されていないかをテストする。

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`List.vue matches snapshot 1`] = `
<ul>
    <li>
        item 1
    </li>
    <li>
        item 2
    </li>
</ul>
`;

.snapshotファイルの扱いに関しては、Jestの公式ドキュメントに記述があるので参考にすると良い。

スナップショットテスト

セットアップ

vue-test-utilのドキュメントにある通りに、以下のサンプルリポジトリをクローンする。

$ git clone https://github.com/vuejs/vue-test-utils-jest-example.git

クローンしたディレクトリに移動して、依存するライブラリをインストール。

$ cd vue-test-utils-jest-example/
$ npm i

vue-jest

単一ファイルコンポーネント(SFC)をテストするには、JavaScriptへ事前コンパイルが必要。

Jestは、.vue ファイルをコンパイルしない。

vue-jestがインストールされていると、package.json にjestフィールドを追加して.vueをコンパイルの対象を指定できる。

  "jest": {
    "moduleFileExtensions": [
      "js",
      //  vueファイルをコンパイルするように指示
      "vue"
    ],
    // 単一ファイルコンポーネントをインポートするためのエイリアス
    // vue-cliプロジェクトで一般的な@をsrcへ割り当てる
    "moduleNameMapper": {
      "^@/(.*)$": "<rootDir>/src/$1"
    },
    "transform": {
     // ES2015 機能をサポートするために必要
      "^.+\\.js$": "<rootDir>/node_modules/babel-jest",
      // 単一ファイルコンポーネントをJavaScriptへ変換する
      ".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
    },
    // カスタムシリアライザを使用して読みやすいスナップショットを表示する
    // 改善されたスナップショットをJestのスナップとして渡す
    "snapshotSerializers": [
      "<rootDir>/node_modules/jest-serializer-vue"
    ],
    // ソースマップを使用する
    "mapCoverage": true
  }

テストファイル

Jestは、.spec.js, .test.js の拡張子を持つ全てのテストファイルを再帰的に取得しテストを実行する。

公式で推奨しているのは、__test__ディレクトリにテストファイルを置くように勧めている。

テストファイルは、自由に置くこともできるが、スナップショットテストが行われるとテストファイルと同階層に__snapshots__ディレクトリが作成されることに注意。

import { shallow } from 'vue-test-utils'
import { createRenderer } from 'vue-server-renderer'

import List from '@/components/List.vue'

describe('List.vue', () => {
  it('matches snapshot', () => {
    // ダミーのprops
    const items = ['item 1', 'item 2']
    const renderer = createRenderer()
    // コンポーネントをマウント
    const wrapper = shallow(List, {
      propsData: { items }
    })
    // コンポーネントをHTML文字列にレンダリング
    renderer.renderToString(wrapper.vm, (err, str) => {
      if (err) throw new Error(err)
      // 最新のスナップショットと一致するか比較
      expect(str).toMatchSnapshot()
    })
  })
})

テスト実行

package.jsonを見てみると、以下の様にnpm-scriptsでtestコマンドを介してjest実行が定義されあった。

  "scripts": {
        // 省略
    "test": "jest"
  },

テストを実行してみる。

$ npm test

マークアップに変更があれば、Jestはテスト実行時にスナップショットに変更があることを以下の様に警告する。

 FAIL  __test__/List.test.js
  ● List.vue › matches snapshot

    expect(value).toMatchSnapshot()
    
    Received value does not match stored snapshot 1.
    
    - Snapshot
    + Received
    
      <ul>
          <li>
    -         item 1
    +         item
          </li>
          <li>
              item 2
          </li>
      </ul>
      
      at __test__/List.test.js:23:19
      at Object.<anonymous> (__test__/List.test.js:21:14)
      at process._tickCallback (internal/process/next_tick.js:109:7)

 › 1 snapshot test failed.

意図的にスナップショットを変更したい場合は、スナップショットを再生成するオプションを付けてjestを実行する。

$ ./node_modules/.bin/jest -u

また、--coverrageオプションを付けてテストを実行すると、簡単にカバレッジも出すことも出来る。

$ ./node_modules/.bin/jest --coverage

以下、表示結果。

$ ./node_modules/.bin/jest --coverage
 PASS  test/Message.spec.js
 PASS  test/List.spec.js
 PASS  test/MessageToggle.spec.js

Test Suites: 3 passed, 3 total
Tests:       5 passed, 5 total
Snapshots:   1 passed, 1 total
Time:        7.036s
Ran all test suites.
-------------------|----------|----------|----------|----------|----------------|
File               |  % Stmts | % Branch |  % Funcs |  % Lines |Uncovered Lines |
-------------------|----------|----------|----------|----------|----------------|
All files          |      100 |      100 |      100 |      100 |                |
 Message.js        |      100 |      100 |      100 |      100 |                |
 MessageToggle.vue |      100 |      100 |      100 |      100 |                |
-------------------|----------|----------|----------|----------|----------------|

他にもたくさんのオプションが用意されているので、-hオプションで見つけて色々と試してみるといいだろう。

$ ./node_modules/.bin/jest -h

まとめ

vue-test-utils程ではないが、 Jestもドキュメントの和訳が進んでいて導入のハードルは低いように思った。

JestのassertionAPIは、スナップショットテスト以外にもたくさんある。

Jasmineと似ている様なのでとっつきやすいのかもしれない。

Jest和訳ドキュメント
vue-test-utils和訳ドキュメント