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を使用します:
yarn add --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
設定オプションでアセットの変換方法を指定できます。 例えばファイルのベースネームに変換したい場合(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
ファイルが格納されているディレクトリになります。
Similarly, webpack's resolve.root
option functions like setting the NODE_PATH
env variable, which you can set, or make use of the modulePaths
option.
// 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"
}
}
}
And finally, we have to handle the webpack alias
. For that, we can make use of the moduleNameMapper
option again.
// 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",
"^react(.*)$": "<rootDir>/vendor/react-master$1",
"^config$": "<rootDir>/configs/app-config.js"
}
}
}
以上です! webpackは複雑で柔軟なツールなので、適用するアプリケーションが必要とすることに対応するためにいくらか調整をしなければならないでしょう。 幸いにもほとんどのプロジェクトでは、Jestはwebpackの設定を調整するよりも十分な柔軟性を持っているはずです。
注意: より複雑なwebpackの構成については、次のようなプロジェクトも参考にして下さい: babel-plugin-webpack-loaders
webpack2と使用する場合
webpack2はESモジュールのネイティブサポートを提供しています。 しかし、JestはNode上で動作するため、ESモジュールはCommonJSモジュールにトランスパイルされている必要があります。 Webpack 2を利用する場合は、 test
環境でのみESモジュールをCommonJSモジュールに変換させたいと考えるでしょう。
// .babelrc
{
"presets": [["env", {"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": [["env", {"modules": false}]],
"plugins": ["syntax-dynamic-import"],
"env": {
"test": {
"plugins": ["dynamic-import-node"]
}
}
}
Jest を Webpack、React, Redux、および Node と使用する場合の例については、こちらで確認できます。