Using CSS modules in react when testing with enzyme
We’ve been using CSS modules in a react project, and wanted to use those classes
in our tests. However we quickly ran into the problem that none of the classes were found.
Any wrapper.exists
would be false. The problem was with our css modules, as they were not
imported correctly during tests.
Our code looked like this:
import styles from './QA.scss?module';
interface QAProps {
question: string;
answer?: string;
isOpen?: boolean;
}
const QA:React.FC<QAProps> = ({question, answer, isOpen}) => (
<div>
<p>{question}</p>
{isOpen && <div className={styles.Answer}>{answer}</div>}
</div>
);
When testing it we tried the following:
it('has no answer when not opened', () => {
const wrapper = shallow(<QA question="hi" />)
// passes
expect(wrapper.exists('.Answer')).toBe(false);
});
it('has an answer when opened', () => {
const wrapper = shallow(<QA question="hi" answer="answer" isOpen />)
// fails
expect(wrapper.exists('.Answer')).toBe(true);
});
The problem lied in our fileMock for jest.
// jest.config.js
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.(scss|less|scss\\?module)$": "<rootDir>/__mocks__/fileMock.js"
},
// __mocks__/fileMock.js
module.exports = 'content';
Because of this export, styles.Answer
would be undefined. Instead, during our tests we want it
to just return the name of the property. In PHP you would use the __get
magic method.
(Un)fortunately, this is also possible in js, through a Proxy
object.
We make a proxy of an empty object, that always returns the property that is being requested. And in the jest.config.js
we update the css files to refer to this new cssMock.js
file.
// __mocks__/cssMock.js
const target = {};
const handler = {
get: function(target, prop) {
return prop;
}
};
const proxy = new Proxy(target, handler);
export default proxy;
Now, our tests pass, and our css modules can be used within our tests.