Reputation: 185
I am new to Angular testing.
I am trying to test a simple method in a service that gets some data via an ajax call and returns a promise using Jasmine.
So far very unsuccessfully.
This is the method I am testing:
function getDefaultFibonnacci() {
var deferred = $q.defer();
$http({ method: 'GET', url: '/api/fibonnacci/get' })
.success(function (data) {
deferred.resolve(data);
})
.error(function (data, status) {
deferred.reject(status);
});
return deferred.promise;
}
This is my test code: (Please note all other tests pass apart from 'should return 0,1,1,2,3'
describe('datacontext', function () {
var $httpBackend;
var $rootScope;
var datacontext;
var $q;
beforeEach(function () {
module('app');
inject(function (_$httpBackend_, _$rootScope_, _$q_, _datacontext_) {
$httpBackend = _$httpBackend_;
$rootScope = _$rootScope_;
datacontext = _datacontext_;
$q = _$q_;
});
});
it('should have a getDefaultFibonnacci() function', function () {
expect(angular.isFunction(datacontext.getDefaultFibonnacci)).toBe(true);
});
it('should return a promise', function () {
expect(datacontext.getDefaultFibonnacci().then).toBeDefined();
});
it('should return 0,1,1,2,3', function () {
var sequence = '123';
$httpBackend.when('GET', 'app/dashboard/dashboard.html').respond('');
$httpBackend.when('GET', '/api/fibonnacci/get').respond('0,1,1,2,3');
var deferred = $q.defer();
var promise = deferred.promise;
promise.then(function (response) {
sequence = response.success;
});
datacontext.getDefaultFibonnacci().then(function (data) { deferred.resolve(data); });
$rootScope.$digest();
expect(sequence).toEqual('0,1,1,2,3');
});
});
Guys thanks for all your comments. I learnt a lot through this exercise.
This is the code I ended up with for a passing test.
function getDefaultFibonnacci() {
return $http({ method: 'GET', url: '/api/fibonnacci/get' });
}
it('should return 0,1,1,2,3', function () {
var sequence;
$httpBackend.whenGET('app/dashboard/dashboard.html').respond('');
$httpBackend.expectGET('/api/fibonnacci/get').respond('0,1,1,2,3');
datacontext.getDefaultFibonnacci().then(function (data) {
sequence = data.data;
});
$httpBackend.flush();
expect(sequence).toEqual('0,1,1,2,3');
});
Upvotes: 3
Views: 2509
Reputation: 19098
$httpBackend
has a flush()
method for exactly this reason.
flush()
simulates the http server responding, so it will trigger the resolution of your $http.get()
. Until you call flush()
, nothing will happen (the server hasn't responded yet).
As such, replace your $rootScope.digest()
code with $httpBackend.flush()
and work from there.
Furthermore, you can save a lot of effort by understanding that $http
methods themselves return promises.
This:
function getDefaultFibonnacci() {
var deferred = $q.defer();
$http({ method: 'GET', url: '/api/fibonnacci/get' })
.success(function (data) {
deferred.resolve(data);
})
.error(function (data, status) {
deferred.reject(status);
});
return deferred.promise;
}
Can be simplified to this:
function getDefaultFibonnacci() {
return $http({ method: 'GET', url: '/api/fibonnacci/get' })
}
And will do the same thing.
Finally you don't need another promise in your test. This is enough (remove all reference to $q
and deferred and put this directly after your $httpBackend.when(...
code):
datacontext.getDefaultFibonnacci()
.then(function (data) {
sequence = data;
});
Upvotes: 4
Reputation: 7809
The most important think you forgot to do is call $httpBackend.flush()
at some point after making the requests before using the data.
Also you don't need to create an extra promise.
it('should return 0,1,1,2,3', function () {
var sequence;
// Use the shorthand method whenGET
$httpBackend.whenGET('app/dashboard/dashboard.html').respond('');
// We should probably test that this request is actually made, so use expect<method>
$httpBackend.expectGET('/api/fibonnacci/get').respond('0,1,1,2,3');
// Leave out the extra promise code.
// var deferred = $q.defer();
// var promise = deferred.promise;
// promise.then(function (response) {
// sequence = response.success;
// });
// datacontext.getDefaultFibonnacci().then(function (data) { deferred.resolve(data); });
datacontext.getDefaultFibonnacci().then(function (response) {
sequence = response.success;
});
$httpBackend.flush(); // Flush the backend. Important!
// $rootScope.$digest(); // I don't think this is necessary.
expect(sequence).toEqual('0,1,1,2,3');
});
The html template won't be called if you set up your app
Upvotes: 1
Reputation: 2584
Are you expecting an object {success: "0,1,1,2,3"} as the response from the http service? You're using response.success
when promise resolved
promise.then(function (response) {
sequence = response.success;
});
whereas you're returning a string '0,1,1,2,3'
$httpBackend.when('GET', '/api/fibonnacci/get').respond('0,1,1,2,3');
Also, from the code I see that you don't need to create another promise to test your method.
Try this:
it('should return 0,1,1,2,3', function () {
var sequence = '123';
$httpBackend.when('GET', 'app/dashboard/dashboard.html').respond('');
$httpBackend.when('GET', '/api/fibonnacci/get').respond('0,1,1,2,3');
datacontext.getDefaultFibonnacci().then(function (data) { sequence = data; });
$rootScope.$digest();
expect(sequence).toEqual('0,1,1,2,3');
});
Upvotes: 1