Использование с Webpack
Jest может использоваться в проектах, использующих webpack для управления ресурсами, стилями и компиляцией. Webpack способен предложить некоторые уникальные возможности, по сравнению с другими инструментами, поскольку он объединяется непосредственно с вашим приложением, позволяя управлять таблицами стилей, дополнительными элементами, такими как изображения и шрифты, а также обширной экосистемой компилируемых в JavaScript языков и инструментов.
Webpack пример
Давйте начнем с привычной конфигурации webpack и адаптируем ее для использования с Jest.
module.exports = {
module: {
rules: [
{
test: /\.jsx?$/,
exclude: ['node_modules'],
use: ['babel-loader'],
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.gif$/,
type: 'asset/inline',
},
{
test: /\.(ttf|eot|svg)$/,
type: 'asset/resource',
},
],
},
resolve: {
alias: {
config$: './configs/app-config.js',
react: './vendor/react-master',
},
extensions: ['.js', '.jsx'],
modules: [
'node_modules',
'bower_components',
'shared',
'/shared/vendor/modules',
],
},
};
Если вы располагаете файлами, которые трансформируются Babel, вы можете включить поддержку Babel путем установки плагина babel-jest
. Non-Babel JavaScript transformations can be handled with Jest's transform
config option.
Обработка статических активов
Далее, настроим Jest для корректной обработки активов стилей и изображений. Обычно эти файлы не особо полезны в тестах, так что мы можем безопасно их имитировать. However, if you are using CSS Modules then it's better to mock a proxy for your className lookups.
module.exports = {
moduleNameMapper: {
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/__mocks__/fileMock.js',
'\\.(css|less)$': '<rootDir>/__mocks__/styleMock.js',
},
};
And the mock files themselves:
module.exports = {};
module.exports = 'test-file-stub';
Мокинг CSS модулей
М ожно использовать ES6 Proxy для имитации CSS модулей:
- npm
- Yarn
- pnpm
npm install --save-dev identity-obj-proxy
yarn add --dev identity-obj-proxy
pnpm add --save-dev identity-obj-proxy
Тогда доступ к className в объектах стилей будет возвращаться как есть (т.е. styles.foobar === 'foobar'
). Это довольно удобно при тестировании с использованием снимков в React.
module.exports = {
moduleNameMapper: {
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/__mocks__/fileMock.js',
'\\.(css|less)$': 'identity-obj-proxy',
},
};
If moduleNameMapper
cannot fulfill your requirements, you can use Jest's transform
config option to specify how assets are transformed. For example, a transformer that returns the basename of a file (such that require('logo.jpg');
returns 'logo'
) can be written as:
const path = require('path');
module.exports = {
process(sourceText, sourcePath, options) {
return {
code: `module.exports = ${JSON.stringify(path.basename(sourcePath))};`,
};
},
};
module.exports = {
moduleNameMapper: {
'\\.(css|less)$': 'identity-obj-proxy',
},
transform: {
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/fileTransformer.js',
},
};
Мы указали Jest на необходимость игнорировать файлы расширения которых совпадают с расширениями таблиц стилей и изображений, и на необходимость использовать имитационные файлы вместо них. Вы можете корректировать регулярное выражение так, чтобы оно совпадало с типами файлов, которые обрабатывает ваша webpack конфигурация.
Remember to include the default babel-jest
transformer explicitly, if you wish to use it alongside with additional code preprocessors:
"transform": {
"\\.[jt]sx?$": "babel-jest",
"\\.css$": "some-css-transformer",
}
Конфигурация Jest для поиска наших файлов
Now that Jest knows how to process our files, we need to tell it how to find them. For webpack's modules
, and extensions
options there are direct analogs in Jest's moduleDirectories
and moduleFileExtensions
options.
module.exports = {
moduleFileExtensions: ['js', 'jsx'],
moduleDirectories: ['node_modules', 'bower_components', 'shared'],
moduleNameMapper: {
'\\.(css|less)$': '<rootDir>/__mocks__/styleMock.js',
'\\.(gif|ttf|eot|svg)$': '<rootDir>/__mocks__/fileMock.js',
},
};
<rootDir>
is a special token that gets replaced by Jest with the root of your project. Most of the time this will be the folder where your package.json
is located unless you specify a custom rootDir
option in your configuration.
Similarly, Jest's counterpart for Webpack's resolve.roots
(an alternative to setting NODE_PATH
) is modulePaths
.
module.exports = {
modulePaths: ['/shared/vendor/modules'],
moduleFileExtensions: ['js', 'jsx'],
moduleDirectories: ['node_modules', 'bower_components', 'shared'],
moduleNameMapper: {
'\\.(css|less)$': '<rootDir>/__mocks__/styleMock.js',
'\\.(gif|ttf|eot|svg)$': '<rootDir>/__mocks__/fileMock.js',
},
};
And finally, we have to handle the webpack alias
. For that, we can make use of the moduleNameMapper
option again.
module.exports = {
modulePaths: ['/shared/vendor/modules'],
moduleFileExtensions: ['js', 'jsx'],
moduleDirectories: ['node_modules', 'bower_components', 'shared'],
moduleNameMapper: {
'\\.(css|less)$': '<rootDir>/__mocks__/styleMock.js',
'\\.(gif|ttf|eot|svg)$': '<rootDir>/__mocks__/fileMock.js',
'^react(.*)$': '<rootDir>/vendor/react-master$1',
'^config$': '<rootDir>/configs/app-config.js',
},
};
Вот и все! webpack is a complex and flexible tool, so you may have to make some adjustments to handle your specific application's needs. Luckily for most projects, Jest should be more than flexible enough to handle your webpack config.
For more complex webpack configurations, you may also want to investigate projects such as: babel-plugin-webpack-loaders.
Использование с Webpack
In addition to installing babel-jest
as described earlier, you'll need to add @babel/preset-env
like so:
- npm
- Yarn
- pnpm
npm install --save-dev @babel/preset-env
yarn add --dev @babel/preset-env
pnpm add --save-dev @babel/preset-env
Then, you'll want to configure Babel as follows:
{
"presets": ["@babel/preset-env"]
}
Jest caches files to speed up test execution. If you updated .babelrc
and Jest is not working as expected, try clearing the cache by running jest --clearCache
.
If you use dynamic imports (import('some-file.js').then(module => ...)
), you need to enable the dynamic-import-node
plugin.
{
"presets": [["env", {"modules": false}]],
"plugins": ["syntax-dynamic-import"],
"env": {
"test": {
"plugins": ["dynamic-import-node"]
}
}
}
For an example of how to use Jest with webpack with React, you can view one here.