监视在被拒绝的承诺中调用的函数

spying a function called in a rejected promise

我想监视一个函数,以测试当承诺被拒绝时是否在 catch 块中调用此函数。我的代码是这样的反应组件

export class ResetPassword extends Component {
    handleSubmit = e => {
        e.preventDefault();

        this.props
            .resetPassword()
            .then(() => {
                this.props.history.push(LOGIN_PATH);
            })
            .catch(({ error }) => {
                this.props.displayErrorAlert('impossible to change password. You should ask for a new reset password link',6000);
            });
    };
}

这里我想测试函数displayErrorAlert是否被调用了。我做了这个测试

it('validate form', () => {
    const resetPassword = () => {
        return Promise.reject({
            error: {
                response: {
                    data: {
                        errors: [
                            {
                                title: 'foo',
                            },
                        ],
                    },
                },
            },
        });
    };

    const displaySpy = sinon.spy();

    const wrapper = mount(
        <ResetPassword
            history={{}}
            resetPassword={resetPassword}
            displayErrorAlert={displaySpy}
        />
    );

    wrapper.instance().handleSubmit({
        preventDefault: () => {},
    });

    expect(displaySpy.calledOnce).toEqual(true);
});

间谍被调用但当然是异步的,所以我的测试总是失败。我想找到一种方法来测试该函数是否仅在调用 catch 块后才被调用,但我不知道该怎么做。

Sinon 为您提供处理 promise 时所需的一切,您可以使用 sinon.stub().

解决和拒绝存根的 promise
const resetPassword = sinon.stub();
const displayErrorAlert = sinon.spy();
const preventDefault = sinon.spy();

const props = {
  resetPassword,
  displayErrorAlert,
  history: []
};

describe('Given a component', () => {
  let component;

  describe('when rendered', () => {
    beforeAll(() => {
      component = shallow(<ResetPassword {...props} />);
    });

    describe('and the form is submitted and there is an error reseting the password', () => {
      beforeAll(() => {
        resetPassword.rejects(new Error('Oops!'));
        component.find('button').simulate('click', { preventDefault });
      });

      it('should invoke the displayErrorAlert function', () => {
        expect(displayErrorAlert.calledOnce).toBeTruthy();
      });
    });
  });
});

我找到了另一个解决方案,我 return handleSubmit 函数中的 promise 并在我的测试中使用它。

export class ResetPassword extends Component {
    handleSubmit = e => {
        e.preventDefault();

        return this.props
            .resetPassword()
            .then(() => {
                this.props.history.push(LOGIN_PATH);
            })
            .catch(({ error }) => {
                this.props.displayErrorAlert('impossible to change password. You should ask for a new reset password link',6000);
            });
    };
}

和我的测试

it('validate form', () => {
    const resetPassword = () => {
        return Promise.reject({
            error: {
                response: {
                    data: {
                        errors: [
                            {
                                title: 'foo',
                            },
                        ],
                    },
                },
            },
        });
    };

    const displaySpy = sinon.spy();

    const wrapper = mount(
        <ResetPassword
            history={{}}
            resetPassword={resetPassword}
            displayErrorAlert={displaySpy}
        />
    );

    expect.assertions(1);
    const promise = wrapper.instance().handleSubmit({
        preventDefault: () => {},
    });

    return promise.then(() => {
        expect(displaySpy.calledOnce).toEqual(true);
    });

});