2021-05-05
|~3 min read
|457 words
While testing specific CSS styles within a unit test is rare, it’s not uncommon to want to know if the right class was applied to a component.
In Jest: Handling Static Assets with Mocks, I walked through how to mock out CSS modules so that they wouldn’t break tests because Jest didn’t know how to handle them.
Unfortunately, the mock removes all detail from the component or requires a separate mock for each test (which is hardly ideal). An NPM package, identity-obj-proxy
provides a pretty elegant solution to this problem. Let’s see how!
Before seeing how identity-obj-proxy
solves the problem, let’s make sure we understand. We’ll assume that we’ve already set up a mock CSS file and we have the following component:
import React from "react"
import PropTypes from "prop-types"
import styles from "./my-component.module.css"
function MyComponent(props) {
return <div className={styles.myClass}>{props.children}</div>
}
A CSS module which defines the class
.myClass = {
/*...*/
}
And finally, the test:
import React from "react"
import { render } from "@testing-library/react"
import MyComponent from "./MyComponent"
test("it renders", () => {
const { debug } = render(<MyComponent />)
debug()
})
When I run the test, I’ll see the following logged by the debug
call:
PASS src/MyComponent.test.js
● Console
console.log
<body>
<div>
<div
data-testid="total"
style="transform: scale(1,1);"
/>
</div>
</body>
at debug (node_modules/@testing-library/react/dist/pure.js:107:13)
Notice that there’s no className! It’s hard to make an assertion that the right class is applied if it gets stripped out completely.
Let’s fix that.
Identity-Obj-Proxy
First, we need to install the library:
% yarn add --dev identity-obj-proxy
Then, we’ll need to add it to our jest.config.js
:
module.exports = {
moduleNameMapper: {
+ '\\.module\\.css$': 'identity-obj-proxy',
'\\.(css|less)$': require.resolve('./test/style-mock.js'),
},
}
Note: Order matters. If the
.module.css
mapper came after the.css
variant, it would not be used.
Once in place, if we re-run our test, we’ll see the class is passed through with the name of the class as defined in the module:
PASS src/MyComponent.test.js
● Console
console.log
<body>
<div>
<div
class="myClass"
data-testid="total"
style="transform: scale(1,1);"
/>
</div>
</body>
at debug (node_modules/@testing-library/react/dist/pure.js:107:13)
The purpose of this post was to walk through how we can use identity-obj-proxy
to get access to details that might otherwise be obscured through the use of mocks so that we can make assertions on them in our tests. This post walked through that exercise using CSS modules as the subject.
It’s also worth a reminder that order matters when it comes to moduleNameMapper
as matches are done on a first seen basis - so, place the most specific matches at the top of the mapper and least specific at the bottom.
Hi there and thanks for reading! My name's Stephen. I live in Chicago with my wife, Kate, and dog, Finn. Want more? See about and get in touch!