Reputation: 1894
You have a controller ExampleController
which consumes a method on a service RequestService.data
during it's initialization, and you just want to test that the controllers (scope).property is set to a value in the response:
app.controller('ExampleController'
, ['$scope','RequestService', function($scope, RequestService){
var ex = this;
(function initialize(){
RequestService.
data().
then(function RSresp(info){
ex.property = info.data.property;
}
})();
}]
app.service('RequestService', ['$http', function($http){
this.data = function RSdata(){
var closure = {prop: 'val', derp: 'aderp'};
var url = 'http://aWebsite.' + closure.prop + '.com/' + closure.derp;
return $http.get(url);
}
}]);
describe('on initialization, ExampleController',function(){
var controller, injector, $httpBackend, $scope, RequestService;
beforeEach(function(){
inject(function(_$injector_, _$controller_, _$rootScope_){
injector = _$injector_;
$scope = _$rootScope_.new();
$httpBackend = injector.get('$httpBackend');
controller = _$controller_('ExampleController', {$scope : $scope});
RequestService = injector.get('RequestService');
})
})
beforeEach(function(){
$httpBackend.
when('GET', 'http://aWebsite.val.com/aderp').
respond({property: 'value'});
});
afterEach(function(){
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it('has a property "property" with a value "value" ', function(){
expect(controller.property).toBeDefined();
expect(controller.property).toBe('value');
});
});
I've tried a bunch of different things like:
expect($scope.property).toBeDefined();
or
spyOn(RequestService, 'data');
// or spyOn(RequestService, 'data').andCallThrough();
expect(controller.property).toBeDefined();
expect(RequestService.data).toHaveBeenCalled;
"Error: Unflushed requests"
or
on initialization, ExampleController has a property "property" with a value "value"
Fail: undefined is not defined.
console.log(controller)
doesn't show that the property is set, and it doesn't seem like RequestService is ever called...
I don't know. All of my tests for RequestService are passing, and the application itself works... but I can't figure out how to write the spec to reflect that.
I've looked at: Unit testing promises in controllers in AngularJS
and some others that haven't turned out to be irrelevant... but no luck
Upvotes: 3
Views: 1759
Reputation: 6940
Your tests currently try to do far too much.
The responsibility for testing your $http
requests should be the tests for your RequestService
. When testing anything that calls RequestService
, you mock the RequestService
.
In general, do not go any further than 1 dependency in unit tests (so, ExampleController
-> RequestService
would be your limit). Your integration tests will be responsible for testing the full sequence.
So your unit tests should look something like this:
describe('on initialization, ExampleController',function(){
var $q, $controller, injector, $scope, RequestService;
beforeEach(function(){
inject(function(_$q_, _$injector_, _$controller_, _$rootScope_){
$q = _$q_;
injector = _$injector_;
$controller = _$controller_;
$scope = _$rootScope_.$new();
RequestService = injector.get('RequestService');
});
});
beforeEach(function(){
spyOn(RequestService, 'data');
});
describe('with successful data retrieval', function () {
beforeEach(function () {
// mock a success
RequestService.data.andReturn($q.when({property: 'value'}));
controller = $controller('ExampleController', {$scope : $scope});
$scope.$digest(); // fulfil the promises
});
it('has a property "property" with a value "value" ', function(){
expect(controller.property).toBeDefined();
expect(controller.property).toBe('value');
});
});
describe('with failed data retrieval', function () {
beforeEach(function () {
// mock a fail
RequestService.data.andReturn($q.reject(null));
controller = $controller('ExampleController', {$scope : $scope});
$scope.$digest(); // fulfill the promises
});
it('should do something', function(){
expect('this').toBe('that');
});
});
});
Upvotes: 3