React Testing: Getting jest to play nicely with webpack static assets imports

Gaurav Gupta
The Startup
Published in
3 min readJun 26, 2019
Photo by Chris Liverani on Unsplash

After using separate css files in public folder for a long time and referring them directly from index.html, we recently switched to co-locating our css with the component and importing it in the component using webpack (using css-loader and style-loader). We did not expect it to break any of our existing setup, because why, who else is using the css files apart from the components anyway. Turns out it was fine before, but now since the css is imported in the component file, jest does not know what to do with it. Why?

Because jest doesn’t know what to do with static imports in components. This is something specific to webpack, and jest has no way of understanding this.

Which brings us back to this. How does jest understand ES6 imports for the javascript modules by default?

Turns out it doesn’t. It is possible to use ES6 syntax with jest because jest by default ships with babel-jest which makes sure that if there is a .babelrc (or any other bable configuration) file in your project, jest would respect it.

It is not so easy with webpack. The jest integration for webpack is not so direct, because jest can’t directly comprehend your webpack.config.js and based on that use loaders to allow you to import static assets.

So, what’s the resolution?

There are 2 options:

  • we can mock these static assets
  • or we can somehow ask jest to transform it and make some sense of it instead of mocking. (see here and here)

In most cases, it should be ok to mock these assets simply, as the component code wouldn’t depend on anything from inside of them.

What do we mock it with?

  • For the css files we can just export an empty object.
  • For the image files (which we use as import something from “./something.jpg”)we can just export some string.

How do we mock it?

There are multiple ways to mock this import.We can do it at a file level, or we can configure jest to “ignore” all imported css files.

At the file level:

jest.mock("./something.css", () => {
return {};
});

Or globally:

// jest.config.js
moduleNameMapper: {
"\\. (jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m 4a|aac|oga)$":"<rootDir>/__mocks__/fileMock.js",
"\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js"
},
// <rootDir>/__mocks__/styleMock.js
module.exports = {};
// <rootDir>/__mocks__/fileMock.js
module.exports = "test-file-stub";

Or

you can use the transform config in jest, to do some specific transforms:

// fileTransformer.js 
const path = require('path');
module.exports = {
process(src, filename, config, options) {
return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';';
},
};
// config
"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"
}

This does suffice for the use case we encountered.

Below I talk about some other common use cases:

What if your static assets do contain something which is being used in your code, for example css-modules, in which case the classnames in your component are being mapped from the imported css file. Turns out there is a easy resolution for that as well. Instead of mocking it with an empty file, you can mock it with something that returns the stringified classname whenever it is referred.

What if we are not just using classnames, but some variables from inside our css files to do some calculations in our component. In this case, you can manually mock the file only for that module and expose an object which returns the required values.

References:

--

--