className returns undefined with Mocha Enzyme & React CSS Modules

1.4k views Asked by At

I believe what I am trying to achieve has been done many times, but I can't manage it.

I would just like to be able to test if an element has a certain class on a certain element.

Splash

import React from 'react';
import { NavLink } from 'react-router-dom'
import Logo from '../shared/logo/index';
import * as styles from './style.css';

class Splash extends React.Component {
  render(){
    return (
      <div className={styles.indexAppContent}>
        <NavLink to="/home"  className={styles.index}>
          <Logo />
        </NavLink>
      </div>
    );
  }
}

export default Splash;

style.css

.index {
  div {
    color: #FFF;
    //font-size: 8rem;
  }
  position: absolute;
  left: 50%;
  top: 50%;
  display: block;
  transform: translate3d(-50%, -50%, 0);
  -webkit-transform: translate3d(-50%, -50%,0);
  -moz-transform: translate3d(-50%, -50%,0);
  -ms-transform: translate3d(-50%, -50%,0);
}

.indexAppContent {
  height: 100vh;
  width: 100vw;
  position: relative;
}

However this is the output:

{ className: undefined,
  children: 
   { '$$typeof': Symbol(react.element),
     type: { [Function: NavLink] propTypes: [Object], defaultProps: [Object] },
     key: null,
     ref: null,
     props: 
      { to: '/home',
        className: undefined,
        children: [Object],
        activeClassName: 'active',
        ariaCurrent: 'true' },
     _owner: null,
     _store: {} } }

Splash

/* eslint-disable object-property-newline */
import React from 'react';
import ReactTestUtils from 'react-dom/test-utils'
import { expect } from 'chai';
import { NavLink } from 'react-router-dom'
import { shallow } from 'enzyme';

//Splash
import Splash from '../../../src/components/Splash';
import * as styles from '../../../src/components/Splash/style.css';

//logo
import Logo from '../../../src/components/shared/logo';


describe('<Splash />', () => {

  const wrapperSplash = shallow(<Splash/>);
  const wrapperNavLink = shallow(<NavLink />);
  const wrapperLogo = shallow(<Logo />);

  it('must be defined', () => {
    expect(wrapperSplash).to.be.defined;
  });

  it('should have one logo', () => {
    expect(wrapperSplash.find(Logo)).to.have.length(1);
  })

  it('should have className', () => {
    expect(wrapperSplash.first().prop('className'))
      .to.contain('indexAppContent');
  })

  it('Logo links to Home', () => {
    expect(wrapperSplash.find(NavLink).first().props().to)
      .equals('/Home');
  })

});

Test

/* eslint-disable object-property-newline */
import React from 'react';
import ReactTestUtils from 'react-dom/test-utils'
import { expect } from 'chai';
import { NavLink } from 'react-router-dom'
import { shallow } from 'enzyme';

  it('should have className', () => {
    console.info(wrapperSplash.first().props());
    expect(wrapperSplash.first().prop('className'))
      .to.contain('indexAppContent');
  })

Test Helper

import path from 'path';
import csshook from 'css-modules-require-hook/preset' // import hook before routes
import routes from '/shared/views/routes'
import requireHacker from 'require-hacker';
import sass from 'node-sass';
import {jsdom} from 'jsdom';
import injectTapEventPlugin from 'react-tap-event-plugin';

injectTapEventPlugin();

hook({
  extensions: ['.css'],
  generateScopedName: '[local]',
  preprocessCss: (data, filename) =>
    sass.renderSync({
      data,
      file: filename,
      importer: (url) => {
        if (url.indexOf('~') === 0) {
          const node_modules_path = path.resolve(__dirname, '../..', 'node_modules');

          return {
            file: path.join(node_modules_path, url.replace('~', ''))
          };
        }

        return {file: url};
      }
    }).css
});

const fakeComponentString = `
  module.exports = require('react').createClass({
    render() {
      return null;
    }
  });
`;

requireHacker.hook('svg', () => fakeComponentString);

// jsdom
const exposedProperties = ['window', 'navigator', 'document'];


global.document = jsdom('');
global.window = document.defaultView;
Object.keys(document.defaultView).forEach((property) => {
  if (typeof global[property] === 'undefined') {
    global[property] = document.defaultView[property];
  }
});

global.navigator = {
  userAgent: 'node.js'
};
1

There are 1 answers

3
Sagiv b.g On

You are checking a prop of that component and not the existence of a class in the root node that was rendered by this component.
Obviously you are not passing this prop.
You set the class on the root element of this component, thus you should check for nested element that hold this class value in the dom and not the attribute (prop) className You can do it with this syntax for example:

 it('should have class of indexAppContent', () => {
    expect(wrapperSplash.find('.indexAppContent')).to.have.length(1);
  })