0
votes

I have created an react component to act as an autosaving input field. The intended behaviour is:

  1. If the user hits Enter or clicks outside the box it will call its onSubmit prop with the value the user has entered.
  2. If the user hits the Escape key it will reset the value to props.lastSavedValue.
  3. 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

1

1 Answers

0
votes

It looks like the keyUp event is meant to fire this.input.blur(), and you expect blur() to then trigger the component's onBlur() function and call onSubmit(). This may not be something you can easily test with Enzyme. There is not actually a DOM, so you may not be able to expect that this.input.blur() will actually trigger the input's onBlur() handler. You might have better luck testing what the keyUp event directly fires (this.input.blur() rather than onSubmit()).