Tech Racho エンジニアの「?」を「!」に。
  • 開発

RailsのVue.jsをWebpackerとJestでテストする(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

RailsのVue.jsをWebpackerとJestでテストする(翻訳)

今やっているプロジェクトで、既存のRailsアプリにVue.jsを統合する方法の調査をを命じられました。とりあえず公式ガイドを読み、チュートリアルを視聴し、ブログを読みまくった結果、Vueコンポーネントを完全に動かせるようになりました。

最後の段階でいくつかテストを書こうとしましたが、残念なことにWebpacker gemにはテスト向け設定が含まれていなかったので、自分で設定せざるを得ませんでした。

驚いたことに、満足な設定方法がドキュメントに見当たらなかったのです。そこで私が何とかこれを動かせるようにしたときの方法を本記事で皆様と共有したいと考えました。

1. Jestのインストール

特にこれといった好みもなかったので、Jestを使うことに決めました。vue-cliも同梱されていたので使いました。

Jestのインストールで必要なのは、プロジェクトのルートディレクトリでyarn add --dev jestを実行することだけです。続いて、package.jsonに自分のテストスクリプトを追加します。

{
  "scripts": {
    "test": "jest",
    ...
  },
  ...
}

これで、yarn testを実行すればテストが走ります。

2. テストの置き場所を定義する

この時点でyarn testを実行しようとすると、config/webpack/test.jsでコケます。これは、Jestがプロジェクト内のテストファイルを探索する方法が原因です。基本的にはプロジェクト全体のうち.spec.js.test.jsにマッチするすべてのファイルを実行します。ここではテストファイルが*.test.jsとマッチしたので、テストとして実行されようとしていたのです。

自分たちのテストを実行する基準を満たすプロジェクト内の他のファイルと同様、Webpack configファイルを使わないようにしたいので、探索するファイルの場所をJestに指定する必要があります。

ここではRspecを使っていることもあり、spec/javascriptsディレクトリを探索場所として指定することにしました。もちろん、自分のプロジェクトに合う場所を自由に指定することもできます。

これを行うには、package.jsonファイルにrootsを追加しなければなりません。

"jest": {
  "roots": [
    "spec/javascript"
  ]
},

package.jsonのサイズがかなり大きいのでこのファイルにこれ以上設定を追加したくない場合は、--config <path/to/js|json>オプションでJest設定を定義できます。この方法にする場合、package.jsonは次のような感じになるはずです。

  {
    "scripts": {
      "test": "jest --config spec/javascript/jest.conf.js",
      ...
    },
    ...
  }

これが動作することを確認するために、以下のようなシンプルなテストをspec/javascript/team.spec.jsファイルを作成してもよいでしょう。

test('there is no I in team', () => {
  expect('team').not.toMatch(/I/);
});

これで再びyarn testを実行すれば、greenの「PASS」が表示され、動作していることがわかるはずです。

3. babelをrescueする

最初のテストが動くようになったので、一歩進めてVueコンポーネントをテストしてみましょう。

最初にやってみるのは、たいていspec/javascript/の下にファイルを作成してmy_component.spec.jsのような名前を付けることでしょう。続いて次のようにimportステートメントで自分のコンポーネントをspecにインポートしてみましょう。

  import MyComponent from '../../app/javascript/my_component.vue';

これをやってみた方は、そのままyarn testでテストを実行してみてください。SyntaxError: Unexpected token importエラーが出力されます。

ここでの問題は、importがECMAScript 6の一部である点です。つまりBabelなどのトランスパイラの助けが必要になるということです。

動くようにするには、yarn add --dev babel-jest babel-preset-es2015で2つのパッケージをインストールし、.babelrcファイルにes2015プリセットを追加する必要があります。

{
  "presets": ["es2015",
    ["env", {
          ...

さらに一歩進めてみたい方は、moduleDirectoriespackage.jsonに追加すると、モジュールへのフルパスを入力しなくても済むようになります。

"jest": {
  ...
  "moduleDirectories": [
    "node_modules",
    "app/javascript"
  ]
}

これで、先ほどのパスを簡単にできます。

  import MyComponent from '../../app/javascript/my_component.vue';

上のパスは以下のように書けます。

  import MyComponent from 'my_component.vue';

4. Vueが見つからない

ここまでの手順をすべて行った場合、yarn testでテストを実行するとまたしてもSyntaxErrorが表示されます。これは、コンポーネントのimportは成功したものの、.vueファイルフォーマットを理解できていないためです。

幸い、この辺りの面倒を見てくれるvue-jestを使えます。早速yarn add --dev vue-jestを実行してvue-jestをインストールし、READMEの指示に沿ってmoduleFileExtensionstransformmapCoverageを追加します。追加後のpackage.jsonは次のような感じになるはずです。

"jest": {
  ...
  "moduleFileExtensions": [
    "js",
    "json",
    "vue"
  ],
  "transform": {
    "^.+\\.js$": "<rootDir>/node_modules/babel-jest",
    ".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
  },
  "mapCoverage": true
}

moduleFileExtensionsを使うと、単一のファイルコンポーネントのimport.vue拡張子が不要になります。

  import MyComponent from 'my_component.vue';

上のパスは、以下のように書き換えられます。

  import MyComponent from 'my_component';.

これで、importをシームレスに使えるようになりました。

transformセクションに記述されたルールでは、テストするファイルの変換を担当するパッケージを指定します。ここではすべての.vueファイルの扱いをvue-jestに任せたいので、これらのファイルはJestで扱われる前に純粋なJavaScriptに変換されます。

mapCoverageは、トランスフォーマーが生成するソースマップを使うために設定してあります。Jestはこのソースマップを用いて、カバレッジの試行や、レポート生成時や閾値チェック中に元のソースコードとのマッピングを行います。

最後に、Vue.js公式の単体テストユーティリティライブラリであるvue-test-utilsを追加しましょう。yarn add --dev @vue/test-utilsを実行するだけですぐ使えるようになります。

ついにVueコンポーネントのテストを書けるようになりました🎉。

クレジット

本記事は、Jest公式ドキュメントHow to setup JavaScript testing in Rails 5.1 with Webpacker and JestなどWeb上の多数のドキュメントから集めた情報を元に執筆いたしました。

関連記事

新しいRailsフロントエンド開発(1)Asset PipelineからWebpackへ(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。