I am using to sinon
to test a react component to confirm that a function is triggered onClick
.
I am using styled-components
so finding it difficult to target the element to click on.
I am seeing the following error:
Method “simulate” is only meant to be run on a single node. 0 found instead.
My react code looks like this:
import React, { Component } from 'react'
import styled from 'styled-components'
import PropTypes from 'prop-types'
class Button extends Component {
pressNumber = () => {
this.props.updateNumber(this.props.number)
}
render() {
return (
<ButtonContainer
onClick={ this.pressNumber }
>
<Number>{ this.props.number }</Number>
</ButtonContainer>
)
}
}
const ButtonContainer = styled.div`
height: 60px;
width: 60px;
`
const Number = styled.div`
color: #fff;
font-size: 26px;
font-weight: 300;
`
My test then looks like this:
import { expect } from 'chai'
import { shallow, mount } from 'enzyme'
import sinon from 'sinon'
import React from 'react'
import Button from './index'
describe('Button', () => {
let wrapper
const pressNumber = () => {}
beforeEach(() => {
wrapper = mount(
<Button
number={1}
pressNumber={ pressNumber }
/>
)
})
it('should call the update pin prop when click is simulated', () => {
const updatePinClick = sinon.spy();
wrapper.find('ButtonContainer').simulate('click')
expect(updatePinClick.calledOnce).to.be.true
})
})
Can anyone see what I am doing wrong here, and if there is a different approach as I am using styled-components.
I am seeing the following error
Method “simulate” is only meant to be run on a single node. 0 found instead.
(disclosure: i'm an enzyme maintainer)
Your spy is updatePinClick
, but you're not passing it anywhere, so it can't be used. Additionally, Button
doesn't take a pressNumber
prop.
First, I'd suggest the following general tips:
.simulate
- if you want to invoke a prop, do it directly, like .prop('onClick')()
.beforeEach
- in tests, it's far better to repeat yourself, and specifically the jsx you're using..find
; it's less brittle to export the component you want to find, and find it by reference instead..to.be.true
. This is because you could easily make a typo and it would fail silently - expect(object).to.be.yogurt;
will happily pass, even though that's not a valid matcher.shallow
for all your tests. Only use mount
when it's necessary to use refs, or to test componentDidMount
, or other browser-only code.Specifically, try this:
import { expect } from 'chai'
import { shallow, mount } from 'enzyme'
import sinon from 'sinon'
import React from 'react'
import Button from './index'
describe('Button', () => {
it('should call the update pin prop when click is simulated', () => {
const updatePinClick = sinon.spy();
const wrapper = shallow(
<Button
number={1}
updateNumber={updatePinClick}
/>
);
wrapper.find('ButtonContainer').prop('onClick')();
expect(updatePinClick).to.have.property('callCount', 1);
expect(updatePinClick.calledWith(1)).to.equal(true);
});
})