Hi,
I鈥檝e got the following React component:
class ModalDialog extends React.Component {
render() {
return (
<div className="modal" onClick={() => this.props.cancel(0) }>
<div className="modal-dialog" onClick={(event) => event.stopPropagation() } >
...
</div>
</div>
)
}
}
And the following test:
it('does not call cancel() when clicking inside the modal dialog', () => {
const cancel = () => undefined
const spy = sinon.spy(cancel)
const html = shallow(<ModalDialog cancel={spy} />)
const modal = html.find('.modal-dialog').first()
modal.simulate('click')
expect(spy.notCalled).to.be.true // Cannot read property 'stopPropagation' of undefined
})
The problem I鈥檓 having is that the onClick handler (event) => event.stopPropagation() isn't receiving an event argument when simulating the click. Is this a known (or by design) behaviour, or am I doing something wrong?
My tests are Mocha-based running inside Wallaby.js with the environment set to 'node', so there's no browser etc involved. Could that be the problem? If so, is there a way around it without having to massively change the test environment?
Thanks
Managed to figure it out, although it does mean fudging things a little just for testing purposes:
const fakeEvent = {
stopPropagation: () => false
}
class ModalDialog extends React.Component {
render() {
return (
<div className="modal" onClick={() => this.props.cancel(0) }>
<div className="modal-dialog" onClick={(event = fakeEvent) => event.stopPropagation() } >
...
</div>
</div>
)
}
}
So I鈥檓 assigning the value of fakeEvent to the event argument when it hasn't been passed to the click handler, which will only happen in my test environment. In the browser, the event will always be set to a proper value.
I鈥檝e also changed the test to:
it('does not call cancel() when clicking inside the modal dialog', () => {
const spy = sinon.spy() // The cancel function is no longer defined
const html = shallow(<ModalDialog cancel={spy} />)
const modal = html.find('.modal-dialog').first()
modal.simulate('click')
expect(spy.notCalled).to.be.true
})
As the faked function with which the spy was created doesn't actually need to exist at it doesn't ever get called.
Now my test passes, although I鈥檓 not 100% happy with the way I鈥檝e fudged it.
Could you use modal.simulate('click', { preventDefault() {} }) to avoid the fudging?
There also seems to be a bug in your test.
Your are assigning the prop.click function to the div.modal node,
but trying to test the prop.click by simulating the div.modal-dialog node.
I think the test you want to see is:
// spy stuff...
html.find('.modal').simulate('click', { preventDefault() {} });
// expect
Doh! Yes, that is a much simpler way of doing it. Here's what I've gone with:
modal.simulate('click', { stopPropagation: ()=> undefined })
Which is more or less the same thing :) Thanks!
@blainekasten it's part of a set of two tests. The one I was having trouble with tests that clicking the modal dialog _doesn't_ call props.cancel, whereas the other test checks that clicking outside the modal dialog _does_ call it. Here are the two tests in full:
it('calls cancel() when clicking outside the modal dialog', () => {
const spy = sinon.spy()
const html = shallow(<ModalDialog cancel={spy} />)
const modal = html.find('.modal').first()
modal.simulate('click')
expect(spy.calledOnce).to.be.true
})
it('does not call cancel() when clicking inside the modal dialog', () => {
const spy = sinon.spy()
const html = shallow(<ModalDialog cancel={spy} />)
const modal = html.find('.modal-dialog').first()
modal.simulate('click', { stopPropagation: () => undefined })
expect(spy.notCalled).to.be.true
})
@dylanparry glad you got it sorted out. Seems like this issue is close-able then, yeah?
Yes. Sorry, I thought I'd closed it already :)
Hi, guys. I'm having an issue with the button click. The following is getting as the response on checking the click event for a button.
AssertionError: expected false to be true
Adding the test scripts below,
it('find the tab state 1', () => {
const onsubmit = sinon.spy();
const wrapper = mount(<Login className="sampleclass" onSubmit={onsubmit} onChange={props.onChange} />);
wrapper.setState({ tab: 1});
wrapper.setState({clientEmail: "[email protected]"});
const button = wrapper.find('button').at(0)
button.simulate('click');
expect(wrapper.find('.email')).to.have.length(1);
expect(onsubmit.calledOnce).to.be.true
});
@muneermuhammed can you share Login's implementation. The following code above would only work if the component did something like this:
render() {
<button onClick={this.props.onSubmit} />
}
@blainekasten Thanks for the helping hand. Since I'm new to react and enzyme don't have the clear idea about this, I will share the login implementation here,
Login
You can simply pass an event, rather than passing a literal object with some custom methods on:
modal.simulate('click', new Event('click'));
Most helpful comment
Could you use
modal.simulate('click', { preventDefault() {} })to avoid the fudging?