インスト

テストランナを選ぶ

テストランナは、テストを実行するプログラムです。

多くの一般的な JavaScript テストランナがあり、vue-test-utils はそれらすべてで動作します。テストランナにとらわれません。

ですが、テストランナを選択する際には、機能セット、パフォーマンス、および単一ファイルコンポーネント (SFC) の事前コンパイルのサポートなどを考慮すべきです。既存のライブラリを慎重に比較した上で、以下の 2 つのテストランナをお勧めします:

  • Jest は最も充実したテストランナです。最小の設定が必要で、デフォルトで JSDOM を設定し、組み込みの検証を提供し、コマンドラインのユーザーエクスペリエンスが優れています。ただし、テストで SFC コンポーネントをインポートできるようにするには、プリプロセッサが必要です。最も一般的な SFC 機能を処理できる vue-jest プリプロセッサを作成しましたが、現在 vue-loader と 100% 同じ機能を持っていません。

  • mocha-webpack は webpack + Mocha のラッパですが、より合理的なインタフェースと watch モードを備えています。この設定のメリットは、webpack + vue-loader を使用して完全な SFC サポートを得ることができるということですが、より多くの設定を行う必要があります。

ブラウザ環境

vue-test-utils はブラウザ環境に依存します。技術的には、実際のブラウザで実行することはできますが、異なるプラットフォーム上で実際のブラウザを起動するという複雑さのため、お勧めできません。代わりに、JSDOM を使用して仮想ブラウザ環境で Node.js でテストを実行することをお勧めします。

Jest テストランナーは JSDOM を自動的に設定します。他のテストランナーの場合は、jsdom-global を使用してテスト用の JSDOM を手動で設定できます:

npm install --save-dev jsdom jsdom-global

// テストのセットアップと登録
require('jsdom-global')()

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

単一ファイルコンポーネントは、ノードまたはブラウザで実行する前に事前コンパイルが必要です。コンパイルを実行するには、Jest プリプロセッサを使用する方法と webpack を直接使用する方法が推奨されます。

vue-jest プリプロセッサは基本的な SFC 機能をサポートしていますが、現在 vue-loader でのみサポートされているスタイルブロックやカスタムブロックは扱いません。これらの機能やその他の Webpack 固有の設定に依存する場合は、webpack + vue-loader ベースの設定を使用する必要があります。

さまざまな設定については、次のガイドをお読みください:

リソース

Jest を使用した単一ファイルコンポーネントのテスト

このセットアップのサンプルプロジェクトは、 GitHub にあります。

Jest は Facebook が開発したテストランナであり、ユニットテストソリューションの提供を目指しています。 Jest の詳細については、公式ドキュメントを参照してください。

Jest のセットアップ

既に、webpack、vue-loader、および Babel が正しく設定されている設定から始めると仮定します。例: vue-cli によって雛形生成された webpack-simple テンプレートです。

まず Jest と vue-test-utils をインストールします:

$ npm install --save-dev jest @vue/test-utils

次に、package.json にスクリプトを定義する必要があります。

// package.json
{
  "scripts": {
    "test": "jest"
  }
}

Jest における単一ファイルコンポーネントの処理

Jest に *.vue ファイルの処理方法を教えるために、vue-jest プリプロセッサをインストールして設定する必要があります。:

npm install --save-dev vue-jest

次に、package.jsonjest ブロックを作成します:

{
  // ...
  "jest": {
    "moduleFileExtensions": [
      "js",
      "json",
      // *.vue ファイルを処理するように Jest に指示する
      "vue"
    ],
    "transform": {
      // vue-jest で *.vue ファイルを処理する
      ".*\\.(vue)$": "vue-jest"
    }
  }
}

注意: vue-jest は現在、カスタムブロックのサポートやスタイルのロードなど、vue-loader のすべての機能をサポートしていません。さらに、コード分割などの Webpack 固有の機能はサポートされていません。サポートされていない機能を使用するには、 Jest の代わりに Mocha をテストランナーとして使用します。そして、 Webpack をコンポーネントをコンパイルするために使用します。やり方は Mocha + webpack による単一ファイルコンポーネントのテストのガイドをお読みください。

Webpack エイリアスの処理

webpack 設定で、@/src のエイリアスにしたいといった場合、moduleNameMapperオプションを使って Jest の設定を追加する必要があります

{
  // ...
  "jest": {
    // ...
    // ソースコードにある @ を src へと割当てる
    "moduleNameMapper": {
      "^@/(.*)$": "<rootDir>/src/$1"
    }
  }
}

Jest のための Babel の設定

