使用 sinon 时不一致的 UnhandledPromiseRejectionWarning
Inconsistent UnhandledPromiseRejectionWarning when using sinon
据我所知,failApiClient
和 explicitFailApiClient
这两个对象应该具有相同的类型,并且记录它们似乎是一致的:
console.log(failApiClient) // { getObjects: [Function: getObjects] }
console.log(explicitFailApiClient) // { getObjects: [Function: getObjects] }
阅读 问题给了我正确处理这个问题所需的信息,但它没有告诉我 为什么 生成的 failApiClient
导致警告而 explicitFailApiClient
则没有。
我已将其削减到接近重建环境和展示可行替代方案所需的最低限度:
import * as sinon from 'sinon';
import 'source-map-support/register';
class LocalObject {
}
const fakeObject = new LocalObject();
const getFakeApi = (result: Promise<LocalObject[]>) = ({getObjects: () => result});
const successObjectClient = getFakeApi(Promise.resolve([fakeObject]));
// These should be equivalent, but the former causes a test error
const failApiClient = getFakeApi(Promise.reject(new Error()));
const explicitFailApiClient = {
getObjects(): Promise<LocalObject[]> {
return Promise.reject(new Error());
}
};
describe('successApiClient', () => {
before(() => {
sinon.spy(successObjectClient, 'getObjects');
});
it('does not have a warning', async () => {
// do nothing
});
});
describe('failApiClient', () => {
before(() => {
sinon.spy(failApiClient, 'getObjects');
});
it('should not have a warning', async () => {
// do nothing
});
});
describe('explicitFailApiClient', () => {
before(() => {
sinon.spy(explicitFailApiClient, 'getObjects');
});
it('does not have a warning', async () => {
// do nothing
});
});
和~/...> tsc && npm test
的结果:
> internal-api@1.0.0 test /Users/./Projects/./node/internal-api
> grunt test
Running "test" task
Running "env:dev" (env) task
Running "simplemocha:unit" (simplemocha) task
(node:72101) UnhandledPromiseRejectionWarning: Error
at Object.<anonymous> (/Users/./Projects/./node/internal-api/src/test/unit/models/mvp.test.ts:21:57)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (/Users/./Projects/./node/internal-api/node_modules/coffee-script/lib/coffee-script/register.js:45:36)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
at Module.require (module.js:596:17)
at require (internal/module.js:11:18)
at /Users/./Projects/./node/internal-api/node_modules/mocha/lib/mocha.js:222:27
at Array.forEach (<anonymous>)
at Mocha.loadFiles (/Users/./Projects/./node/internal-api/node_modules/mocha/lib/mocha.js:219:14)
at Mocha.run (/Users/./Projects/./node/internal-api/node_modules/mocha/lib/mocha.js:487:10)
at Object.<anonymous> (/Users/./Projects/./node/internal-api/node_modules/grunt-simple-mocha/tasks/simple-mocha.js:29:20)
at Object.<anonymous> (/Users/./Projects/./node/internal-api/node_modules/grunt/lib/grunt/task.js:255:15)
at Object.thisTask.fn (/Users/./Projects/./node/internal-api/node_modules/grunt/lib/grunt/task.js:73:16)
at Object.<anonymous> (/Users/./Projects/./node/internal-api/node_modules/grunt/lib/util/task.js:294:30)
at Task.runTaskFn (/Users/./Projects/./node/internal-api/node_modules/grunt/lib/util/task.js:244:24)
at Task.<anonymous> (/Users/./Projects/./node/internal-api/node_modules/grunt/lib/util/task.js:293:12)
at /Users/./Projects/./node/internal-api/node_modules/grunt/lib/util/task.js:220:11
at _combinedTickCallback (internal/process/next_tick.js:131:7)
at process._tickCallback (internal/process/next_tick.js:180:9)
at Function.Module.runMain (module.js:695:11)
at startup (bootstrap_node.js:191:16)
at bootstrap_node.js:612:3
(node:72101) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:72101) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
successApiClient
✓ does not have a warning
failApiClient
✓ should not have a warning
(node:72101) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
explicitFailApiClient
✓ does not have a warning
3 passing (14ms)
Done.
承诺可以是未解决的、已解决的或拒绝的。 "then" 用于处理决议,而 "catch" 用于处理拒绝。你在没有捕捉到它的情况下抛出一个拒绝。
尝试SomePromiseRejection().catch(err => DoSomeStuff(err))
所以在调用 explicitFailApiClient
之后有一个 .catch
块。
它们不等价。
在下面的代码中,JS 已经执行语句 Promise.reject
作为参数,这就是为什么你会得到早期警告 UnhandledPromiseRejectionWarning
.
const failApiClient = getFakeApi(Promise.reject(new Error()));
与
相比
const explicitFailApiClient = {
getObjects(): Promise<LocalObject[]> {
return Promise.reject(new Error());
}
};
调用 explicitFailApiClient.getObjects()
时将评估其 Promise.reject
。
解决方案
这是我对此事的替代解决方案。我可以只使用 Sinon 的 resolves
和 rejects
。
const getFakeApi = {getObjects: (result) => result};
const getFakeApiStub = sinon.stub(getFakeApi, 'getObjects');
describe('successApiClient', () => {
before(() => {
getFakeApiStub.resolves([fakeObject]); // success and resolves
});
it('does not have a warning', async () => {
// do nothing
});
});
describe('failApiClient', () => {
before(() => {
getFakeApiStub.rejects(new Error()); // make it failed
});
it('should not have a warning', async () => {
// do nothing
});
});
参考:
https://sinonjs.org/releases/v6.3.5/stubs/#stubresolvesvalue
希望对您有所帮助
据我所知,failApiClient
和 explicitFailApiClient
这两个对象应该具有相同的类型,并且记录它们似乎是一致的:
console.log(failApiClient) // { getObjects: [Function: getObjects] }
console.log(explicitFailApiClient) // { getObjects: [Function: getObjects] }
阅读 failApiClient
导致警告而 explicitFailApiClient
则没有。
我已将其削减到接近重建环境和展示可行替代方案所需的最低限度:
import * as sinon from 'sinon';
import 'source-map-support/register';
class LocalObject {
}
const fakeObject = new LocalObject();
const getFakeApi = (result: Promise<LocalObject[]>) = ({getObjects: () => result});
const successObjectClient = getFakeApi(Promise.resolve([fakeObject]));
// These should be equivalent, but the former causes a test error
const failApiClient = getFakeApi(Promise.reject(new Error()));
const explicitFailApiClient = {
getObjects(): Promise<LocalObject[]> {
return Promise.reject(new Error());
}
};
describe('successApiClient', () => {
before(() => {
sinon.spy(successObjectClient, 'getObjects');
});
it('does not have a warning', async () => {
// do nothing
});
});
describe('failApiClient', () => {
before(() => {
sinon.spy(failApiClient, 'getObjects');
});
it('should not have a warning', async () => {
// do nothing
});
});
describe('explicitFailApiClient', () => {
before(() => {
sinon.spy(explicitFailApiClient, 'getObjects');
});
it('does not have a warning', async () => {
// do nothing
});
});
和~/...> tsc && npm test
的结果:
> internal-api@1.0.0 test /Users/./Projects/./node/internal-api
> grunt test
Running "test" task
Running "env:dev" (env) task
Running "simplemocha:unit" (simplemocha) task
(node:72101) UnhandledPromiseRejectionWarning: Error
at Object.<anonymous> (/Users/./Projects/./node/internal-api/src/test/unit/models/mvp.test.ts:21:57)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (/Users/./Projects/./node/internal-api/node_modules/coffee-script/lib/coffee-script/register.js:45:36)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
at Module.require (module.js:596:17)
at require (internal/module.js:11:18)
at /Users/./Projects/./node/internal-api/node_modules/mocha/lib/mocha.js:222:27
at Array.forEach (<anonymous>)
at Mocha.loadFiles (/Users/./Projects/./node/internal-api/node_modules/mocha/lib/mocha.js:219:14)
at Mocha.run (/Users/./Projects/./node/internal-api/node_modules/mocha/lib/mocha.js:487:10)
at Object.<anonymous> (/Users/./Projects/./node/internal-api/node_modules/grunt-simple-mocha/tasks/simple-mocha.js:29:20)
at Object.<anonymous> (/Users/./Projects/./node/internal-api/node_modules/grunt/lib/grunt/task.js:255:15)
at Object.thisTask.fn (/Users/./Projects/./node/internal-api/node_modules/grunt/lib/grunt/task.js:73:16)
at Object.<anonymous> (/Users/./Projects/./node/internal-api/node_modules/grunt/lib/util/task.js:294:30)
at Task.runTaskFn (/Users/./Projects/./node/internal-api/node_modules/grunt/lib/util/task.js:244:24)
at Task.<anonymous> (/Users/./Projects/./node/internal-api/node_modules/grunt/lib/util/task.js:293:12)
at /Users/./Projects/./node/internal-api/node_modules/grunt/lib/util/task.js:220:11
at _combinedTickCallback (internal/process/next_tick.js:131:7)
at process._tickCallback (internal/process/next_tick.js:180:9)
at Function.Module.runMain (module.js:695:11)
at startup (bootstrap_node.js:191:16)
at bootstrap_node.js:612:3
(node:72101) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:72101) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
successApiClient
✓ does not have a warning
failApiClient
✓ should not have a warning
(node:72101) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
explicitFailApiClient
✓ does not have a warning
3 passing (14ms)
Done.
承诺可以是未解决的、已解决的或拒绝的。 "then" 用于处理决议,而 "catch" 用于处理拒绝。你在没有捕捉到它的情况下抛出一个拒绝。
尝试SomePromiseRejection().catch(err => DoSomeStuff(err))
所以在调用 explicitFailApiClient
之后有一个 .catch
块。
它们不等价。
在下面的代码中,JS 已经执行语句 Promise.reject
作为参数,这就是为什么你会得到早期警告 UnhandledPromiseRejectionWarning
.
const failApiClient = getFakeApi(Promise.reject(new Error()));
与
相比const explicitFailApiClient = {
getObjects(): Promise<LocalObject[]> {
return Promise.reject(new Error());
}
};
调用 explicitFailApiClient.getObjects()
时将评估其 Promise.reject
。
解决方案
这是我对此事的替代解决方案。我可以只使用 Sinon 的 resolves
和 rejects
。
const getFakeApi = {getObjects: (result) => result};
const getFakeApiStub = sinon.stub(getFakeApi, 'getObjects');
describe('successApiClient', () => {
before(() => {
getFakeApiStub.resolves([fakeObject]); // success and resolves
});
it('does not have a warning', async () => {
// do nothing
});
});
describe('failApiClient', () => {
before(() => {
getFakeApiStub.rejects(new Error()); // make it failed
});
it('should not have a warning', async () => {
// do nothing
});
});
参考: https://sinonjs.org/releases/v6.3.5/stubs/#stubresolvesvalue
希望对您有所帮助