Using with webpack
Jestは webpackでアセットやスタイル、コンパイル作業を管理するプロジェクトで使用できます。 webpackはJavaScript代替言語とツールの拡張的なエコシステムに加えて、スタイルシート、画像やフォントのようなアセットの管理を可能にするためにアプリケーションに直接結合するので、他の同様のツールと比べて実にユニークで挑戦的な機能を提供しています。
webpackの設定例 #
一般的な種類のwebpackの設定ファイルから始めて、Jestのセットアップに変換してみましょう。
// webpack.config.js module.exports = { module: { loaders: [ {exclude: ['node_modules'], loader: 'babel', test: /\.jsx?$/}, {loader: 'style-loader!css-loader', test: /\.css$/}, {loader: 'url-loader', test: /\.gif$/}, {loader: 'file-loader', test: /\.(ttf|eot|svg)$/}, ], }, resolve: { alias: { config$: './configs/app-config.js', react: './vendor/react-master', }, extensions: ['', 'js', 'jsx'], modules: [ 'node_modules', 'bower_components', 'shared', '/shared/vendor/modules', ], }, };
Babelで変換されたJavaScriptファイルがある場合は、 babel-jest
プラグインをインストールすることでBabelへのサポートを有効にすることができます。 Babel以外のJavaScriptトランスパイラはJestの transform
設定オプションで管理できます。
静的アセットの管理 #
次は、スタイルシートや画像などのアセットを簡潔に管理できるようにJestを設定しましょう。 通常、これらのファイルはテストでは特に扱いづらいので、問題がないようにモックします。 しかし、CSSモジュールを利用している場合はクラス名参照のためのプロキシをモックした方が良いでしょう。
// package.json { "jest": { "moduleNameMapper": { "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js", "\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js" } } }
そしてモックファイル自身は次のようになります:
// __mocks__/styleMock.js module.exports = {};
// __mocks__/fileMock.js module.exports = 'test-file-stub';
CSSモジュールのモック #
CSS ModulesをモックするにはES6 Proxyを使用します:
npm install --save-dev identity-obj-proxy
スタイルオブジェクトの全てのクラス名参照はそのまま返るようになります(つまりstyles.foobar === 'foobar'
となります)。 この挙動はReactのSnapshotのテストにとても便利です。
// package.json (for CSS Modules) { "jest": { "moduleNameMapper": { "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js", "\\.(css|less)$": "identity-obj-proxy" } } }
Node6ではプロキシはデフォルトで有効であることに注意してください。Node6以前のバージョンを使用している場合は、Jestを
node --harmony_proxies node_modules/.bin/jest
コマンドで起動するようにして下さい。
moduleNameMapper
が目的にそぐわない場合は、Jestのtransform
設定オプションでアセットの変換方法を指定できます。 例えばファイルのbasename(require('logo.jpg');
なら 'logo'
となるような)を返させたい場合は、次のように記述できます:
// fileTransformer.js const path = require('path'); module.exports = { process(src, filename, config, options) { return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';'; }, };
// package.json (for custom transformers and CSS Modules) { "jest": { "moduleNameMapper": { "\\.(css|less)$": "identity-obj-proxy" }, "transform": { "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/fileTransformer.js" } } }
Jestがスタイルシートや画像の拡張子のあるファイルを無視して、代わりにモックファイルを読み込むように設定しました。 webpackの設定で扱うファイルタイプを照合する正規表現は調整することができます。
注意: babel-jestを追加のコードプリプロセッサと使用する場合、 .js
拡張子ファイルを babel-jestモジュールに対応付けるため、明示的にbabel-jestをJavaScriptコードのトランスパイラとして定義する必要があります。
"transform": { "^.+\\.js$": "babel-jest", "^.+\\.css$": "custom-transformer", ... }
ソースファイルを探索できるようにJestを設定する #
ここまででJestはファイルの処理方法を理解したので、次はJestにファイルを 見つける方法を教えてやる必要があります。 webpackのmodulesDirectories
、そして extensions
オプションはJestの moduleDirectories
や moduleFileExtensions
と直接的な類似性があります。
// package.json { "jest": { "moduleFileExtensions": ["js", "jsx"], "moduleDirectories": ["node_modules", "bower_components", "shared"], "moduleNameMapper": { "\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js", "\\.(gif|ttf|eot|svg)$": "<rootDir>/__mocks__/fileMock.js" } } }
注意: <rootdir> (何らかのパラメータ名?) はJestによりプロジェクトのルートディレクトリに置き換えられます。 設定で特別に
rootDir
オプションを指定しない限り、大抵の場合はpackage.jsonファイルが格納されているディレクトリになります。
webpackの resolve.root
オプションもmodulePaths
オプションによってNODE_PATH
環境変数を設定することと同様のことができます。
// package.json { "jest": { "modulePaths": [ "/shared/vendor/modules" ], "moduleFileExtensions": ["js", "jsx"], "moduleDirectories": ["node_modules", "bower_components", "shared"], "moduleNameMapper": { "\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js", "\\.(gif|ttf|eot|svg)$": "<rootDir>/__mocks__/fileMock.js" } } }
最後に取り扱うものとしてwebpackの alias
だけが残っています。それには moduleNameMapper
を再び利用します。
// package.json { "jest": { "modulePaths": [ "/shared/vendor/modules" ], "moduleFileExtensions": ["js", "jsx"], "moduleDirectories": ["node_modules", "bower_components", "shared"], "moduleNameMapper": { "^react(.*)$": "<rootDir>/vendor/react-master$1", "^config$": "<rootDir>/configs/app-config.js", "\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js", "\\.(gif|ttf|eot|svg)$": "<rootDir>/__mocks__/fileMock.js" } } }
以上です! webpackは複雑で柔軟なツールなので、適用するアプリケーションが必要とすることに対応するためにいくらか調整をしなければならないでしょう。 幸いにもほとんどのプロジェクトでは、Jestはwebpackの設定を調整するよりも十分な柔軟性を持っているはずです。
注意: より複雑なwebpackの構成については、次のようなプロジェクトも参考にして下さい: babel-plugin-webpack-loaders
webpack2と使用する場合 #
webpack2はESモジュールのネイティブサポートを提供しています。 しかし、JestはNode上で動作するので、ESモジュールはCommonJSモジュールにトランスパイルされている必要があります。 このようにwebpackを利用している場合は、Babelにtest
環境でのみESモジュールをCommonJSモジュールに変換させたいと考えるでしょう。
// .babelrc { "presets": [ ["es2015", {"modules": false}] ], "env": { "test": { "plugins": ["transform-es2015-modules-commonjs"] } } }
注意: Jestはテストを高速化するためキャッシュ機能を持っています。 .babelrcを変更後にJestがうまく動作しない場合は、Jestを
--no-cache
オプションを付けて実行してください。
動的インポートを使用する場合 (import('some-file.js').then (module = >...)
など)、 dynamic-import-node
プラグインを有効にする必要があります。
// .babelrc { "presets": [ ["es2015", {"modules": false}] ], "plugins": ["syntax-dynamic-import"], "env": { "test": { "plugins": ["dynamic-import-node"] } } }