Angular is a controller testing block that promises initialization. (Jasmine)
You have a controller ExampleController
that uses a service method RequestService.data
during its initialization and you just want to check that the controller (scope) .property is set to a value in the response:
ExampleController:
app.controller('ExampleController'
, ['$scope','RequestService', function($scope, RequestService){
var ex = this;
(function initialize(){
RequestService.
data().
then(function RSresp(info){
ex.property = info.data.property;
}
})();
}]
RequestService:
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);
}
}]);
Unit test:
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;
Karma says:
"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 look like the RequestService is ever called ...
I dont know. All my tests for the RequestService pass and the application itself works ... but I can't figure out how to write a spec to reflect this.
I looked at: Unit tests promises in controllers in AngularJS
and some others that didn't turn out to be irrelevant ... but no luck
source to share
Your tests are doing too much at the moment.
The responsibility for testing your queries $http
should be a test for yours RequestService
. When testing anything that causes RequestService
, you mock RequestService
.
In general, do not execute more than 1 dependency in unit tests (so ExampleController
â RequestService
will be your limit). Your integration tests will be responsible for testing the complete 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');
});
});
});
source to share