enzymejs/enzyme

Local scoped css

halvardos opened this issue ยท 8 comments

Hi

We use CSS modules and I'm having a hard time finding a way to select nodes that have a local scoped css className.

The actual classname that is set in the DOM is built as a combination of the JS class and the css class plus a hash that ensures the class is unique.
Something like:
JSClassName__cssclass__!"##$"$Feoij3432

I tried using the attribute contains selector but this seems to not be supported yet.
E.g:
expect(wrapper.find('div[class*="cssclass"]')).to.have.length(1);

So I'm wondering if anyone has any experience on how to do this without adding code to the component to identify the node we are trying to select.

I think that a good option is to extract the thing that you want to select in tests into its own component (preferably stateless functional component if that fits your use-case). Then you should be able to select it easily without worrying about the CSS classes at all.

However, if you would rather not do that, I think you might have a few options:

  • import your stylesheet in your tests as a dependency and reference the classes as you would in the component
  • use a global class for this

And a couple of options that don't fit your requirement of not adding code to the component to identify the node you are trying to select:

  • add an attribute to help with testing (like data-test-name) and then find based on that attribute
  • add a non-CSS className to your component, for testing purposes

I have pulled this off by having my preprocessor not obfuscate the classnames for my unit tests. I'm not sure what your build pipeline is, but you should be able to do this. That way you can test it by the js key you define.

For example:

// component
import style from './style.css';

const div = <div className={style.foo} />

// test
const wrapper = shallow(div);
wrapper.hasClass('foo') // true;

I run my tests with karma-webpack so that the spec files can also process CSS. In my tests, it looks something like this

import style from './style.css';
render.find(`.${style.foo}`);

@clouddra thx! this actually worked perfectly, we also use karma-webpack.

I'm not sure why i thought it would generate a different classname for my test and for my source, but when i tried testing it i forgot to concatenate it with .

When a selector is composed of another you get two class names which will throw this error: Enzyme received a complex CSS selector ('.styles__navigation___fCgdZ styles__trigger___2b9Qy') that it does not currently support

Used this to fix it:

wrapper.find(`.${styles.navigation.split(' ').join('.')}`);

How can I make it work if I use jest? I need to find a selector with a class generated with CSS Modules. Like "search-icon--33gh78". I'm adding a fixed class like "enzyme-search-icon" as a workaround, but I'd like to import my css files in my tests.

@pietrofxq use this https://github.com/Connormiha/jest-css-modules-transform/blob/master/src/index.js

Then in your tests your className will match the className in your .css file (not obfuscated);

// component
import style from './style.css';

const div = <div className={style.foo} />

// test
const wrapper = shallow(div);
wrapper.hasClass('foo') // true;

I managed to get it working by adding this: identity-obj-proxy

  "moduleNameMapper": {
    ".*\\.scss$": "identity-obj-proxy"
  }

Then when you do styles['badger'] in jest you get "badger" rather than ""