react-onclickoutside: Enzyme's wrapper.state() returns "null" when use react-onclickoutside

I use enzyme to test React components. Recently, I’ve encountered a problem while testing some of my components where I used react-onclickoutside.

See following example.

// component.js - Define a basic React component.
export default class Component extends React.Component {
  constructor() {
    super();
    this.state = { value: 'Pineapple' };
  }

  // required by react-onclickoutside
  handleClickOutside() { }

  render() {
    return <h3>{ this.state.value }</h3>;
  }
}
// component.spec.js
import { mount } from 'enzyme';
import Component from '../component';

// This test will pass just fine
it('Component', function() {
  const wrapper = mount(<Component />);
  expect(typeof wrapper.state()).toEqual('object'); // 
  expect(wrapper.state().value).toEqual('Pineapple');
});


// Wrap Component using `react-onclickoutside`
const Enhancer = onClickOutside(Component);

// This test will fail
it('Enhancer', function() {
  const wrapper = mount(<Enhancer />);
  expect(typeof wrapper.state()).toEqual('object'); // throws an error. state = null
  expect(wrapper.state().value).toEqual('Pineapple');
});
screen shot 2016-09-19 at 13 09 33

As you can see from the example above. Wrapping Component into onClickOutside makes wrapper return null instead of a state object.

Any ideas?

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 6
  • Comments: 15 (8 by maintainers)

Most upvoted comments

I finally found a very good solution to get a wrapper from a decorated component. For shallowed components you can use dive() but there is no similar method for mounted components. This is the solution I did:

const wrapper = mount(shallow(<MyComponent />).get(0))

Works like a charm 😃

Reading more about similar scenarios here…sounds like its recommended to export the unwrapped class and just do tests around that. Then essentially you can have another export that contains the wrapped version.

@abdennour I strongly discourage doing that; that’s what .dive() is for. You should never need to export a wrapped component just for tests - in fact, any character of production code you write solely for testing is a code smell.

If you have :

/*MyComponent.js*/
//....
export default ClickedOutSide(MyComponent);

Add another line of export :

/*MyComponent.js*/
//....
export { MyComponent }; // This export is useful in unit-tests 😉
export default ClickedOutSide(MyComponent);

Then in your test/spec file :

import { MyComponent } from './MyComponent';
// and NOT [  import  MyComponent  from './MyComponent'; ]

@Pomax that getInstance() is what I needed for an enzyme test of a component that uses onClickOutside: https://github.com/WikiEducationFoundation/WikiEduDashboard/commit/462411a2474bc8efbe97f989f8e42bdfd34a3d20

Thanks for maintaining this component, which works really nicely in my project!

In that case you have getInstance() available on the wrapped component. Give that a shot and if that works we can come up with some troubleshooting text to add to the README.md for enzyme users.