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
.
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) .
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)
})
})
})
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
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
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 --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.