I use webpack to develop a React component. Here is a simple version of it:
'use strict'; require('./MyComponent.less'); var React = require('react'); var MyComponent = React.createClass({ render() { return ( <div className="my-component"> Hello World </div> ); } }); module.exports = MyComponent;
Now, I would like to test this component using jest. Here is the relevant bit from my package.json
:
"scripts": { "test": "jest" }, "jest": { "rootDir": ".", "testDirectoryName": "tests", "scriptPreprocessor": "<rootDir>/node_modules/babel-jest", "unmockedModulePathPatterns": [ "react" ] }
When running npm test
, I get the following error:
SyntaxError: /Users/mishamoroshko/react-component/src/tests/MyComponent.js: /Users/mishamoroshko/react-component/src/MyComponent.js: /Users/mishamoroshko/react-component/src/MyComponent.less: Unexpected token ILLEGAL
Looks like webpack needs to process require('./MyComponent.less')
before jest can run the test.
I wonder if I need to use something like jest-webpack. If yes, is there a way to specify multiple scriptPreprocessor
s? (note that I already use babel-jest
)
Using with 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.
Jest actually ships with jsdom and the environment already configured. You can override it with the testEnvironment setting. If you need to set up more aspects of the environment though, you can use the setupTestFrameworkScriptFile setting to point to a file that executes before all of your tests run.
You can create your own mock in jest to prevent processing of css files. // __mocks__/styleMock. js module. exports = {};
Babel can be classified as a tool in the "JavaScript Compilers" category, while Webpack is grouped under "JS Build Tools / JS Task Runners".
I ended up with the following hack:
// package.json "jest": { "scriptPreprocessor": "<rootDir>/jest-script-preprocessor", ... } // jest-script-preprocessor.js var babelJest = require("babel-jest"); module.exports = { process: function(src, filename) { return babelJest.process(src, filename) .replace(/^require.*\.less.*;$/gm, ''); } };
But, I'm still wondering what is the right solution to this problem.
The cleanest solution I found for ignoring a required module is to use the moduleNameMapper config (works on the latest version 0.9.2)
The documentation is hard to follow. I hope the following will help.
Add moduleNameMapper key to your packages.json config. The key for an item should be a regex of the required string. Example with '.less' files:
"moduleNameMapper": { "^.*[.](less|LESS)$": "EmptyModule" },
Add a EmptyModule.js to your root folder:
/** * @providesModule EmptyModule */ module.exports = '';
The comment is important since the moduleNameMapper use EmptyModule as alias to this module (read more about providesModule).
Now each require reference that matches the regex will be replaced with an empty string.
If you use the moduleFileExtensions configuration with a 'js' file, then make sure you also add the EmptyModule to your 'unmockedModulePathPatterns'.
Here is the jest configuration I ended up with:
"jest": { "scriptPreprocessor": "<rootDir>/node_modules/babel-jest", "moduleFileExtensions": ["js", "json","jsx" ], "moduleNameMapper": { "^.*[.](jpg|JPG|gif|GIF|png|PNG|less|LESS|css|CSS)$": "EmptyModule" }, "preprocessorIgnorePatterns": [ "/node_modules/" ], "unmockedModulePathPatterns": [ "<rootDir>/node_modules/react", "<rootDir>/node_modules/react-dom", "<rootDir>/node_modules/react-addons-test-utils", "<rootDir>/EmptyModule.js" ] }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With