次のモジュールがあるとします:
var modulesReq = require.context('.', false, /\.js$/);
modulesReq.keys().forEach(function(module) {
modulesReq(module);
});
Jestはrequire.context
を知らないため文句を言います:
FAIL /foo/bar.spec.js (0s)
● Runtime Error
- TypeError: require.context is not a function
どうすればいいですか? setupTestFrameworkScriptFile
Jest構成を使用してみましたが、require
で行った変更をテストで確認できません。
私は同じ問題を抱えていたので、「解決策」を作成しました。
これは最善の選択ではないと確信しています。ここで回答したポイントによって、私はそれを使用するのをやめました:
https://github.com/facebookincubator/create-react-app/issues/517https://github.com/facebook/jest/issues/2298
しかし、本当に必要な場合は、呼び出すすべてのファイルに以下のポリフィルを含める必要があります(テストファイル自体ではなく、require
はNode環境)。
// This condition actually should detect if it's an Node environment
if (typeof require.context === 'undefined') {
const fs = require('fs');
const path = require('path');
require.context = (base = '.', scanSubDirectories = false, regularExpression = /\.js$/) => {
const files = {};
function readDirectory(directory) {
fs.readdirSync(directory).forEach((file) => {
const fullPath = path.resolve(directory, file);
if (fs.statSync(fullPath).isDirectory()) {
if (scanSubDirectories) readDirectory(fullPath);
return;
}
if (!regularExpression.test(fullPath)) return;
files[fullPath] = true;
});
}
readDirectory(path.resolve(__dirname, base));
function Module(file) {
return require(file);
}
Module.keys = () => Object.keys(files);
return Module;
};
}
この関数を使用すると、require.context
呼び出しを変更する必要はありません。同じ動作で実行されます(webpackの場合は元の実装を使用し、Jest実行の場合はポリフィル機能)。
別のモジュールへの呼び出しを抽出します。
// src/js/lib/bundle-loader.js
/* istanbul ignore next */
module.exports = require.context('bundle-loader?lazy!../components/', false, /.*\.vue$/)
次から抽出したモジュールで新しいモジュールを使用します。
// src/js/lib/loader.js
const loadModule = require('lib/bundle-loader')
// ...
新しく作成されたバンドルローダーモジュールのモックを作成します。
// test/unit/specs/__mocks__/lib/bundle-loader.js
export default () => () => 'foobar'
テストでモックを使用します。
// test/unit/specs/lib/loader.spec.js
jest.mock('lib/bundle-loader')
import Loader from 'lib/loader'
describe('lib/loader', () => {
describe('Loader', () => {
it('should load', () => {
const loader = new Loader('[data-module]')
expect(loader).toBeInstanceOf(Loader)
})
})
})
Babelを使用している場合は、 babel-plugin-require-context-hook をご覧ください。 Storybookの構成手順は Storyshots | Configure JestがWebpackのrequire.context() で機能するようになっていますが、Storyshots/Storybook固有のものではありません。
要約すると:
プラグインをインストールします。
yarn add babel-plugin-require-context-hook --dev
次の内容のファイル.jest/register-context.js
を作成します。
import registerRequireContextHook from 'babel-plugin-require-context-hook/register';
registerRequireContextHook();
Jestを構成します(ファイルは、Jest構成の保管場所によって異なります(例:package.json
):
setupFiles: ['<rootDir>/.jest/register-context.js']
プラグインを.babelrc
に追加します
{
"presets": ["..."],
"plugins": ["..."],
"env": {
"test": {
"plugins": ["require-context-hook"]
}
}
}
または、babel.config.js
に追加します:
module.exports = function(api) {
api.cache(true)
const presets = [...]
const plugins = [...]
if (process.env.ENV_NODE === "test") {
plugins.Push("require-context-hook")
}
return {
presets,
plugins
}
}
babel.config.js
ではなく.babelrc
を使用すると問題が発生する可能性があることに注意してください。たとえば、require-context-hook
でbabel.config.js
プラグインを定義すると、次のことがわかりました。
jest --coverage
はそれを拾いませんでした(おそらく、イスタンブールはBabel 7に追いついていませんか?)。いずれの場合も、.babelrc
構成で問題ありませんでした。
Edmundo Rodrigues's answer に関するコメント
このbabel-plugin-require-context-hook
プラグインは、ここでEdmundo Rodriguesの答えに似たコードを使用します。エドムンドの小道具!プラグインはBabelプラグインとして実装されているため、静的分析の問題を回避できます。例えばEdmundoのソリューションにより、Webpackは次のように警告します。
Critical dependency: require function is used in a way in which dependencies cannot be statically extracted
警告にもかかわらず、EdmundoのソリューションはBabelに依存していないため、最も堅牢です。
インストール中
babel-plugin-transform-require-context
.babelrcにプラグインを追加してプラグインを追加すると、問題が解決しました。こちらのドキュメントを参照してください: https://www.npmjs.com/package/babel-plugin-transform-require-context
このためのシンプルなソリューション
ただやる
var modulesReq = require.context && require.context('.', false, /\.js$/);
if(modulesReq) {
modulesReq.keys().forEach(function(module) {
modulesReq(module);
});
}
だから、ここでrequire.contextが定義されている場合に追加のチェックを追加してから、実行するだけで文句を言わない