20

Given a simple component:

export default class SearchForm extends Component {
  constructor(props) {
    super(props)
    this.state = { query: '' }
  }
  onSubmit = (event) => {
    event.preventDefault()
    history.push(`/results/${this.state.query}`, { query: this.state.query })
  }
  render() {
    return (
      <form onSubmit={this.onSubmit}>
        <input
          type="text"
          value={this.state.query}
          onChange={event => this.setState({ query: event.target.value })}
        />
        <button>Search</button>
      </form>
    )
  }
}

And the test:

describe('SearchForm Component', () => {
  it('should navigate to results/query when submitted', () => {
    const wrapper = shallow(<SearchForm />)
    ...?
  })
})

How do you verify that form submission is taking the user to the next page with the correct query value?

I've tried simply mocking the onSubmit handler and at least confirming that it's been called, but this results in a security error due to history.push.

const wrapper = shallow(<SearchForm />)
const mockedEvent = { target: {}, preventDefault: () => {} }
const spy = jest.spyOn(wrapper.instance(), 'onSubmit')
wrapper.find('form').simulate('submit', mockedEvent)
expect(spy).toHaveBeenCalled()
skyboyer
  • 15,149
  • 4
  • 41
  • 56
Darryl Snow
  • 868
  • 1
  • 6
  • 20

1 Answers1

31

It's actually simple, you can pass in any props to the component when shallow rendering it inside the test, like that:
const wrapper = shallow(<SearchForm history={historyMock} />)

By the way, inside onSubmit, you should call like this.props.history.push(...).

Now, to create a mock (more info in the documentation), you can write like this in the test:
const historyMock = { push: jest.fn() };

Keep in mind that you are actually mocking only the push method of the history object, if you use more methods inside the component and want to test them, you should create a mock to each one tested.

And then, you need to assert that the push mock was called correctly. To do that, you write the assertion necessary:
expect(historyMock.push.mock.calls[0]).toEqual([ (url string), (state object) ]);
Use the needed (url string) and (state object) to be asserted.

rodgobbi
  • 1,272
  • 13
  • 10
  • 2
    To add to the answer, keep in mind that you can pass any parameter that you want when shallow rendering a component, not just mocks. – rodgobbi Jun 04 '18 at 16:03
  • this requires adding additional props and changing our target component though, right? – Damian Green Feb 20 '19 at 13:54
  • @DamianGreen not really, the objective in the end is asserting that the `push` function from the object `history` is called correctly, and `history` is passed as props. – rodgobbi Feb 20 '19 at 15:30