Как я могу издеваться над Webpack require.context в Jest?
Предположим, что у меня есть следующий модуль:
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
.
Ответы
Ответ 1
У меня была такая же проблема, тогда я нашел "решение".
Я уверен, что это не лучший выбор. Я закончил тем, что прекратил использовать это, ответив на вопросы здесь:
https://github.com/facebookincubator/create-react-app/issues/517 https://github.com/facebook/jest/issues/2298
Но если вам это действительно нужно, вы должны включить приведенный ниже полифилл в каждый файл, который вы вызываете (не в сам файл тестов, потому что require
не будет переопределено глобально в среде Node).
// This condition actually should detect if it 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
, он будет выполняться с тем же поведением, что и при выполнении (если он используется в веб-пакете, он просто использует оригинальную реализацию, а если он находится внутри выполнения Jest - с полифиллом) функция).
Ответ 2
Извлеките вызов отдельному модулю:
// 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)
})
})
})
Ответ 3
Если вы используете Babel, посмотрите на babel-plugin-require-context-hook. Инструкции по настройке для Storybook доступны на Storyshots | Настройте 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
:
- Шут 22 не поднял это;
- Шут 23 поднял это; но
-
jest --coverage
не подняла его (возможно, Стамбул не в ногу с Бабелем 7?).
Во всех случаях конфигурация .babelrc
была в порядке.
Замечания по Эдмундо Родригесу ответ
Этот babel-plugin-require-context-hook
использует код, подобный ответу Эдмундо Родригеса здесь. Реквизит Эдмундо! Поскольку плагин реализован как плагин Babel, он позволяет избежать проблем статического анализа. Например, с помощью решения Edmundo Webpack предупреждает:
Critical dependency: require function is used in a way in which dependencies cannot be statically extracted
Несмотря на предупреждения, решение Edmundo является наиболее надежным, поскольку оно не зависит от Babel.
Ответ 4
Установка
столпотворение-плагин-преобразование-требуют контексты
пакет и добавление плагина в .babelrc решили проблему для меня. Обратитесь к документации здесь: https://www.npmjs.com/package/babel-plugin-transform-require-context