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

cod*_*123 27 mocking promise reactjs jestjs enzyme

代码

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

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

测试

 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');
      });
 });
Run Code Online (Sandbox Code Playgroud)

嘲笑

export const createUser = function() {
  return new Promise((resolve, reject) => {
    reject('error');
  });
};
Run Code Online (Sandbox Code Playgroud)

测试确实强制代码进入方法中的捕获。所以状态确实被设置为“错误”。

但是在我的测试中,它没有按照我的预期进行操作,而是在测试状态更改之前等待 Promise 拒绝。我不确定在这里尝试什么,我应该使用 async/await 吗?

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

And*_*iol 20

你应该做这样的事情:

it('rejects...', () => {
  const Container = createUserContainer(CreateUser);
  const wrapper = shallow(<Container />);  
  return expect(wrapper.instance().handleFormSubmit()).rejects.toEqual('error');
});
Run Code Online (Sandbox Code Playgroud)

我认为这样更干净。您可以在官方文档中看到这种方法。

  • 这是检查异步错误的官方方法。这应该是公认的答案。 (2认同)
  • 注意:可能应该使方法异步并在期望之前添加等待(请参阅链接的官方文档) (2认同)

Cas*_*son 18

测试失败,因为它不知道主题是异步的。它可以通过使用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');
      });
 });
Run Code Online (Sandbox Code Playgroud)

旧样式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();
      });
 });
Run Code Online (Sandbox Code Playgroud)

异步测试参考

expect.assertions 参考

  • 如果函数没有抛出异常,这个测试不会给出误报吗? (5认同)
  • @oyalhi 不,它不会给出误报。`expect.assertions(1)` 行告诉 jest 将有一个断言,因此如果未触发 `catch`,jest 会抱怨缺少断言 (3认同)

Hri*_*odi 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;
    });
};
Run Code Online (Sandbox Code Playgroud)

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

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

  • 这并没有解决问题。代码仍然进入 catch,但测试仍然不会等待 Promise 履行后再运行期望 (3认同)