当未被捕获的承诺拒绝发生时,如何在Jest中测试失败?

时间:2018-05-01 17:39:20

标签: javascript node.js unit-testing jestjs

我正在努力将测试覆盖率添加到我正在使用Jest的Node项目中。我正在测试的代码是在promises中抛出错误,导致UnhandledPromiseRejectionWarning消息被记录到控制台。

在编写测试时,我可以非常轻松地识别这些问题并解决它们,但这些警告实际上并没有导致Jest将测试标记为失败,因此我们的CI将无法捕获它。我四处寻找任何建议,但没有找到太多建议。

我确实在Node的文档中发现你可以捕获这些警告并处理它们......

process.on('unhandledRejection', (error) => {
  throw error; // Or whatever you like...
});

因此,将此代码添加到我的测试用例中似乎非常简单。毕竟,测试中抛出的Error 会导致测试失败......

describe('...', () => {
  it('...', () => {
    process.on('uncaughtRejection', (error) => {
      throw error;
    });

    // the rest of my test goes here
  });
});

不幸的是,我看到的行为是错误 被抛出,但是Jest没有捕获它并且未通过测试。相反,Jest崩溃时出现此错误,测试不会继续运行。这不太可取,似乎是不正确的行为。

uncaughtRejection处理程序之外抛出错误按预期工作:Jest记录抛出的错误并使测试失败,但不会崩溃。 (即测试观察者继续观察并运行测试)

5 个答案:

答案 0 :(得分:1)

我接近这一点的方式与我编写函数的方式密切相关 - 基本上,任何使用promises的函数都应该返回一个promise。这允许任何函数的代码调用以任何它认为合适的方式处理捕获错误。请注意,这是我的方法,我不会声称这是唯一的做法。

例如......想象一下,我正在测试这个功能:

const myFunction = () => {
    return doSomethingWithAPromise()
        .then(() => {
            console.log('no problems!');
            return true;
        });
};

测试看起来像这样:

describe('...', () => {
    it('...', () => {
        return myFunction()
            .then((value) => {
                expect(value).toBe(true);
            });
    });
});

哪个效果很好。现在如果承诺被拒绝会怎样?在我的测试中,被拒绝的承诺被传递回Jest(因为我正在返回我的函数调用的结果)并且Jest可以报告它。

相反,如果您的函数没有返回承诺,则可能需要执行以下操作:

const myOtherFunction = () => {
    doSomethingWithAPromise()
        .then(() => {
            console.log('no problems!');
            return true;
        })
        .catch((err) => {
             // throw the caught error here
             throw err;
        });
};

与上面的示例不同,Jest没有(直接)方式处理被拒绝的承诺,因为您没有将承诺传递给Jest。避免此的一种方法可能是确保函数中有catch来捕获&抛出错误,但我没有尝试过,我不确定它是否会更可靠。

答案 1 :(得分:1)

模块:

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

测试:

import { myPromise } from './module';


it('should reject the promise', () => {
  expect.assertions(1);

  const expectedError = new Error('error test');

  myPromise().catch((error) => {
    expect(error).toBe(expectedError);
  });

答案 2 :(得分:0)

从节点文档site中我们可以看到The process object is an instance of EventEmitter
使用process中的emit函数,可以在需要时以编程方式触发类似uncaughtRejectionuncaughtException的错误。

  it("should log the error", () => {
        process.emit("unhandledRejection");
        ...
        const loggerInfo = jest.spyOn(logger, "info");
        expect(loggerInfo).toHaveBeenCalled();
    });

答案 3 :(得分:0)

Jest's setupFiles中包括以下内容:

if (!process.env.LISTENING_TO_UNHANDLED_REJECTION) {
  process.on('unhandledRejection', reason => {
    throw reason
  })
  // Avoid memory leak by adding too many listeners
  process.env.LISTENING_TO_UNHANDLED_REJECTION = true
}

stipsan中的https://github.com/facebook/jest/issues/3251#issuecomment-299183885提供。

答案 4 :(得分:-1)

不确定这是否有帮助,但您也可以声明承诺拒绝

<强> index.js

module.exports = () => {
  return Promise.reject('it didnt work');
}

<强> index.spec.js

const thing = require('../src/index');

describe('rejected promise', () => {
  it('should reject with a reason', ()=> {

    return expect(thing()).rejects.toEqual('it didnt work');
   });
});