webpack を使用してReactコンポーネントを開発します。以下にその簡単なバージョンを示します。
_'use strict';
require('./MyComponent.less');
var React = require('react');
var MyComponent = React.createClass({
render() {
return (
<div className="my-component">
Hello World
</div>
);
}
});
module.exports = MyComponent;
_
次に、 jest を使用してこのコンポーネントをテストします。 _package.json
_からの関連ビットは次のとおりです。
_"scripts": {
"test": "jest"
},
"jest": {
"rootDir": ".",
"testDirectoryName": "tests",
"scriptPreprocessor": "<rootDir>/node_modules/babel-jest",
"unmockedModulePathPatterns": [
"react"
]
}
_
_npm test
_を実行すると、次のエラーが表示されます。
SyntaxError:/Users/mishamoroshko/react-component/src/tests/MyComponent.js:/Users/mishamoroshko/react-component/src/MyComponent.js:/Users/mishamoroshko/react-component/src/MyComponent.less:予期しないトークン違法
Jestがテストを実行する前に、webpackはrequire('./MyComponent.less')
を処理する必要があるようです。
jest-webpack のようなものを使用する必要があるのだろうか。はいの場合、複数のscriptPreprocessor
sを指定する方法はありますか? (私はすでに_babel-jest
_を使用していることに注意してください)
必要なモジュールを無視するために見つけた最もクリーンなソリューションは、 moduleNameMapper config を使用することです(最新バージョン0.9.2で動作します)
ドキュメントを理解するのは困難です。以下が役立つことを願っています。
Packages.json構成にmoduleNameMapperキーを追加します。アイテムのキーは、必要な文字列の正規表現である必要があります。 「.less」ファイルの例:
"moduleNameMapper": { "^.*[.](less|LESS)$": "EmptyModule" },
EmptyModule.jsをルートフォルダーに追加します。
/**
* @providesModule EmptyModule
*/
module.exports = '';
ModuleNameMapperはこのモジュールのエイリアスとしてEmptyModuleを使用するため、コメントは重要です( providesModuleの詳細 )。
正規表現に一致する必要な参照はそれぞれ空の文字列に置き換えられます。
「js」ファイルでmoduleFileExtensions構成を使用する場合は、「unmockedModulePathPatterns」にEmptyModuleも追加してください。
これが私が結んだjest構成です:
"jest": {
"scriptPreprocessor": "<rootDir>/node_modules/babel-jest",
"moduleFileExtensions": ["js", "json","jsx" ],
"moduleNameMapper": {
"^.*[.](jpg|JPG|gif|GIF|png|PNG|less|LESS|css|CSS)$": "EmptyModule"
},
"preprocessorIgnorePatterns": [ "/node_modules/" ],
"unmockedModulePathPatterns": [
"<rootDir>/node_modules/react",
"<rootDir>/node_modules/react-dom",
"<rootDir>/node_modules/react-addons-test-utils",
"<rootDir>/EmptyModule.js"
]
}
私は次のハックになりました:
// package.json
"jest": {
"scriptPreprocessor": "<rootDir>/jest-script-preprocessor",
...
}
// jest-script-preprocessor.js
var babelJest = require("babel-jest");
module.exports = {
process: function(src, filename) {
return babelJest.process(src, filename)
.replace(/^require.*\.less.*;$/gm, '');
}
};
しかし、私はまだこの問題の正しい解決策は何だろうと思っています。
JestのmoduleNameMapper
構成を使用すると、さらに簡単になることがわかりました。
// package.json
"jest": {
"moduleNameMapper": {
"^.+\\.scss$": "<rootDir>/scripts/mocks/style-mock.js"
}
}
// style-mock.js
module.exports = {};
詳細については、Jestの チュートリアルページ を参照してください。
私は最近 Jestpack をリリースしました。最初にWebpackを使用してテストファイルをビルドするため、カスタムモジュールの解決/ローダー/プラグインなどが機能するだけで、JavaScriptになります。次に、Webpackモジュールランタイムを理解するJestのカスタムモジュールローダーを提供します。
Jest docs から:
// in terminal, add new dependency: identity-obj-proxy
npm install --save-dev identity-obj-proxy
// package.json (for CSS Modules)
{
"jest": {
"moduleNameMapper": {
"\\.(css|less)$": "identity-obj-proxy"
}
}
}
上記のスニペットはすべての.less
ファイルを新しい依存関係に追加identity-obj-proxy
は、呼び出されたときにクラス名を含む文字列を返します。 'styleName'
ために styles.styleName
。
ハッカーの少ない解決策は、プリプロセッサをjavascriptファイルに一致するファイル名を条件にラップすることだと思います。
if (filename.match(/\.jsx?$/)) {
return babelJest.process(src, filename);
} else {
return '';
}
これは、require行で明示的に拡張子を設定せず、ソースで正規表現の置換を必要としない場合でも機能します。
私はそのようなパターンで同様の問題を経験しました
_import React, { PropTypes, Component } from 'react';
import styles from './ContactPage.css';
import withStyles from '../../decorators/withStyles';
@withStyles(styles)
class ContactPage extends Component {
_
Jestを実行するには、2つの問題があります。
.css
_のインポート@withStyles
_(TypeError: <...> (0 , _appDecoratorsWithStyles2.default)(...) is not a function
)最初の1つは、スクリプトプリプロセッサで_.css
_自体をモックすることで解決されました。
2番目のは、unmockedModulePathPatterns
を使用して自動モックからデコレータを除外することで解決しました。
_module.exports = {
process: function (src, filename) {
...
if (filename.match(/\.css$/)) src = '';
...
babel.transform(src, ...
}
}
_
https://github.com/babel/babel-jest/blob/77a24a71ae2291af64f51a237b2a9146fa38b136/index.js に基づく例
注:jestプリプロセッサを使用する場合は、キャッシュを消去する必要があります。
_$ rm node_modules/jest-cli/.haste_cache -r
_
CSSファイルにも同様の問題がありました。前述したように、 jest-webpack はこの問題を解決します。モックやモジュールマッパーを使用する必要もありません。私たちにとっては、npm testコマンドをjest
からjest-webpack
に置き換えたところ、うまくいきました。
Babelを使用している場合は、 https://github.com/Shyp/babel-plugin-import-noop のようなものを使用してbabel変換中に不要なインポートを削除し、.babelrc
test
プラグインを使用するenv。
{
"env": {
"development": {
...
},
"test": {
"presets": [ ... ],
"plugins": [
["import-noop", {
"extensions": ["scss", "css"]
}]
]
}
}
}
Webpackは優れたツールですが、Jest単体テストでその動作をテストする必要はありません。単体テストを実行する前にwebpackビルドを追加しても、プロセスは遅くなります。 教科書の答えは、"moduleNameMapper"
オプション
https://facebook.github.io/jest/docs/webpack.html#handling-static-assets
Mishaの対応からインスピレーションを得て、私はこの問題を解決するNPMパッケージを作成し、同時に出会ったいくつかのシナリオも処理しました。
これが次の人を数時間節約できることを願っています。