Node の最新バージョンではすでにほとんどの ES2015 機能がサポートされていますが、テストでは ES Modules 構文と stage-x 機能を使用することができます。そのために、babel-jest をインストールする必要があります。

npm install --save-dev babel-jest

次に、Jest に babel-jest で JavaScript テストファイルを処理するよう、package.jsonjest.transform の中にエントリを追加する必要があります:

{
  // ...
  "jest": {
    // ...
    "transform": {
      // ...
      // babel-jest で js を処理する
      "^.+\\.js$": "<rootDir>/node_modules/babel-jest"
    }
    // ...
  }
}

デフォルトでは、babel-jest はインストールしさえすれば自動的に設定します。しかし、*.vue ファイルのための変換を明示的に追加したため、babel-jest も明示的に設定する必要があります。

webpack で babel-preset-env を使用するとした場合、webpack は ES Modules 処理方法を既に知っているので、デフォルトの Babel 設定は ES Modules のトランスパイルを無効にします。ただし、Jest テストは Node で直接実行されるため、テスト用に有効にする必要があります。

また、babel-preset-env に、使用している Node のバージョンを指定するように指示することもできます。これにより不要な機能をスキップし、テストがより速く起動します。

これらのオプションをテストのためだけに適用するには、 env.test の下に別の設定をします(これは babel-jest によって自動的に選択されます)。

.babelrc:

{
  "presets": [["env", { "modules": false }]],
  "env": {
    "test": {
      "presets": [["env", { "targets": { "node": "current" } }]]
    }
  }
}

テストファイルの配置

デフォルトでは、Jest はプロジェクト全体で .spec.js または .test.js 拡張子を持つすべてのファイルを再帰的に取得します。これがあなたのニーズに合わない場合は、package.json ファイルの config セクションでtestRegex を変更することが可能です。

Jest は、テスト対象のコードのすぐ隣に__tests__ディレクトリを作成することを推奨していますが、適切にテストを構造化することは自由です。 Jest がスナップショットテストを実行するテストファイルの隣に__snapshots__ディレクトリを作成することに注意してください。

カバレッジ

Jest は複数のフォーマットでカバレッジを取ることができます。 以下はそれをするための簡単な例です。

jest の設定 (普通は package.json か  jest.config.js) に  collectCoverage オプションを加えます。それから、カバレッジを収集する対象のファイルを collectCoverageFrom に配列で定義します。

{
  "jest": {
    // ...
    "collectCoverage": true,
    "collectCoverageFrom": ["**/*.{js,vue}", "!**/node_modules/**"]
  }
}

デフォルトのカバレッジレポーターのカバレッジレポートは有効になります。 coverageReporters オプションでそれらをカスタマイズすることができます。

{
  "jest": {
    // ...
    "coverageReporters": ["html", "text-summary"]
  }
}

より詳しい情報は Jest configuration documentation にあります。 カバレッジの閾値やターゲットを出力するディレクトリなどのオプションが記載されています。

Spec の例

あなたが Jasmine をよく知っているなら、Jest の assertion APIは自宅のように感じるはずです。

import { mount } from '@vue/test-utils'
import Component from './component'

describe('Component', () => {
  test('is a Vue instance', () => {
    const wrapper = mount(Component)
    expect(wrapper.isVueInstance()).toBeTruthy()
  })
})

スナップショットテスト

Vue Test Utils でコンポーネントをマウントすると、コンポーネントのルート HTML 要素にアクセスすることができます。 Jest のスナップショットテストで使用するためにこれを保存することができます。

test('renders correctly', () => {
  const wrapper = mount(Component)
  expect(wrapper.element).toMatchSnapshot()
})

カスタムシリアライザを使用することによって保存されたスナップショットを改善することができます。

npm install --save-dev jest-serializer-vue

package.json でその設定をします。

{
  // ...
  "jest": {
    // ...
    // スナップショットに対するシリアライズ
    "snapshotSerializers": ["jest-serializer-vue"]
  }
}

リソース

Mocha + webpack による単一ファイルコンポーネントのテスト

このセットアップのサンプルプロジェクトは、 GitHub にあります。

単一ファイルコンポーネントをテストするためのもう一つの戦略は、webpack を使用してすべてのテストをコンパイルし、それをテストランナで実行することです。このアプローチの利点は、すべての webpack と vue-loader 機能を完全にサポートしていることです。ソースコードに妥協する必要はありません。

技術的に好きなテストランナを使用して結びつけることができますが、この特定の作業に非常に合理的な経験を提供するために mocha-webpack を見つけました。

mocha-webpack の設定

