This is great however testing mocking out angularjs service dependencies which return promises was less great!
I want to test this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
angular.module('myApp.controllers', []) | |
.controller('MyCtrl', ['$scope', 'MyService', function ($scope, MyService) { | |
//Get promise and once resolved set it in the scope | |
MyService.fetchData('foo').then(function(result) { | |
$scope.result = result; | |
}); | |
}]); |
What I wanted:
- A way to easily mock the "fetchData" service method
- Capability to assert "fetchData" was called the with right arguments ( using jasmine spies)
- The mock "fetchData" should return a promise so I can call "then" and use utilities such as $q.all
- As little boiler plate code as possible
So I wrote this little helper:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
jasmineNG = {}; | |
//set $q in your test | |
jasmineNG.$q = null; | |
//Could make similar to test a failing promise | |
jasmineNG.createPromiseReturningSpy = function(retval) { | |
return jasmine.createSpy().andCallFake(function() { | |
res = jasmineNG.$q.defer(); | |
res.resolve(retval) | |
return res.promise | |
}); | |
} |
And here is what the full test looks like:
Here is a full working jsfiddle
There's potential to expand this out having more functionality such as dealing with failing promises and giving more control over when the promise is resolved etc. If you think that's a good idea let me know in the comments.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
describe('myApp', function () { | |
var scope, | |
controller, | |
service; | |
beforeEach(function () { | |
module('myApp.controllers'); | |
}); | |
// Mock service | |
beforeEach(module(function ($provide) { | |
service = {fetchData: jasmineNG.createPromiseReturningSpy("RESULT")} | |
$provide.value('MyService', service); | |
})); | |
describe('MyCtrl', function () { | |
beforeEach(inject(function ($rootScope, $controller, $q) { | |
//IMPORTANT! set $q on the test helper | |
jasmineNG.$q = $q; | |
scope = $rootScope.$new(); | |
controller = $controller('MyCtrl', { | |
'$scope': scope | |
}); | |
})); | |
it('should call service and set result on scope', function () { | |
expect(scope.result).not.toBeDefined(); | |
expect(service.fetchData).toHaveBeenCalledWith('foo'); | |
//Call apply to propogate changes | |
scope.$apply(); | |
expect(scope.result).toBe('RESULT'); | |
}); | |
}); | |
}); |
Here is a full working jsfiddle
There's potential to expand this out having more functionality such as dealing with failing promises and giving more control over when the promise is resolved etc. If you think that's a good idea let me know in the comments.
Nice!
ReplyDeleteSince spies in Jasmine have a .andReturn function, how about adding a .andResolveWith and a .andRejectWith functions to your spy? I've done that in this gist: https://gist.github.com/matiboy/7243743
Good idea!
ReplyDeleteThe call to $q needs to be lazy to work as $q might not be injected yet.
Also I like the brevity of my approach but I think both can work together. I'll write an update. Thanks!
Thanks that's great - a nice way of organising the test structure.
ReplyDeleteAwesome look at some real test examples. Thanks for posting this. I'd love a post about how you structure the app with browserify.
ReplyDeleteOne of the reasons for AngularJS’ success is its outstanding ability to be tested. It’s strongly supported by Karma (the spectacular test runner written by Vojta Jína) and its multiple plugins. Karma, combined with its fellows Mocha, Chai and Sinon, offers a complete toolset to produce quality code that is easy to maintain, bug-free and well documented.
ReplyDeletehttp://www.credosystemz.com/training-in-chennai/best-angularjs-training-in-chennai/