如何使用Jest正确测试被拒绝的承诺?

时间:2018-06-12 16:24:32

标签: reactjs promise mocking jestjs enzyme

代码:

import { createUser } from '../services';
...
...

handleFormSubmit = () => {  
  this.setState({ loading: true });
  createUser()
    .then(() => {
      this.setState({
        loading: false,
      });
    })
    .catch(e => {
       this.setState({
         error: e,
       });
    });
};

测试:

 it('rejects...', () => {
    const Container = createUserContainer(CreateUser);
    const wrapper = shallow(<Container />);  

    return wrapper.instance().handleFormSubmit()
      .catch(e => {
         console.log("State: ", wrapper.state());
         expect(e).toEqual('error');
      });
 });

模拟

export const createUser = function() {
  return new Promise((resolve, reject) => {
    reject('error');
  });
};

测试会强制代码进入方法中的catch。因此,州确实设置为错误&#39;。

但是在我的测试中,它没有做我期望的事情,等待Promise在测试状态变化之前拒绝。 我不确定在这里尝试什么,我应该使用async / await吗?

所以我想等待的createUser方法,但我不确定我的实现是否允许这个

5 个答案:

答案 0 :(得分:2)

测试失败,因为它不知道主题是异步的。可以通过使用done参数或使用测试函数async来修复它。

请注意,还需要设置预期断言的数量,以使即使未执行catch分支,测试也将失败。

async / await样式:

 it('rejects...', async () => {
    expect.assertions(1);
    const Container = createUserContainer(CreateUser);
    const wrapper = shallow(<Container />); 

    await wrapper.instance().handleFormSubmit()
      .catch(e => {
         console.log("State: ", wrapper.state());
         expect(e).toEqual('error');
      });
 });

旧式done参数:

 it('rejects...', done => {
    expect.assertions(1);
    const Container = createUserContainer(CreateUser);
    const wrapper = shallow(<Container />);  

    wrapper.instance().handleFormSubmit()
      .catch(e => {
         console.log("State: ", wrapper.state());
         expect(e).toEqual('error');
         done();
      });
 });

Asynchronous Testing Reference

expect.assertions reference

答案 1 :(得分:1)

已经有点晚了,但是您可以执行以下操作:

it('rejects...', () => {
  const Container = createUserContainer(CreateUser);
  const wrapper = shallow(<Container />);  

  expect(wrapper.instance().handleFormSubmit()).rejects.toEqual('error');
});

我认为这样更干净。您可以凭此方法here

答案 2 :(得分:0)

在您的代码handleFormSubmit中,函数应返回Promise,您可以在其中等待测试。此外,您还需要从成功和错误回调中返回真实数据,以分别解决和拒绝承诺。

handleFormSubmit = () => {  
  this.setState({ loading: true });
  return createUser()
    .then(() => {
      this.setState({
        loading: false,
      });
      return true;
    })
    .catch(e => {
       this.setState({
         error: e,
       });
       throw e;
    });
};

在您的实际代码中,您已捕获catch处理程序中的错误,并尝试在测试用例代码中进一步捕获它。因此catch无法进一步链接,而您可以多次链接then

供参考,请参阅Promise文件: https://www.peterbe.com/plog/chainable-catches-in-a-promise

答案 3 :(得分:0)

您的代码看起来正确。您为什么说它不等待承诺否决?我唯一要做的就是利用Jest的模拟功能,因此进行更改

模拟

export const createUser = function() {
  return new Promise((resolve, reject) => {
    reject('error');
  });
};

测试

jest.mock('../services');
const services = require('../services');

const createUser = jest.spyOn(services, "createUser");
createUser.mockRejectedValue("error");

...

it('rejects...', () => {

不需要单独的Mock文件

答案 4 :(得分:-1)

我使用过这种方法:

test('example of rejection with fetch', () => {
  global.fetch = jest.fn(() => Promise.reject('rejected'))

  return expect(
    someFunctionUtilizingFetch()
  ).rejects.toThrowErrorMatchingSnapshot()
})

编辑(适用于您的问题):

return expect(
    wrapper.instance().handleFormSubmit()
).rejects.toThrowErrorMatchingSnapshot()