Webpacker環境へのJest + Power-Assertの導入が本当に簡単だった話

まとめ

  • Jest は確かに設定減ってる。でも zero config は言いすぎ1
  • Webpack の設定をテスト用に書き足す必要はなかったが、Jest 用の transform を追加するが必要あり、Webpack の再発明感はある2
  • Power-Assert が Babel に対応してて設定が楽になってきてる
  • Jest よりも Webpacker のクセが強い(これはまた別に書く)

背景

以前 Rails 4.2にWebpacker入れた - あーありがち(2018-01-19) で Webpacker を導入したわけだが、やはりテストがなくてつらかったので3、今回はテストの環境を Jest で作った話。

実は最近も Nuxtを利用したVueアプリのユニットテストに関するメモ - あーありがち(2018-04-24) で似たような話をやっているんだけど、その時は

  • mocha-webpack
  • テスト環境用のwebpack.config.js
  • jsdom-global
  • power-assert

をちまちまと準備していった。勉強にはなったけど、またアレやるのはちょっとイヤだなと思っていたので、最近評判のよい Jest を試してみることにした。

Jest · Delightful JavaScript Testing

参考までに今回動かしたのはそれぞれ以下のバージョン。

  • jest 23.2
  • power-assert 1.6.0
  • @vue/test-utils 1.0.0-beta.20
  • babel-jest 23.2.0
  • vue-jest 2.6.0

まず最小限で動かす

yarn add –dev jest とか npm install –save-dev jest とかでインストール。

で、 package.json に

"test": "jest --config <config-path>"

を書く。Rails + RSpec 環境なので、場所は

spec/javascripts/jest.conf.js

がよいだろう。

で、jest.conf.js の中身だが、基本的には

module.exports = {
  rootDir: ".",
  modulePaths: <webpacker-path>
  ..

で動く。

rootDir ( または roots ) や modulePaths はこの jest.conf.js からの相対パスで指定するようだ。conf を独立させずに package.json の中に書く場合は package.json からの相対パスになる。

これでテストコード側からは modulePaths で指定したパス以下のプロダクトコードを気軽に読み込むことができる。はずだ。ただし Jest は Node.js で動いており、2018-07 時点では当たり前だがそのままでは import は使えないので、Babel の登場を待つ必要がある。

Mochaの追加とjsdom-globalの設定は不要

自分が Mocha にこだわっていたのは Jasmine では power-assert を使うのが難しいと思っていたためだったのだが、Jest では Jasmine2 + jsdom-global の環境が最初からできあがっており、またこの状態で describe / it 形式でテストコードは書けるので、ここは本当によかった。いきなり

describe('', () => {
  it('', () => {
    console.log('foo')
  })
})

が動く。

jsdom-global はここまでの流れでは関係ないが、Vue component のテストを書く際に jsdom 関係の設定は一切不要だった。

余談だけど Jest では assert を呼ばなくても true が返ってなければエラーになるっぽい。こういうの、いいな。

やはりimportは解釈できないのでtransformの追加が必要

Vue.jsでアプリを書いている場合、基本的にはこれでいける。

transform: {
  "\\.js$": "babel-jest",
  "\\.vue$": "vue-jest",

もちろん babel-jest, vue-jest はインストールしておくこと。

この辺が非常に Webpack の再発明っぽくてどうなんだと思のだが、babel-jest, vue-jest については特に設定は不要なので助かる4。babel-jest は Jest本家が、vue-jest は Vue本家がサポートしているので安心。

YAML でデータを食わせている場合にも yaml-jest を追加設定すればよいだけ。

以前は JavaScript のテストでは fixture をどうするのかが課題の一つだったが、イマドキはもうこれでよいような気がする。違う? 適当にテストデータを YAML で用意すればいいんじゃないかなぁ。

Webpacker環境独自の課題

ここまでは順調だが、Webpacker 環境の場合はまだ注意が必要。

まず、Webpacker の作った .babelrc の presets env が modules: false になっているので、babel-jest を設定しているにも関わらず import できない。そこでこれを消そうかと思うのだが、影響がよく分からないのと、ついでにやることがあるので、 .babelrc で

"env": {
  "test": {
    ..
  }
}

を用意して環境を切り替えることにする。いちばんシンプルには以下のようになる。

"env": {
  "test": {
    "presets": ["env"]
  }
}

Power-Assertの導入

実は Webpacker の課題を解決するのと同時に Power-Assert を使うために上では .babelrc で env を追加してある。

yarn add --dev power-assert babel-preset-power-assert

しておいて、先ほどの env.test の中に以下のように追加する。

"env": {
  "test": {
    "presets": ["env", "power-assert"]
  }
}

これでテストコードの中で

import assert from 'power-assert'

して使うことができる。

よーしこれでバンバンTDDできるってもんだ。

  1. jsdom-global は確かに zero config 

  2. でも出力しなくて済むので、Webpack と Jest は load と transform 周りを切り離すと本当はいいんだろうなぁ 

  3. どーして毎回こういう話になるのかというと、自分が新規案件をゼロから書く機会を奪われている(集中すると他に手が回らなくなって困る)ので、こういう話が増えるのです。とは言え今回は 2016年にやっていたことに比べればへなちょこ級に楽ちんです。 http://aligach.net/diary/20161228.html#p01 

  4. 特に vue-jest が Webpack にも Babel にも依存していなくてどちらにも何も設定しなくて済むのは助かる。Webpacker 側も無設定なので本当に助かる。 

More