Richard Desouza
Richard Desouza

Reputation: 259

Unable to find functions or node when testing a nested component in Jest/Enzyme

I am trying to test a specific component that is nested within two other components:

<Router>
  <Provider store={store}>
    <Howitworks />
  </Provider>
</Router>

However when I try to run my test:

 test("should call onTaskerClick", () => {

   const spy = jest.spyOn(Howitworks.prototype, "onTaskerClick");
   const wrapper = mount(
     <Router>
       <Provider store={store}>
         <Howitworks />
       </Provider>
     </Router>
   );
   wrapper.find("#pills-tasker-tab.nav-link.tasklink").at(0).simulate("click");

   expect(spy).toHaveBeenCalled();

 });

I get a "spyOn on a primitive value; undefined given" error. I have tried different variations of mocking this "onTaskerClick" function when simulating a click on the link that invokes it but always get a variation of the error that the function is undefined or function was not called.

The link that invokes onTaskerClick:

 <a className='nav-link tasklink' id='pills-tasker-tab' data-toggle='pill' onClick={this.onTaskerClick} role='tab' aria-controls='pills-tasker' aria-selected='false'>LINK<span></span></a>

Here is how the Howitworks component is currently being exported:

 export default connect(mapStateToProps, { onNotifyClick })(Howitworks);

Unfortunately there's very limited documentation on accessing functions within a nested component in a test environment so any help would be great.

EDIT:

Updated test suite:

 test("should call onTaskerClick", () => {

   const wrapper = mount(
     <Router>
       <Provider store={store}>
         <Howitworks />
       </Provider>
     </Router>
   );
   const spy = 
 jest.spyOn(wrapper.find(Howitworks.WrappedComponent).instance(), "onTaskerClick");
   wrapper.find("#pills-tasker-tab.nav-link.tasklink").at(0).simulate("click");

   expect(spy).toHaveBeenCalled();
 });

mapStateToProps function and export:

 let mapStateToProps = (state) => ({});

 export default connect(mapStateToProps, { onNotifyClick })(Howitworks);

Upvotes: 1

Views: 1009

Answers (1)

Estus Flask
Estus Flask

Reputation: 222319

connect returns a higher-order component that doesn't inherit from original component, which is common in React.

In order for onTaskerClick to be spyable on a prototype, it should be prototype and not instance (arrow) method. Original component class can be either separate named export:

export class Howitworks {
  onTaskerClick() {...}
  ...
}

export default connect(...)(Howitworks);

Or it can be accessed on connected component as WrappedComponent property.

Since onTaskerClick isn't called on component instantiation, there's no need to spy on a prototype, it's easier to do this on an instance, this doesn't limit a spy to prototype methods:

   const wrapper = mount(...);
   const origComp = wrapper.find(Howitworks.WrappedComponent).instance();
   const spy = jest.spyOn(origComp, "onTaskerClick");
   origComp.forceUpdate();
   // trigger click

Upvotes: 1

Related Questions