Consider the following (contrived) example:
import Promise from 'bluebird';
const resolvedPromise = () => {
return Promise.resolve('Test');
};
const asyncFunc = async (asyncResource) => {
await resolvedPromise();
await asyncResource.fetchItem();
};
describe('async/await', () => {
it('should throw an error', (done) => {
const mockAsyncResource = jasmine.createSpyObj('mockAsyncResource', ['fetchItem']);
const mockError = Promise.reject(new Error('HTTP 401 - Access Denied'));
mockAsyncResource.fetchItem.and.returnValue(mockError);
return asyncFunc(mockAsyncResource).catch(err => {
expect(err.message).toEqual('HTTP 401 - Access Denied');
done();
});
});
});
I receive the following output:
1) async/await
Unhandled rejection Error: HTTP 401 - Access Denied
... (error stack trace)
✔ should throw an error
The spec passes, but Bluebird complains about the unhandled rejection error.
Because of the blocking nature of awaits, does the mockError
report it's unhandled rejection before the second await
has a chance to call (and handle) the mockError
promise?
What is the best way to handle this scenario? I've discovered promise.suppressUnhandledRejections()
, is it as simple as using this?
I think this is a problem caused by mixing 2 different types of promises. You are creating your resolved/rejected mock promises using bluebird's Promise
but the await returns the native Promise
.
If you try the following on the chrome console, you will see it works as you expected when only using native promises:
let resolvedPromise = () => {
return Promise.resolve('Test');
};
let asyncFunc = async (asyncResource) => {
await resolvedPromise();
await asyncResource.fetchItem();
};
let mockAsyncResource = {fetchItem: () => Promise.reject(new Error("foo"))};
asyncFunc(mockAsyncResource).catch((e) => console.log('handled'))
If you want to stick with creating bluebird promises, you might need to wrap your async function with bluebird's Promise.try
, although I haven't been able to test this:
let asyncFunc = async (asyncResource) => {
return Promise.try(async () => {
await resolvedPromise();
await asyncResource.fetchItem();
});
};