angularjs - Testing immediately resolved $.defer() with Jasmine -
if testing code in angular uses $q , resolves such as;
angular.module('myapp.mymodule', ['ng']) .service('someservice', function($q) { this.task = function() { var deferred = $q.defer(); deferred.resolve('some value'); return deferred.promise; }; });
that might used follows;
function(someservice) { someservice.task().then(function() { console.log('resolved'); }); }
you might find runs expected in application, fails under test;
phantomjs 1.9.7 (mac os x) myapp.mymodule someservice someservice.task when invoked returned promise when invoked should call our handler failed expected spy ontaskcomplete have been called [ 'some value' ] never called.
here example test above module;
describe('myapp.mymodule', function() { describe('someservice', function() { beforeeach(function() { var suite = this; module('myapp.mymodule'); suite.injectservice = function() { inject(function(someservice) { suite.someservice = someservice; }); }; }); describe('when instantiated', function() { beforeeach(function() { this.injectservice(); }); it('should expose expected api', function() { expect(typeof this.someservice.task).toequal('function'); }); }); describe('someservice.task', function() { describe('when invoked', function() { beforeeach(function() { this.injectservice(); this.taskpromise = this.someservice.task(); }); it('should return promise', function() { expect(typeof this.taskpromise.then).toequal('function'); }); describe('returned promise', function() { describe('when invoked', function() { beforeeach(function() { this.ontaskcomplete = jasmine.createspy('ontaskcomplete'); this.taskpromise.then(this.ontaskcomplete); }); it('should call our handler immediately', function() { expect(this.ontaskcomplete).tohavebeencalledwith('some value'); }); }); }); }); }); }); });
the reason fails that—although code appears synchronous—internally $q
uses $evalasync
$scope
defer work until future call stack. since $q
has no flush
method $httpbackend
, $timeout
, , $interval
- call $rootscope.$digest()
needed achieve same result.
phantomjs 1.9.7 (mac os x): executed 3 of 3 success (0.451 secs / 0.01 secs)
here updated example test;
describe('myapp.mymodule', function() { describe('someservice', function() { beforeeach(function() { var suite = this; module('myapp.mymodule'); inject(function($rootscope) { suite.$rootscope = $rootscope; }); suite.injectservice = function() { inject(function(someservice) { suite.someservice = someservice; }); }; }); describe('when instantiated', function() { beforeeach(function() { this.injectservice(); }); it('should expose expected api', function() { expect(typeof this.someservice.task).toequal('function'); }); }); describe('someservice.task', function() { describe('when invoked', function() { beforeeach(function() { this.injectservice(); this.taskpromise = this.someservice.task(); }); it('should return promise', function() { expect(typeof this.taskpromise.then).toequal('function'); }); describe('returned promise', function() { describe('when invoked', function() { beforeeach(function() { this.ontaskcomplete = jasmine.createspy('ontaskcomplete'); this.taskpromise.then(this.ontaskcomplete); this.$rootscope.$digest(); }); it('should call our handler immediately', function() { expect(this.ontaskcomplete).tohavebeencalledwith('some value'); }); }); }); }); }); }); });
Comments
Post a Comment