Using with webpack
Jest может использоваться в проектах, использующих webpack для управления активами, стилями и компиляцией. webpack does offer some unique challenges over other tools because it integrates directly with your application to allow managing stylesheets, assets like images and fonts, along with the expansive ecosystem of compile-to-JavaScript languages and tools.
Webpack пример #
Давйте начнем с привычной конфигурации webpack и адаптируем ее для использования с Jest.
// webpack.config.js module.exports = { module: { loaders: [ {exclude: ['node_modules'], loader: 'babel', test: /\.jsx?$/}, {loader: 'style-loader!css-loader', test: /\.css$/}, {loader: 'url-loader', test: /\.gif$/}, {loader: 'file-loader', test: /\.(ttf|eot|svg)$/}, ], }, 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
. Трансформации кода осуществляемые другими средствами могут быть обработаны при помощи опции transform
Jest.
Обработка статических активов #
Далее, настроим Jest для корректной обработки активов стилей и изображений. Обычно эти файлы не особо полезны в тестах, так что мы можем безопасно их имитировать. However, if you are using CSS Modules then it's better to mock a proxy for your className lookups.
// package.json { "jest": { "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:
// __mocks__/styleMock.js module.exports = {};
// __mocks__/fileMock.js module.exports = 'test-file-stub';
Мокинг CSS модулей #
Можно использовать ES6 Proxy для имитации CSS модулей:
npm install --save-dev identity-obj-proxy
Тогда доступ к className в объектах стилей будет возвращаться как есть (т.е. styles.foobar === 'foobar'
). Это довольно удобно при тестировании с использованием снимков в React.
// package.json (for CSS Modules) { "jest": { "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" } } }
Обратите внимание, что Proxy включен по умолчанию в Node версии 6. Если вы еще не используете Node версии 6, убедитесь, что вы вызываете Jest с помощью
node --harmony_proxies node_modules/.bin/jest
.
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:
// fileTransformer.js const path = require('path'); module.exports = { process(src, filename, config, options) { return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';'; }, };
// package.json (for custom transformers and CSS Modules) { "jest": { "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 конфигурация.
Note: if you are using babel-jest with additional code preprocessors, you have to explicitly define babel-jest as a transformer for your JavaScript code to map .js
files to the babel-jest module.
"transform": { "^.+\\.js$": "babel-jest", "^.+\\.css$": "custom-transformer", ... }
Конфигурация Jest для поиска наших файлов #
Now that Jest knows how to process our files, we need to tell it how to find them. For webpack's modulesDirectories
, and extensions
options there are direct analogs in Jest's moduleDirectories
and moduleFileExtensions
options.
// package.json { "jest": { "moduleFileExtensions": ["js", "jsx"], "moduleDirectories": ["node_modules", "bower_components", "shared"], "moduleNameMapper": { "\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js", "\\.(gif|ttf|eot|svg)$": "<rootDir>/__mocks__/fileMock.js" } } }
Note: <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 webpack's resolve.root
option functions like setting the NODE_PATH
env variable, which you can set, or make use of the modulePaths
option.
// package.json { "jest": { "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 just have the webpack alias
left to handle. For that we can make use of the moduleNameMapper
option again.
// package.json { "jest": { "modulePaths": [ "/shared/vendor/modules" ], "moduleFileExtensions": ["js", "jsx"], "moduleDirectories": ["node_modules", "bower_components", "shared"], "moduleNameMapper": { "^react(.*)$": "<rootDir>/vendor/react-master$1", "^config$": "<rootDir>/configs/app-config.js", "\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js", "\\.(gif|ttf|eot|svg)$": "<rootDir>/__mocks__/fileMock.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.
Note: For more complex webpack configurations, you may also want to investigate projects such as: babel-plugin-webpack-loaders.
Использование с Webpack 2 #
webpack 2 offers native support for ES modules. However, Jest runs in Node, and thus requires ES modules to be transpiled to CommonJS modules. As such, if you are using webpack 2, you most likely will want to configure Babel to transpile ES modules to CommonJS modules only in the test
environment.
// .babelrc { "presets": [ ["es2015", {"modules": false}] ], "env": { "test": { "plugins": ["transform-es2015-modules-commonjs"] } } }
Note: Jest caches files to speed up test execution. If you updated .babelrc and Jest is still not working, try running Jest with
--no-cache
.
If you use dynamic imports (import('some-file.js').then(module => ...)
), you need to enable the dynamic-import-node
plugin.
// .babelrc { "presets": [ ["es2015", {"modules": false}] ], "plugins": ["syntax-dynamic-import"], "env": { "test": { "plugins": ["dynamic-import-node"] } } }