【问题标题】:How to test a simple async React action with Jest?如何用 Jest 测试一个简单的异步 React 动作?
【发布时间】:2018-02-11 22:28:13
【问题描述】:

我正在尝试测试 Redux 操作,并且在测试具有副作用的操作时需要帮助。

这是我的行动:

export function login(email, password) {
  return dispatch => {
    dispatch(setLoginSuccess(false));
    loginApi(email, password, error => {
      dispatch(setLoginPending(false));
      if (!error) {
        dispatch(setLoginSuccess(true));
      } else {
        dispatch(setLoginError(error));
      }
    });
  }
}

下面是验证用户的 loginApi 函数:

export function loginApi(email, password, callback) {
    if (email === 'test@test.com' && password == '123') {
      return callback(null);
    } else {
      return callback(new Error('Please provide valid email and password'));
    }
};

此外,我在使用 Enzyme 和 Jest 在组件中模拟表单提交时遇到了问题。

这是相同的代码:

render() {
        let {email, password, emailValid} = this.state;
        let {isLoginPending, isLoginSuccess, loginError} = this.props;     
        return (
                <div className="col-md-6 col-md-offset-3 col-sm-8 col-sm-offset-2 col-xs-10 col-xs-offset-1">
                    <h3 className="text-center">Login</h3>
                    <form className="login-form" onSubmit={this.handleSubmit.bind(this)}>
                        <div className={emailValid? "form-group has-success" : (emailValid == undefined)? "form-group": "form-group has-error"}>
                            <label>Email address</label>
                            <input type="email" name="email" className="form-control" ref="userEmail" 
                            placeholder="Enter your email" onChange={this.handleChange.bind(this)}/>
                        </div>

                        {/* Checking if email valid or not */}
                        {this.props.emailValid? "" : (this.props.emailValid == undefined)? "" : <p className="text-danger">Please provide a valid email!</p>}

                        <div className="form-group">
                            <label>Password</label>
                            <input type="password" name="password" className="form-control" ref="userPassword"
                            placeholder="Enter your password" onChange={this.handleChange.bind(this)}/>
                        </div>

                        <button type ="submit" className="btn btn-primary btn-block" disabled={!this.props.emailValid}>Get Started</button>

                        {/* Displaying error messages */}
                        { loginError && <div className="auth-error-msg"><p className="text-danger">{loginError.message}</p></div> }
                    </form>
                </div>
        );
    };

这里是handleSubmit事件的代码:

handleSubmit(e){
    e.preventDefault();
    this.props.login(this.refs.userEmail.value, this.refs.userPassword.value);
    this.setState({
      email: '',
      password: ''
    });

}

我正在尝试以这种方式模拟提交事件:

 it('should render 1 error block on submitting invalid form', () => {
        // Render a checkbox with label in the document
        const spy = jest.fn();
        const component = shallow(<Login login={spy}/>);

        const form = component.find('form').simulate('submit');

});

但它目前会抛出错误,因为它找不到 preventDefault。如何测试此事件?

【问题讨论】:

    标签: reactjs react-redux enzyme redux-thunk


    【解决方案1】:

    我建议您拆分测试。提交表单和测试操作是两件不同的事情。要使用 jest 测试操作,您需要将操作分派到模拟存储,并查看存储的最终状态。像这样的:

    describe('actions', () => {
      let store
    
      beforeEach(() => {
        store = mockStore({})
      })
    
      it('should dispatch the correct actions', () => {
        const expectedActions = [
          { type: 'action1', ...arguments },
          { type: 'action2', ...arguments }
        ]
    
        store.dispatch(login('user', 'password'))
        expect(store.getActions()).toEqual(expectedActions)
      })
    })
    

    您可以执行多个测试用例,根据您作为参数传递的内容调整预期操作。

    对于创建模拟商店,有多个包可以完成这项工作。下面是一个支持 thunk 的示例:

    import configureMockStore from 'redux-mock-store'
    import thunk from 'redux-thunk'
    
    const middlewares = [ thunk ]
    const mockStore = configureMockStore(middlewares)  
    export default mockStore
    

    我个人不会花太多精力测试表单提交的内容。最后,这是一个标准的 html 内容,因此我将重点介绍您自己构建的组件。

    还有一个提示:如果您已经经历了使用redux 的所有麻烦,请不要回到正常状态。您拥有的 setState 将更容易实现和测试,通过使用普通的减速器并将其也放入您的状态。

    【讨论】:

    • 感谢@Mario 的解释。我有一个小小的疑问。我没有在我的操作中使用 Promise,所以如果我在测试中使用 'then' 会引发错误。我浏览了redux docs,他们也有一个使用promises的类似示例,但在我的情况下,我只是在等待loginApi函数回调,那么我该如何重构测试?请帮忙!
    • 我编辑了同步案例的示例。您只需要删除 then 并在调度操作后执行您的断言
    • 您能否帮助我测试单击表单时的“handleSubmit”事件?这是非常基本的,但对我来说弄清楚这些很重要。提前致谢!
    • 我认为你的问题在于here。我不太确定如何处理。您可以尝试mount 而不是浅的以获得更完整的组件吗?如果事件具有该功能,您还可以调整代码以仅调用preventDefault,尽管这有点调整代码以通过测试。
    • 谢谢!这是一个很大的帮助!
    猜你喜欢
    • 2019-10-30
    • 2018-04-27
    • 2016-09-15
    • 2020-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-24
    • 2017-04-18
    相关资源
    最近更新 更多