Testing CSS modules in React components with Jest, Enzyme and a custom moduleNameMapper

David Barral
Trabe
Published in
3 min readOct 15, 2018
Photo by Dmitri Popov on Unsplash

Your React project is already setup. You use webpack to build and you test your componentes using Jest snapshots and Enzyme. One of your components may look like this:

You are happy with this setup for the most part but your project has been growing and the CSS beast is becoming harder to tame. You have used some modular CSS approach but still feel a disconnection between your components and their styles. It’s time to try something new. After some reading about CSS-in-JS approaches and CSS Modules, you go with the latter.

Moving to CSS Modules

Using CSS Modules in webpack is easy. You just need to set to true the modules option in the css-loader, move the component styles to it’s own file, and import them in your component.

We have a problem though, Jest does not know how to handle the css file by default. The Jest documentation (Using with webpack) explains how to tweak the configuration to use a moduleNameMapper.

A moduleNameMapper bridges the gap between Jest and webpack. Jest will use the mapper to create a mock CSS Module when a CSS file is imported. If you use an empty module (module.exports = {}) your test will break: instead of the expected button classname you’ll get undefined. You should use the identity-obj-proxy library to create a mock CSS module that returns the expected classnames.

The identity-obj-proxy does no magic. It’s implementation is straightforward and removing some polyfilling and sanity checks could be reduced to this:

Falling short

The identity-obj-proxy quickly falls short. If you want to use camelCase in JS but keep using dashes in your CSS classes (setting camelCase: true in css-loader) you’ll find soon enough that a styles.buttonInactive appears as buttonInactive in the snapshot instead of button-inactive.

We can overcome this by switching to our own mapper:

Troubled waters

As we’ve seen, sometimes you need to use complex mappers to fit your project needs. Take my previous post “Using BEM conventions in CSS modules leveraging custom webpack loaders” as an example. It’s about how we use BEM classnames in CSS Modules and how we reference them using structured JS objects. It’s by means of a webpack loader that allows us, for example, to get a .button--inactive classname as styles.button.$inactive.

With this setup, to test our components we need a very specific moduleNameMapper. Unfortunately, Enzyme won’t properly serialize the mock CSS modules this mapper returns. We need to add another piece to the puzzle and fine tune the Enzyme output to get usable test snapshots. You can see the code of both mapper and custom serializer in this gist. You can also check Asís García’s post “Fine tuning React Jest snapshots using enzyme-to-json”.

At the end of the day, you may have to make some adjustments to cover your application needs. The existing documentation just covers the basic use cases, but webpack, Jest and Enzyme are very flexible. Just dig into the docs and put together a solution that suits you!

--

--

David Barral
Trabe
Editor for

Co-founder @Trabe. Developer drowning in a sea of pointless code.