I have created an react component to act as an autosaving input field. The intended behaviour is:
- If the user hits Enter or clicks outside the box it will call its
onSubmit
prop with the value the user has entered. - If the user hits the Escape key it will reset the value to
props.lastSavedValue
. - When either Enter or Escape is pressed the input field is defocused.
The code of the component is:
class AutoSavingInput extends React.Component {
constructor (props) {
super(props)
this.state = {currentValue: props.lastSavedValue || ''}
}
render() {
return (
<input
ref={(input) => this.input = input}
value={this.state.currentValue}
onChange={(e) => this.setState({currentValue: e.target.value})}
onBlur={() => this.props.onSubmit(this.state.currentValue)}
onKeyUp={(event) => {
switch (event.key) {
case 'Enter':
this.input.blur()
break
case 'Escape': {
this.setState({currentValue: this.props.lastSavedValue},
() => this.input.blur())
break
}
}
}}
/>
)
}
}
Testing the blur
event with Jest or Enzyme is trivial but I am having trouble testing
the key press events. I have tried:
function setup () {
const onSubmit = jest.fn()
const component = ReactTestUtils.renderIntoDocument(
<AutoSavingInput lastSavedValue="last-saved-value" onSubmit={onSubmit} />
)
const node = ReactTestUtils.findRenderedDOMComponentWithTag(component, 'input')
component.setState({currentValue: 'the-value'})
return { component, node, onSubmit }
}
// THIS TEST SHOULD PASS BUT IT FAILS
it('submits when Enter key is pressed', () => {
const { node, onSubmit } = setup()
ReactTestUtils.Simulate.keyUp(node, {key: 'Enter'})
expect(onSubmit).toHaveBeenCalledWith('the-value')
})
// THIS TEST SHOULD FAIL BUT IT PASSES
it('does not submit when Escape key is pressed', () => {
const { node, onSubmit } = setup()
ReactTestUtils.Simulate.keyUp(node, {key: 'Escape'})
expect(onSubmit).toHaveBeenCalledTimes(0)
})
As the comments describe, the Enter key test fails when it should pass and the Escape key
test passes when it should fail. This is happening because in the test environment,
this.input.blur()
is not triggering the blur
event.
When I test in the browser, the code behaves as expected.
It is possible to write a Jest or Enzyme test which handles events emitted from within the component?
I've put the code in a create-react-app project here if anyone wants to experiment: https://github.com/RobbieClarken/testing-react-component-events