如何在与Jest的捕获语句中重新遇到错误

发布于 2025-01-18 05:01:11 字数 2268 浏览 1 评论 0原文

我有一个返回承诺的函数,但是我想测试它的捕获量定义,然后测试它会重新犯错。

这是一个非常人为的例子,但这是显示问题的最清晰方法。在我的实际代码中,我调用了一个被模拟失败的函数(与此示例中的手动拒绝),并且我在catch语句中还有其他登录,该语句解释了重新启动错误。

const foo = () => {
  return new Promise((resolve, reject) => {
    reject(new Error('reject')); // manually rejecting to mimic actual code...
  }).catch(error => {
    // do some additional logging...
    throw error;
  });
};

it('should catch and re-throw error', () => {
  // Received function did not throw
  // and
  // Unhandled promise rejection
  expect(() => foo()).toThrow();

  // Test passes, even when `throw error` is commented out with false positive
  expect(foo()).rejects.toThrow();
});

我可以成功检查记录功能是否被调用,但无法弄清楚如何确保在此之后重新遇到错误。

工作更新:)

感谢 @skyboyer & @bergi 让我对问题有所不同,并将我暴露于

下面的一些更好的点是显示记录功能的更新代码,也是我解决的更新测试在。

导致此问题的问题无法

  • 测试记录,由于重新遇到的错误
  • 无法测试重新

捕获错误的错误值的错误使我可以做到这两个。

我本来要留在recupts.toequal测试中,但是现在似乎多余了...

对任何反馈感兴趣!再次感谢!

// myModule.js
export const logging = () => {};
export const bar = () => new Promise(resolve => {});
export const foo = () => {
  return bar().catch(error => {
    logging();
    throw error;
  });
};

describe('myModule', () => {
  let fooReturn;

  beforeEach(() => {
    jest.clearAllMocks();

    jest.spyOn(myModule, 'bar').mockImplementation(() => {
      return Promise.reject({ error: 'bar error' });
    });

    jest.spyOn(myModule, 'logging').mockImplementation(() => {});

    fooReturn = myModule.foo();
  });

  it('should catch and re-throw error', () => {
    expect.assertions(1);
    fooReturn.catch(result => expect(result).toEqual({ error: 'bar error' }));

    // removed since the above test covers that the promise was rejected
    // return fooReturn.rejects.toEqual(expect.anything());
  });

  it('should call the loggin method', async () => {
    expect.assertions(1);

    // prevents UnhandledPromiseRejectionWarning
    fooReturn.catch(() => {});

    expect(myModule.logging).toBeCalled();
  });
});

I have a function that returns a promise, but I want to test that it has a catch defined, and then additionally test that it re-throws the error.

This is a very contrived example but it was the clearest way to show the issue. In my actual code, I am calling a function that is mocked to fail (vs the manually rejecting in this example), and I have additional logging in the catch statement, which explains the re-throwing of the error.

const foo = () => {
  return new Promise((resolve, reject) => {
    reject(new Error('reject')); // manually rejecting to mimic actual code...
  }).catch(error => {
    // do some additional logging...
    throw error;
  });
};

it('should catch and re-throw error', () => {
  // Received function did not throw
  // and
  // Unhandled promise rejection
  expect(() => foo()).toThrow();

  // Test passes, even when `throw error` is commented out with false positive
  expect(foo()).rejects.toThrow();
});

I can successfully check that the logging function is called, but can't figure out how to ensure the error is re-thrown after.

WORKING UPDATE :)

thanks to @skyboyer & @Bergi for getting me to think about the issue a bit differently, and exposing me to some of the finer points of jest

Below is both the updated code to show the logging function, and the updated tests i settled on.

The issues that led to this were

  • unable to test logging was called due to the error being re-thrown
  • unable to test the value of the error being re-thrown

Catching the rejected promise allowed me to do both.

I was going to leave in the rejects.toEqual test, but it seems redundant now...

interested in any feedback! and thanks again!

// myModule.js
export const logging = () => {};
export const bar = () => new Promise(resolve => {});
export const foo = () => {
  return bar().catch(error => {
    logging();
    throw error;
  });
};

describe('myModule', () => {
  let fooReturn;

  beforeEach(() => {
    jest.clearAllMocks();

    jest.spyOn(myModule, 'bar').mockImplementation(() => {
      return Promise.reject({ error: 'bar error' });
    });

    jest.spyOn(myModule, 'logging').mockImplementation(() => {});

    fooReturn = myModule.foo();
  });

  it('should catch and re-throw error', () => {
    expect.assertions(1);
    fooReturn.catch(result => expect(result).toEqual({ error: 'bar error' }));

    // removed since the above test covers that the promise was rejected
    // return fooReturn.rejects.toEqual(expect.anything());
  });

  it('should call the loggin method', async () => {
    expect.assertions(1);

    // prevents UnhandledPromiseRejectionWarning
    fooReturn.catch(() => {});

    expect(myModule.logging).toBeCalled();
  });
});

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

柒七 2025-01-25 05:01:11

您错过了返程

https://jestjs.io/docs/asynchronous#resolves--rejects

一定要返回断言 - 如果省略此 return 语句,您的测试将在 fetchData 返回的 Promise 得到解析之前完成,然后()有机会执行回调。

您的测试应该是

it('should catch and re-throw error', () => {
  return expect(foo()).rejects.toEqual(expect.anything());
});

你/Bergi 注意到 async/await 它可能看起来更简洁:

it('should catch and re-throw error', async () => {
  await expect(foo()).rejects.toEqual(expect.anything());
});

但如果我们错过在 expect 之前添加 await,我们将遇到与版本中完全相同的问题1 没有返回。所以要小心。

You missed return.

https://jestjs.io/docs/asynchronous#resolves--rejects

Be sure to return the assertion—if you omit this return statement, your test will complete before the promise returned from fetchData is resolved and then() has a chance to execute the callback.

Your test should be

it('should catch and re-throw error', () => {
  return expect(foo()).rejects.toEqual(expect.anything());
});

As u/Bergi noticed with async/await it may look more laconic:

it('should catch and re-throw error', async () => {
  await expect(foo()).rejects.toEqual(expect.anything());
});

but if we miss to add await before our expect we will have exact the same issue as in version 1 without return. So beware.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文