开玩笑-函数未调用其子异步函数

时间:2018-06-23 00:13:57

标签: javascript reactjs jestjs mobx

我正在用Jest为我的React Login组件编写单元测试。该组件具有一个handleLoginSubmit方法,该方法在提交表单时被调用。此方法实际上是在我的store中定义的,并且引用被传递到Login组件。

store.js:

handleLoginSubmit = async (event) => {
    event.preventDefault();
    const result = await service.validateUser(this.username, this.password);
    if (result) {
        this.isAuthenticated = true;
        this.invalidLogin = false;
        history.push('/search');
    }
    else this.invalidLogin = true;
}

我已经编写了测试用例,以检查提交表单时Login组件是否调用handleSubmit以及认证是否正确完成:

login.test.js

describe('Login should authenticate users corectly when', () => {

    it('correct credentials are submitted', async () => {
        const spySubmit = jest.spyOn(store, 'handleLoginSubmit');
        const spyValidate = jest.spyOn(service, 'validateUser');
        const wrapper = shallow(<Login store={store} />);
        expect(spySubmit).toHaveBeenCalledTimes(0);
        wrapper.find('form').simulate('submit');
        expect(spySubmit).toHaveBeenCalledTimes(1);
        expect(spyValidate).toBeCalledWith({ username: store.username, password: store.password });
    });
});

service.js:

export function validateUser(username, password) {
    return fetch(`https://abc.co/api?search=${username}`)
        .then(function (response) {
            return response.json();
        }).then(function (response) {
            if (response.results.length) {
                if (response.results[0].key === password) {
                    return true;
                }
                else return false;
            }
            else return false;
        });
}

但是测试失败,并显示消息“未调用spyValidate”。所以我的问题是,即使service.validateUser被成功调用了,为什么没有调用handleLoginSubmit呢?我相信这与异步有关吗?测试Login的身份验证功能的正确方法是什么?

1 个答案:

答案 0 :(得分:1)

问题是您expect所拥有的不是模拟方法。您应该期望这样的模拟方法:

expect(store.handleLoginSubmit).toHaveBeenCalledTimes(0)

,与其他expect类似。

在测试用例的最后,您应该通过调用.mockRestore()来还原模拟方法:

store.handleLoginSubmit.mockRestore()

如果在此之后您仍然遇到异步调用问题,那么我的建议是使您的测试更加...单元测试:您应该将测试分为2个测试用例,一个用于测试store.handleLoginSubmit是否是在提交表单后调用,另一种方法是测试store.handleLoginSubmit中的内容,

test('.handleLoginSubmit() called when form is submitted', () => {
  jest.spyOn(store, 'handleLoginSubmit').mockImplementation(() => {})
  const wrapper = shallow(<Login store={store} />);
  wrapper.find('form').simulate('submit');
  expect(store.handleLoginSubmit).toBeCalled()
  store.handleLoginSubmit.mockRestore()
})

test('.handleLoginSubmit()', async () => {
  jest.spyOn(service, 'validateUser')
    .mockImplementation(() => Promise.resolve(true))
  await store.handleLoginSubmit({preventDefault: () => {}})
  expect(service.validateUser).toBeCalled()
  service.validateUser.mockRestore()
})