web-dev-qa-db-fra.com

Comment puis-je simuler le require.context de Webpack dans Jest?

Supposons que j'ai le module suivant:

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

Jest se plaint parce qu'il ne sait pas à propos de require.context:

 FAIL  /foo/bar.spec.js (0s)
● Runtime Error
  - TypeError: require.context is not a function

Comment puis-je m'en moquer? J'ai essayé d'utiliser la configuration setupTestFrameworkScriptFile Jest, mais les tests ne détectent aucune modification apportée dans require.

20
borges

J'ai eu le même problème, alors j'ai fait une «solution».

Je suis à peu près sûr que ce n'est pas le meilleur choix. J'ai fini par cesser de l'utiliser, par les points répondus ici:

https://github.com/facebookincubator/create-react-app/issues/517https://github.com/facebook/jest/issues/2298

Mais si vous en avez vraiment besoin, vous devez inclure le polyfill ci-dessous dans chaque fichier que vous appelez (pas dans le fichier de test lui-même, car la variable require ne sera pas remplacée dans un environnement de noeud).

// 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;
  };
}

Avec cette fonction, vous n’avez pas besoin de changer d’appel require.context, il s’exécutera avec le même comportement qu’il le ferait (si c’est sur Webpack, il utilisera simplement l’implémentation originale, et s’il s’agit de JF, avec la fonction polyfill) .

16
Edmundo Rodrigues

Extrayez l'appel dans un module séparé:

// src/js/lib/bundle-loader.js
/* istanbul ignore next */
module.exports = require.context('bundle-loader?lazy!../components/', false, /.*\.vue$/)

Utilisez le nouveau module dans le module d'où vous l'avez extrait:

// src/js/lib/loader.js
const loadModule = require('lib/bundle-loader')
// ...

Créez une maquette pour le module de chargeur de paquet nouvellement créé:

// test/unit/specs/__mocks__/lib/bundle-loader.js
export default () => () => 'foobar'

Utilisez la maquette dans votre test:

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

L'installation 

babel-plugin-transform-require-context

le package et l’ajout du plugin dans le fichier .babelrc ont résolu le problème pour moi . Consultez la documentation ici: https://www.npmjs.com/package/babel-plugin-transform-require-context

0
Rahul Akurati

Solution Simpleset pour cette

Juste faire 

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

}

Donc ici, j'ai ajouté une vérification supplémentaire si require.context est défini, alors seulement exécuter

0
Aditya kumar

Si vous utilisez Babel, regardez babel-plugin-require-context-hook . Les instructions de configuration de Storybook sont disponibles sur Storyshots | Configurez Jest pour qu'il fonctionne avec require.context () de Webpack, mais ils ne sont pas spécifiques à Storyshots/Storybook.

Pour résumer:

Installez le plugin.

yarn add babel-plugin-require-context-hook --dev

Créez un fichier .jest/register-context.js avec le contenu suivant:

import registerRequireContextHook from 'babel-plugin-require-context-hook/register';
registerRequireContextHook();

Configurez Jest (le fichier dépend de l'emplacement où vous stockez votre configuration Jest, par exemple package.json):

setupFiles: ['<rootDir>/.jest/register-context.js']

Ajouter le plugin à .babelrc

{
  "presets": ["..."],
  "plugins": ["..."],
  "env": {
    "test": {
      "plugins": ["require-context-hook"]
    }
  }
}

Sinon, ajoutez-le à 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
  }
}

Il peut être intéressant de noter que l'utilisation de babel.config.js au lieu de .babelrc peut être à l'origine de problèmes. Par exemple, j'ai constaté que lorsque j'ai défini le plugin require-context-hook dans babel.config.js:

  • Jest 22 ne l'a pas ramassé;
  • Jest 23 l'a ramassé; mais
  • jest --coverage ne l'a pas détecté (peut-être qu'Istanbul n'est pas à la hauteur de Babel 7?).

Dans tous les cas, une configuration .babelrc était correcte.


Remarques sur Réponse d'Edmundo Rodrigues

Ce plugin babel-plugin-require-context-hook utilise un code similaire à la réponse d'Edmundo Rodrigues ici. Des accessoires à Edmundo! Le plugin étant implémenté en tant que plugin Babel, il évite les problèmes d'analyse statique. par exemple. Avec la solution d'Edmundo, Webpack met en garde:

Critical dependency: require function is used in a way in which dependencies cannot be statically extracted

Malgré les avertissements, la solution d'Edmundo est la plus robuste car elle ne dépend pas de Babel.

0
thompsonsj