I am working on an angular js app with karma/Jasmine testing framework, I need to test a factory that returns a http promise but it always return undefined
here is my factory
angular.module('GithubUsers').factory('Users',['$http','$q',function($http,$q){ return{ getAllUsers:function(){ var defered= $q.defer(); $http({ url:'https://api.github.com/users', method:'GET' }).then(function(users){ defered.resolve(users.data); },function(err){ defered.reject(err); }) return defered.promise; } } }])
here is my tests
Update thanks to your answers I modified my code to the following but no I got this error
Possibly unhandled rejection: {"status":0,"config":{"method":"GET","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","url":" https://api.github.com/users?since=1 ","headers":{"Accept":"application/json, text/plain, / "},"cached":false},"statusText":""} thrown
describe('Test Users Factory',function(){ var $controller, Users, $rootScope, $httpBackend, $q; beforeEach(module('GithubUsers')); beforeEach(inject(function(_$controller_,_Users_,_$rootScope_,_$httpBackend_,_$q_){ $controller = _$controller_; Users = _Users_; $rootScope= _$rootScope_; $httpBackend=_$httpBackend_; })) it('should get users',function(){ var result; $httpBackend.whenGET('https://api.github.com/users?since=1').respond(function(){ return {data:[{id:2}],status:200}; }) Users.getAllUsers().then(function(res){ result = res; }); $httpBackend.flush(); $rootScope.$digest() expect(result).toBeTruthy(); }) })
Thanks in advance!
I think you need to pass a function that returns a array with 3 items in it, to whenGET(). respond ().
Maybe, you can try something like this:
beforeEach(angular.mock.inject(function (User, $httpBackend, $http) {
...
this.withOKUsers = function() {
var i1 = new User();
i1.id = 10;
return [200, JSON.stringify([ i1]), {}];
} ...
}));
...
it('should get users',function(){
$httpBackend
.whenGET('https://api.github.com/users')
.respond(this.withOKUsers);
Users.getAllUsers().then(function(res){
result = res;
});
$httpBackend.flush();
expect(result).not.toBeNull();
...
(I prefer to arrange spec outside of it() clause for better readability)
You're missing a $httpBackend.flush(); call after your test method call. It will invoke a success/error or then part and resolve a $q's promise properly. For more tests I would move a $httpBackend.whenGET to each test case separately so I can later verify it per use case but it's just my personal opinion.
I find it a little suspicious that you mix a $controller and a factory in one test. I would suggest to split them, and in controller test just check the calls to service methods and in a facotry test itself do a $httpBackend stuff.
Below I paste your test with my corrections. It works now for me:
describe('Test Users Factory', function () {
var Users,
$rootScope,
$httpBackend,
$q;
beforeEach(module('app.utils'));
beforeEach(inject(function (_Users_, _$rootScope_, _$httpBackend_, _$q_) {
Users = _Users_;
$rootScope = _$rootScope_;
$httpBackend = _$httpBackend_;
}));
afterEach(function () {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it('should get users', function () {
var result;
$httpBackend.when('GET', "https://api.github.com/users").respond({ data: [{ id: 2 }], status: 200 });
Users.getAllUsers().then(function (res) {
result = res;
expect(result).toBeTruthy();
});
$httpBackend.flush();
$rootScope.$digest();
});
Important notices: 1)afterEach - check if no pending requests remain after your call 2) your url differ with a parameter ?since=1. But you do not give it as a parameter in your code so i do not understand why you added this parameter. Maybe consider string concatenation with url and parameter ?
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.