既に、webpack、vue-loader、および Babel が正しく設定されている設定から始めると仮定します。例: vue-cli によって雛形生成された webpack-simple テンプレートです。

最初に行うことは、テストの依存関係をインストールすることです:

npm install --save-dev @vue/test-utils mocha mocha-webpack

次に、package.json にスクリプトを定義する必要があります。

// package.json
{
  "scripts": {
    "test": "mocha-webpack --webpack-config webpack.config.js --require test/setup.js test/**/*.spec.js"
  }
}

ここで注意すべき点がいくつかあります:

  • --webpack-config フラグはテストに使う webpack 設定ファイルを指定します。ほとんどの場合、これは実際のプロジェクトで使用する設定と同じですが、小さな調整が 1 つあります。これについては後で話します。

  • --require フラグは、テストの前に test/setup.js ファイルが実行されることを保証します。このテストでは、テストを実行するためのグローバル環境を設定できます。

  • 最後の引数は、テストバンドルに含まれるテストファイルのグロブです。

別の webpack の設定

NPM 依存関係の外部化

私たちのテストでは、いくつかの NPM 依存関係をインポートする可能性があります。これらのモジュールの中には、ブラウザの使用を念頭に置いて記述されているものもあれば、webpack によって適切にバンドルされていないものもあります。依存関係を外部化することにより、テストの起動速度が大幅に向上するというもう一つの考慮すべき点としてあります。webpack-node-externals を使って NPM の依存関係をすべて外部化することができます:

// webpack.config.js
const nodeExternals = require('webpack-node-externals')

module.exports = {
  // ...
  externals: [nodeExternals()]
}

ソースマップ

ソースマップは、mocha-webpack によってピックアップされるようにインライン化する必要があります。推奨設定は次のとおりです:

module.exports = {
  // ...
  devtool: 'inline-cheap-module-source-map'
}

IDE 経由でデバッグする場合は、以下を追加することをお勧めします:

module.exports = {
  // ...
  output: {
    // ...
    // ソースマップで絶対パスを使用する(IDE 経由のデバッグで重要)
    devtoolModuleFilenameTemplate: '[absolute-resource-path]',
    devtoolFallbackModuleFilenameTemplate: '[absolute-resource-path]?[hash]'
  }
}

ブラウザ環境の設定

vue-test-utils はブラウザ環境を必要とします。jsdom-globalを 使って Node.js でシミュレーションすることができます:

npm install --save-dev jsdom jsdom-global

次に、test/setup.js の中で:

require('jsdom-global')()

これにより、node にブラウザ環境が追加され、 vue-test-utils が正しく動作するようになります。

検証ライブラリのピッキング

Chai は Mocha と並んで一般的に使用される一般的な検証ライブラリです。また、スパイとスタブを作成するための Sinon をチェックしてみてください。

あるいは、Jest の一部である expect を使うことができ、Jest のドキュメントにあるまったく同じ APIを公開しています。

ここで expect を使用してグローバルに利用できるようにして、すべてのテストでインポートする必要はありません。

npm install --save-dev expect

次に、test/setup.js の中で:

require('jsdom-global')()

global.expect = require('expect')

テストのための Babel の最適化

JavaScript を処理するには babel-loader を使用しています。.babelrc ファイルを使ってあなたのアプリでそれを使用しているならば、Babel を設定しておくべきです。babel-loader は自動的に同じ設定ファイルを使います。

注意すべき点の 1 つは、Node バージョン 6 以降を使用している場合、ES2015 の大部分の機能を既にサポートしているため、使用している Node のバージョンではサポートされていない機能のみをトランスパイルする Babel の env オプションを設定できます。(例えばstage-2や flow 構文のサポートなど)

テストを追加する

Counter.vue という名前の src ファイルを作成します。

<template>
  <div>
    {{ count }}
    <button @click="increment">Increment</button>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        count: 0
      }
    },

    methods: {
      increment() {
        this.count++
      }
    }
  }
</script>

次のコードを使って test/Counter.spec.js という名前のテストファイルを作成します。

import { shallowMount } from '@vue/test-utils'
import Counter from '../src/Counter.vue'

describe('Counter.vue', () => {
  it('increments count when button is clicked', () => {
    const wrapper = shallowMount(Counter)
    wrapper.find('button').trigger('click')
    expect(wrapper.find('div').text()).toMatch('1')
  })
})

これでテストを実行できます:

npm run test

やったー!テストを実行している!

カバレッジ

mocha-webpack にコードカバレッジをセットしたい場合は、 the mocha-webpack code coverage guide に従ってください。

