Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test with Mocha and Enzyme a React component that uses React CSS Modules

I'm trying to test the generated class of a component that uses React CSS modules

Here is a sample Foo component:

import React from 'react';
import CSSModules from 'react-css-modules';
import styles from './Foo.css';

const Foo = ({ className })  => <div styleName={className} />;

Foo.propTypes = {
  className: React.PropTypes.string.isRequired,
};

export default CSSModules(Foo, styles, { allowMultiple: true, errorWhenNotFound: false });

Test code (Foo.spec.jsx):

import React from 'react';
import { expect } from 'chai';
import { shallow } from 'enzyme';
import Foo from '../../../app/components/Foo';

describe('<Foo/>', () => {
    it.only('should return a className prop as class value', () => {
      const wrapper = shallow(<Foo className="bar" />);
      console.log('DEBUG----->', wrapper.html());
    });
});

Foo.css code:

.bar {
  background-color: red;
}

And here is the test html output:

DEBUG-----> <div></div>

As you can see it generates an empty div without any class, so no assertion works.

Also I would like to bring up the fact that this only fails in the test, the component generates the expected html class in the web app generated html code.

Any idea how to fix this?

UPDATE

As suggested in the comment by fabio I've tried to remove the option errorWhenNotFound: false

Now the test gives the following error message:

Error: "bar" CSS module is undefined.

Which I don't understand since the bar class is defined in the Foo.css file.

Also I've found that if I debug the styles in the Foo component:

import styles from './Foo.css';
console.log('STYLES', styles);

It returns an empty output:

STYLES {}

Although both in this simplified example and in the full fledged code the component generates the expected html class in the web app generated html code with the corresponding styles working fine.

like image 277
rfc1484 Avatar asked Oct 04 '16 12:10

rfc1484


People also ask

Can you use Mocha to test React?

If you use Create React App, Jest is already included out of the box with useful defaults. Libraries like mocha work well in real browser environments, and could help for tests that explicitly need it.

Does React support CSS modules?

How you use CSS modules in React depends on how you create the React application. If you use create-react-app, CSS modules are set up out of the box. However, if you are going to create the application from scratch, you will need to configure CSS modules with a compiler like webpack.

What technologies do you use to unit test your React components?

Jest is a test runner which is mainly used to execute the test cases with assertions. And, at the same, Enzyme is a library that is used with Jest library, that provides the rendering techniques like (shallow, mount, etc.) for React components and traverses the rendered output of the DOM.


1 Answers

As the OP stated in the comments, the problem is that Mocha was running with the ignore-styles option. That, together with the errorWhenNotFound: false option was masking the actual problem, which is that the style object exported by the module is actually empty, the module being ignored by Mocha.

Without that option on, you still need to instruct Mocha to import the CSS module and to parse it correctly. The /var/www/web/app/components/Icon.css: Leading decorators must be attached to a class declaration error is probably due to the fact that Mocha tries to interpret the content of the css file as js, which obviously fails.

To properly set things up, have a look here: https://gist.github.com/mmrko/288d159a55adf1916f71

The idea is to do something like this:

var hook = require('css-modules-require-hook')
var sass = require('node-sass')

hook({
  extensions: [ '.scss', '.css' ],
  generateScopedName: '[local]___[hash:base64:5]',
  preprocessCss: ( data, file ) => sass.renderSync({ file }).css
})

in your Mocha entry file (before you do anything else), to you tell it how to handle the css/sass files.

You can put the content of that gist inside a test/setup.js file for example, and then run Mocha in this way:

mocha --compilers js:babel-register --require ./test/setup.js \"./test/**/*.spec.js\"

In this way, your setup.js initialisation code will run before the tests.

like image 73
fabio.sussetto Avatar answered Sep 26 '22 13:09

fabio.sussetto