How to Exclude CSS, Images, Anything from Unit Tests
Your app needs all those require
, but your unit tests may not.
When developing web applications, we deal with assets that our JavaScript tests don’t have to be aware of.
If using Webpack, which enables different imports in your JavaScript files, you’ve configured loaders that your test runner probably know nothing about. Therefore, that SVG image in your React component and the import
ed CSS will both be parsed like JavaScript in your tests. A lot of confusing errors will be thrown, of course.
So let’s learn to exclude anything your unit tests, from styles (CSS, Sass), images (PNG, SVG), to other specific imports (like SVG images as React components).
Hook your require()
calls
By intercepting require()
calls, you can make your testing framework ignore what you want to be ignored the way you want it to be ignored.
It’s also useful in isomorphic setups.
Return an empty module
It all comes to returning an empty module for unwanted imports. It looks like this:
module.exports = "";
Jest
For Jest, configure moduleNameMapper to return the empty module for specific extensions. Example:
"jest": {
"moduleNameMapper": {
"\\.(css|jpg|png)$": "<rootDir>/empty-module.js"
}
}
Other testing frameworks
require-hacker is an option for hooking require()
calls.
You can also use built-in compilers (like moduleNameMapper in Jest or Mocha compilers), or even only import ignore-styles into your testing framework (which is preconfigured).
I’ll stick to require-hacker and custom configuration because there’s more flexibility.
Get it from npm:
npm install require-hacker --save-dev
Configure
Create a JavaScript file and set custom handlers for specific extensions using require-hacker’s hook() method.
Assuming you want to ignore CSS and PNG files, always return an empty module for them:
import requireHacker from "require-hacker";
requireHacker.hook("png", () => 'module.exports = ""');
requireHacker.hook("css", () => 'module.exports = ""');
Because you’re smart, you’ll store all extensions in a variable and forEach
them, so there’s no need to repeat yourself. Example.
Import into your test runner
Let your favourite testing framework know about the require
hacking! Some examples, assuming a ignore-utils.js
file:
Mocha
Add to your mocha.opts, or use the --require
flag:
mocha --require ./ignore-utils
ava
Add to your package.json
:
"ava": {
"require": [
"./ignore-utils"
]
}
Now some files will be treated like shit in your JavaScript tests – which is AWESOME!
Bonus: React null component
You don’t need to load that boring SVG icon of a house to test that critical feature in a React component, right?
Right. In case you’re using svg-inline-loader, which transform your SVG files into React components, you cannot just return an empty module because your test case would be actually expecting a React component. Things will break. Annoying errors will be shown.
So, instead of returning an empty module for SVG files, return an empty React component. Let’s set a custom handler for that!
Configure
This example uses require-hacker. For Jest, export a React null component and set it in moduleNameMapper
.
import requireHacker from "require-hacker";
const reactNullComponent = `
require('react').createClass({
render() {
return null;
}
})
`;
requireHacker.hook("svg", () => `module.exports = ${reactNullComponent}`);
Conclusion
I’ve spent a lot of time figuring out how to make everything work, because:
- At the beginning, it was quite confusing to get what was clearly going on.
- There’s a ton of options out there (Webpack null loaders; ignore-styles, which also provide custom handlers; babel-plugin-transform-require-ignore…).
- I didn’t want to handle all the ignored extensions the same say.
Yeah… Sometimes our JavaScript unit tests just know too much.