Как провести модульное тестирование обработчика событий реакции, который содержит history.push, используя Jest и Enzyme?

Учитывая простой компонент:

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>
    )
  }
}

И тест:

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

Как убедиться, что при отправке формы пользователь переходит на следующую страницу с правильным значением запроса?

Я пытался просто издеваться над обработчиком onSubmit и, по крайней мере, подтверждать, что он был вызван, но это приводит к ошибке безопасности из-за 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()

person Darryl Snow    schedule 04.06.2018    source источник


Ответы (1)


На самом деле это просто, вы можете передать компоненту любые реквизиты при поверхностном рендеринге внутри теста, например:
const wrapper = shallow(<SearchForm history={historyMock} />)

Кстати, внутри onSubmit надо звонить как this.props.history.push(...).

Теперь, чтобы создать макет (дополнительная информация в документация) , в тесте можно написать так:
const historyMock = { push: jest.fn() };

Имейте в виду, что на самом деле вы издеваетесь только над методом push объекта history, если вы используете больше методов внутри компонента и хотите их протестировать, вы должны создать макет для каждого тестируемого.

И затем вам нужно утверждать, что макет push был вызван правильно. Для этого вы пишете необходимое утверждение:
expect(historyMock.push.mock.calls[0]).toEqual([ (url string), (state object) ]);
Используйте необходимые (url string) и (state object) для подтверждения.

person rodgobbi    schedule 04.06.2018
comment
Чтобы добавить к ответу, имейте в виду, что вы можете передать любой параметр, который хотите, при поверхностном рендеринге компонента, а не только для макетов. - person rodgobbi; 04.06.2018
comment
это требует добавления дополнительных реквизитов и изменения нашего целевого компонента, верно? - person Damian Green; 20.02.2019
comment
@DamianGreen не совсем, цель в конце концов состоит в том, чтобы утверждать, что функция push из объекта history вызывается правильно, а history передается как реквизит. - person rodgobbi; 20.02.2019