I've been trying to wrap my head around Jasmine 2.0 and AngularJS promises. I know that:
done
function to replace the old runs
and waitsFor
functions$q
promises will not resolve until a digest cycle is triggeredHow can I test AngularJS promises using the new async syntax in Jasmine 2.0?
Testing in AngularJS is achieved by using the karma framework, a framework which has been developed by Google itself. The karma framework is installed using the node package manager. The key modules which are required to be installed for basic testing are karma, karma-chrome-launcher ,karma-jasmine, and karma-cli.
Promises. If you can't use async / await or you need more control, you can explicitly return a promise instead. Jasmine considers any object with a then method to be a promise, so you can use either the Javascript runtime's built-in Promise type or a library.
After your call to promise.resolve()
:
$timeout.flush()
. This will force a digest cycle and propagate the promise resolutiondone()
. This tells Jasmine the async tests have completedHere's an example (Demo on Plunker):
describe('AngularJS promises and Jasmine 2.0', function() { var $q, $timeout; beforeEach(inject(function(_$q_, _$timeout_) { // Set `$q` and `$timeout` before tests run $q = _$q_; $timeout = _$timeout_; })); // Putting `done` as argument allows async testing it('Demonstrates asynchronous testing', function(done) { var deferred = $q.defer(); $timeout(function() { deferred.resolve('I told you I would come!'); }, 1000); // This won't actually wait for 1 second. // `$timeout.flush()` will force it to execute. deferred.promise.then(function(value) { // Tests set within `then` function of promise expect(value).toBe('I told you I would come!'); }) // IMPORTANT: `done` must be called after promise is resolved .finally(done); $timeout.flush(); // Force digest cycle to resolve promises }); });
For me the $timeout.flush()
didn't work very well, but I've multiple async calls in my spec. I found the $rootScope.$apply()
, as a method to force the digest
on each async call.
describe('AngularJS promises and Jasmine 2.0', function () { beforeEach(inject(function (_$q_, _$timeout_, _$rootScope_) { $q = _$q_ $timeout = _$timeout_ $rootScope = _$rootScope_ })) it('demonstrates asynchronous testing', function (done) { var defer = $q.defer() Async.call() .then(function (response) { // Do something var d = $q.defer() Async.call() .then(function (response) { d.resolve(response) $rootScope.$apply() // Call the first digest }) return d.promise }) .then(function (response) { // Do something after the first digest Async.call() .then(function (response) { defer.resolve(response) // The original defer $rootScope.$apply() // Call the second digest }) }) defer.promise.then(function(value) { // Do something after the second digest expect(value).toBe('I told you I would come!') }) .finally(done) if($timeout.verifyNoPendingTasks()) $timeout.flush() }) })
It is like a chained async calls thing. Hope it helps the conversation. Regards
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With