如何使用Jest和Enzyme对包含history.push的react事件处理程序进行单元测试?

如何使用Jest和Enzyme对包含history.push的react事件处理程序进行单元测试?

问题描述:

给出一个简单的组件:

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 />)
    ...?
  })
})

您如何验证表单提交是否将用户带到具有正确查询值的下一页?

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

我已经尝试过简单地模拟onSubmit处理程序,并至少确认它已被调用,但这由于history.push而导致安全错误.

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

实际上很简单,当在测试中对组件进行浅层渲染时,您可以将任何prop传递给该组件,如下所示:
const wrapper = shallow(<SearchForm history={historyMock} />)

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

顺便说一句,在onSubmit内部,您应该像this.props.history.push(...)那样呼叫.

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

现在,创建一个模拟文件(有关详细信息,请参见文档),则可以在测试中编写如下代码:
const historyMock = { push: jest.fn() };

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

请记住,您实际上仅在模拟history对象的push方法,如果在组件内部使用更多方法并要对其进行测试,则应为每个被测试的对象创建一个模拟.

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.

然后,您需要断言push模拟是否已正确调用.为此,您编写必要的断言:
expect(historyMock.push.mock.calls[0]).toEqual([ (url string), (state object) ]);
使用所需的(url string)(state object)进行断言.

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.