Brandon Brandon - 5 months ago 34
Javascript Question

How to spyOn a service to test it -- AngularJS/Jasmine

Have tried everything I've found on the internet to make this work with no success. Trying to test a function in my service, but according to my coverage I'm never accessing it. Any help would be greatly appreciated :)

Service:

'use strict';

angular.module('Service').service('configService', function(
$rootScope, $http) {
var configObj = null;
return {

getConfig: function() {
if (configObj != null) {
console.log("returning cached config");
return configObj;
}
else {
return $http.get('conf.json').then(function(res) {
$http.get(res.confLocation).then(function(
locationResponse) {
configObj = locationResponse;
$rootScope.configObj = configObj;
console.log($rootScope.configObj);
return configObj;
});
});
}
}
};
});


getConfig is never being accessed in the tests I've tried.

ServiceTests:

'use strict';
describe('Service: configService', function() {

// load the controller's module
beforeEach(module('Service'));

var configService, $httpBackend, results, tstLocation, tstRes;
var tstConfig = {
"confLocation": "local-dev-conf.json"
};

var tstConfigEmpty = {};
var tstConfigObjEmpty = {};

var tstConfigObj = {
"AWS": {
"region": "us-east-1",
"endpoint": "http://localhost:8133"
}
};

// Initialize the controller and a mock scope
beforeEach(inject(function(_configService_, _$httpBackend_) {
inject(function($rootScope) {
$rootScope.USERNAME = 'TESTER';
$rootScope.configObj = tstConfigObj;
$rootScope.locationResponse = tstLocation;
$rootScope.res = tstRes;
});

configService = _configService_;
$httpBackend = _$httpBackend_;

//Problem here??
spyOn(configService, 'getConfig').and.callFake(function() {
return {
then: function() {
return "something";
}
};
});

}));
it('should return a promise', function() {
expect(configService.getConfig().then).toBeDefined();
});

it('should test backend stuff', inject(function() {

results = configService.getConfig(tstConfig);
$httpBackend.expectGET('conf.json').respond(tstConfig);
$httpBackend.expectGET('local-dev-conf.json').respond(tstConfigObj);
$httpBackend.flush();
}));

//Thanks Miles
it('should check if it was called', inject(function() {
results = configService.getConfig().then();
expect(configService.getConfig).toHaveBeenCalled();

});
// console.log(results);
}));

it('should check for a null configObj', inject(function() {
results = configService.getConfig(tstConfigObjEmpty).then(function() {
expect(results).toBe(null);
});
// console.log(results);
// console.log(tstConfigObj);
}));

it('should check for a non-null configObj', inject(function() {
results = configService.getConfig(tstConfigObj).then(function() {

// Any string is accepted right now -- Why??
expect(results).toEqual("returning cached config");
expect(results).toBe("returning cached config");
expect(results).toBe("your mom"); // SHOULDN'T BE WORKING BUT DOES
expect(results).toEqual("Object{AWS: Object{region: 'us-east-1', endpoint: 'http://localhost:8133'}}");
expect(results).toBe("Object{AWS: Object{region: 'us-east-1', endpoint: 'http://localhost:8133'}}");
});
// console.log(results);
// console.log(tstConfigObj);
}));

it('should check for null file', inject(function() {
results = configService.getConfig(tstConfigEmpty).then(function() {
expect(results).toEqual(null);
expect(results).toBe(null);
});
}));

it('should test a valid file', inject(function() {
results = configService.getConfig(tstConfig).then(function() {
expect(results).not.toBe(null);
expect(results).toEqual("Object{confLocation: 'local-dev-conf.json'}");
})
});


I think I'm using spyOn wrong, or not accessing getConfig in my tests properly. Thoughts?

EDIT: Here is my code coverage

EDIT 2: Changed test 3 thanks to a problem found by Miles, still no update on test coverage though. Something is wrong with my spyOn logic as Amy pointed out. I shouldn't be using callFake it seems?

EDIT 3: Got it accessing the function now thanks to Miles. Had to change my spyOn to:

spyOn(configService, 'getConfig').and.callThrough();


then add the test case:

results = configService.getConfig(tstConfig).then();
expect(configService.getConfig).toHaveBeenCalled();

Answer

You have an issue here:

results = configService.getConfig(tstConfigObj).then(function() {
  expect(results).toHaveBeenCalled();
  expect(results).toHaveBeenCalledWith(tstConfigObj);
});

getConfig takes no parameters, and neither does then. Omitting these errors, results is assigned the string "something" from then. Even if the expect statements fire, you seem to be testing if a string has been called. Try this instead:

results = configService.getConfig().then();
expect(configService.getConfig).toHaveBeenCalled();
Comments