web-dev-qa-db-ja.com

JestでWebpackのrequire.contextをモックするにはどうすればよいですか?

次のモジュールがあるとします:

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で行った変更をテストで確認できません。

27
borges

私は同じ問題を抱えていたので、「解決策」を作成しました。

これは最善の選択ではないと確信しています。ここで回答したポイントによって、私はそれを使用するのをやめました:

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実行の場合はポリフィル機能)。

19

別のモジュールへの呼び出しを抽出します。

// 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)
    })
  })
})
14
borisdiakur

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-hookbabel.config.jsプラグインを定義すると、次のことがわかりました。

  • Jest 22はそれを拾いませんでした。
  • Jest 23が拾い上げました。だが
  • 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に依存していないため、最も堅牢です。

8
thompsonsj

インストール中

babel-plugin-transform-require-context

.babelrcにプラグインを追加してプラグインを追加すると、問題が解決しました。こちらのドキュメントを参照してください: https://www.npmjs.com/package/babel-plugin-transform-require-context

2
Rahul Akurati

このためのシンプルなソリューション

ただやる

var modulesReq = require.context && require.context('.', false, /\.js$/);
if(modulesReq) {
modulesReq.keys().forEach(function(module) {
  modulesReq(module);
});

}

だから、ここでrequire.contextが定義されている場合に追加のチェックを追加してから、実行するだけで文句を言わない

0
Aditya kumar