3
votes

I am trying to test an event handler with Enzyme / Jest for a react component, however my spy function is never called...

My component has a div with an id and I am using that to find the dom elem

 render() {
    return (
        <div>
            <Top
                {...this.props}
            />
            <div 
                id = 'keyboard_clickable'
                onClick = {this._handleClick}
                style= {styles.main}>
                {this._showKeyBoard()}
            </div>
            <input onChange = {() => {}}/>
      </div>
    );
  }
}

My test

describe('onclick function is called ...', () => {
  it.only('spyOn', () => {
    const spy = jest.fn()

    const wrapper = shallow(
      <Keyboard 
      _getData      = { () => {} }
      _erase        = { () => {} }
      _get_letters  = { () => {} }
      _createWord   = { () => {} }
      _modeSwitch   = { () => {} }
      onClick       = { spy      }
      />
    )

    wrapper.find('#keyboard_clickable').simulate('click', {
      target:{
        parentElement:{ id: 5 },
        id:6
        }
    })
    expect(spy).toHaveBeenCalled();

  })
})

my HandleClick

_handleClick = e => {
    let parent = e.target.parentElement;
    if(e.target.id || (!isNaN(parent.id) && parent.id > 0) ) {
        this.props._getData(e.target.id || e.target.parentElement.id)
        this.setState({status:'ok'})
    }else{
        this.setState({status:'Use numbers between 2 and 9'},()=>{
            return alert(this.state.status)
        })

    }
}

Test output

Expected mock function to have been called, but it was not called.
2
Could you please show what Keyboard._handleClick does? I suspect it might not be calling Keyboard.props.onClick.Jemi Salo
Yeah is not calling Keyboard.props._handleClick, the method is Keyboard._handleClickNilos
Please add it to your original post, it is barely readable hereAxnyff
Your _handleClick method never calls an onClick props. What you could test instead is that the state is correctly changed and that the _getData props get calledAxnyff

2 Answers

3
votes

To test that your event handler is called, you'll have to replace the event handler with a mock function. One way to do that is to extend your component class:

class TestKeyboard extends Keyboard {
  constructor(props) {
    super(props)
    this._handleClick = this.props._handleClick
  }
}

describe('onclick function is called ...', () => {
  it.only('spyOn', () => {
    const spy = jest.fn()

    const wrapper = shallow(
      <TestKeyboard 
      _getData      = { () => {} }
      _erase        = { () => {} }
      _get_letters  = { () => {} }
      _createWord   = { () => {} }
      _modeSwitch   = { () => {} }
      _handleClick  = { spy      }
      />
    )

    wrapper.find('#keyboard_clickable').simulate('click', {
      target:{
        parentElement:{ id: 5 },
        id:6
        }
    })
    expect(spy).toHaveBeenCalled();

  })
})

The prop _handleClick replaces Keyboard._handleClick and is therefore called when onClick fires in the clicked element.

Alternatively, jest.spyOn

In case you need to let the event handler execute and test what it was called with, you can use jest.spyOn. I find this method more complex, but it is more flexible.

import { mount } from 'enzyme'

describe('onclick function is called ...', () => {
  it.only('spyOn', () => {
    const wrapper = mount(
      <Keyboard 
      _getData      = { () => {} }
      _erase        = { () => {} }
      _get_letters  = { () => {} }
      _createWord   = { () => {} }
      _modeSwitch   = { () => {} }
      />
    )

    const spy = jest.spyOn(wrapper.instance(), '_handleClick')
    wrapper.instance().forceUpdate()

    wrapper.find('#keyboard_clickable').simulate('click', {
      target:{
        parentElement:{ id: 5 },
        id:6
        }
    })
    expect(spy).toHaveBeenCalled();

  })
})

Note that this will fail when using shallow rendering so you'll have to use enzyme.mount instead.

1
votes

It seems that simulating a click with enzyme in shallow render does work, but only if I forceUpdate(), like in Jemi's solution.

example:

 beforeEach(() => {
    wrapper = shallow(<VehicleDamage handleSubmit={mockFunction} onPrevClick={mockFunction} />);
});

it('handlePrevClick is called on click', function() {
    const spyHandlePrevClick = jest.spyOn(wrapper.instance(), 'handlePrevClick');
    wrapper.instance().forceUpdate(); // I assume required to assign mocked function

    let buttonContainer = wrapper.find('ButtonContainer').dive();
    let button = buttonContainer.find('Button').at(0);

    button.simulate('click', {
        preventDefault: () => jest.fn()
    });

    expect(spyHandlePrevClick).toHaveBeenCalled();
});