Jest - 函数不调用其子异步函数

Jest - function not calling its child async function

我正在用 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 was not called'。所以我的问题是,为什么 service.validateUser 没有被调用,即使 handleLoginSubmit 被成功调用?我相信这与异步有关?测试 Login 的身份验证功能的正确方法是什么?

问题是您 expected 不是模拟方法。你应该期待这样的模拟方法:

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