リソース

Karma による単一ファイルコンポーネントのテスト

このセットアップの例は GitHub にあり、利用可能です。

Karma はブラウザを起動し、テストを実行しそれをレポートするテストランナーです。ここではテストを書くために Mocha を使用します。テストアサーションのために Chai を使用します。

Mocha をセットアップする

セットアップを始めるにあたって vue-cli でスキャフォールドされた webpack-simple テンプレートのように Webpack 、vue-loader 、 Babel が既に設定されていることを想定しています。

最初にテストに必要なライブラリをインストールします。

npm install --save-dev @vue/test-utils karma karma-chrome-launcher karma-mocha karma-sourcemap-loader karma-spec-reporter karma-webpack mocha

次に test スクリプトを package.json に定義します。

// package.json
{
  "scripts": {
    "test": "karma start --single-run"
  }
}
  • --single-run フラグは Karma にテストスウィートを 1 回実行するように指定します。

Karma の設定

プロジェクトディレクトリのトップに karma.conf.js ファイルを作成します。

// karma.conf.js

var webpackConfig = require('./webpack.config.js')

module.exports = function(config) {
  config.set({
    frameworks: ['mocha'],

    files: ['test/**/*.spec.js'],

    preprocessors: {
      '**/*.spec.js': ['webpack', 'sourcemap']
    },

    webpack: webpackConfig,

    reporters: ['spec'],

    browsers: ['Chrome']
  })
}

このファイルは Karma を設定するために使用されます。

ファイルを Webpack で前処理する必要があります。そのために、 Webpack をプリプロセッサとして加えます。そして、 Webpack の設定を含めます。プロジェクトに元々あった Webpack の設定ファイルを変更なしで使用することができます。

この設定では、 Chrome でテストを実行します。他のブラウザを加える方法は Karma のドキュメントにあるブラウザセクション を見てください。

アサーションライブラリを選ぶ

Chai はよく Mocha と一緒に使用される人気のあるアサーションライブラリです。spy と stub を生成するために Sinon を見てみるとよいかもしれません。

テストで Chai を使うために karma-chai プラグインをインストールします。

npm install --save-dev karma-chai

テストを加える

Counter.vue ファイルを  src ディレクトリに作成します。

<template>
  <div>
    {{ count }}
    <button @click="increment">Increment</button>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        count: 0
      }
    },

    methods: {
      increment() {
        this.count++
      }
    }
  }
</script>

そして、以下のようなコードの test/Counter.spec.js という名前のテストファイルを作成します。

import { expect } from 'chai'
import { shallowMount } from '@vue/test-utils'
import Counter from '../src/Counter.vue'

describe('Counter.vue', () => {
  it('increments count when button is clicked', () => {
    const wrapper = shallowMount(Counter)
    wrapper.find('button').trigger('click')
    expect(wrapper.find('div').text()).contains('1')
  })
})

テストを実行できるようになりました。

npm run test

やった!テストが走った。

カバレッジ

Karma にコードカバレッジをセットアップするために、 karma-coverage プラグインを使います。

デフォルトでは、 karma-coverage はソースマップをカバレッジレポートをマップすることに使用しません。だから、確実に正しくカバレッジがマップされるために babel-plugin-istanbul を使用します。

karma-coverage と  babel-plugin-istanbul と  cross-env をインストールします。

npm install --save-dev karma-coverage cross-env

環境変数の BABEL_ENV をセットするために cross-env を使います。テストをコンパイルする時に babel-plugin-istanbul を使用します。プロダクションコードをコンパイルする時は babel-plugin-istnabul を含めるべきではありません。

npm install --save-dev babel-plugin-istanbul

BABEL_ENV に test がセットされた時、 babel-plugin-istanbul を使用するために .babelrc ファイルを変更します。

{
  "presets": [["env", { "modules": false }], "stage-3"],
  "env": {
    "test": {
      "plugins": ["istanbul"]
    }
  }
}

カバレッジを取るために karma.conf.js ファイルを変更します。 coverage を reporters 配列に加えます。そして、 coverageReporter を加えます。

// karma.conf.js

module.exports = function(config) {
  config.set({
    // ...

    reporters: ['spec', 'coverage'],

    coverageReporter: {
      dir: './coverage',
      reporters: [{ type: 'lcov', subdir: '.' }, { type: 'text-summary' }]
    }
  })
}

そして、 BABEL_ENV をセットするために test スクリプトを変更します。

// package.json
{
  "scripts": {
    "test": "cross-env BABEL_ENV=test karma start --single-run"
  }
}

リソース