Reputation: 4683
I'm trying to unit testing my Angular service using async/await
keyword in the corresponding (Jasmine) unit tests below. The test for the native Promise
works just fine, but I'm pretty much stuck in making the Angular $q
counterpart work.
angular
.module('asyncAwaitTest', [])
.factory('xService', xServiceFactory);
function xServiceFactory(
$q,
$timeout
) {
return {
getXAfter1Sec() {
return new Promise(resolve => setTimeout(() => resolve(43), 1000));
},
getXAfter1SecWithAngular$Q() {
const deferred = $q.defer();
$timeout(() => deferred.resolve(43), 1000);
return deferred.promise;
}
};
}
jasmine.DEFAULT_TIMEOUT_INTERVAL = 2000;
describe('asyncAwaitTest: x service', () => {
let $timeout;
let xService;
beforeEach(() => {
module('asyncAwaitTest');
inject(
(
_$timeout_,
_xService_
) => {
$timeout = _$timeout_;
xService = _xService_;
}
);
});
it('should work', async (done) => {
const x = await xService.getXAfter1Sec();
expect(x).toEqual(43);
done();
});
it('should work, too. but y not?!!', async (done) => {
const xPromise = xService.getXAfter1SecWithAngular$Q();
$timeout.flush();
const x = await xPromise;
expect(x).toEqual(43);
done();
});
});
Fiddle provided here: https://jsfiddle.net/glenn/gaoh6bvc/
I've tried Google but it doesn't give me a significant good lead 😞
Upvotes: 1
Views: 2143
Reputation: 10516
You could create a helper for your test that converts the promise from $q
to a native promise. Check it out here.
it('should work, too. but y not?!!', async (done) => {
const xPromise = toNativePromise(xService.getXAfter1SecWithAngular$Q());
$timeout.flush();
const x = await xPromise;
expect(x).toEqual(43);
done();
});
function toNativePromise(promise) {
return new Promise((resolve, reject) => {
promise.then(val => {
resolve(val);
}, err => {
reject(err);
});
});
}
Upvotes: 3
Reputation: 222309
async
functions are based on native promises, while AngularJS uses $q promises. await
is a syntactic sugar for chaining a promise with then
. $q promise chains are executed on digest in tests.
This cannot be fixed with
await xPromise;
$rootScope.$digest();
because $rootScope.$digest()
isn't evaluated until $rootScope.$digest()
is executed. This results in pending promise.
AngularJS shouldn't be tested with async..await
in the first place. Angular was designed to be tested synchronously.
It is
it('...', () => {
...
xPromise.then(x => {
expect(x).toEqual(43);
});
$rootScope.$digest();
});
Or promises can be flattened with jasmine-promise-matchers
:
it('...', () => {
...
expect(xPromise).toBeResolvedWith(43);
$rootScope.$digest();
});
Upvotes: 0