Testing with $http.backend in Angular - angularjs

I have the following controller:
(function () {
angular.module('cacApp')
.controller('mainController', function ($scope, $location, geonames) {
$scope.browseCountries =
function (path) {
$location.path(path);
};
geonames.countries()
.then(function (response) {
$scope.countries = response;
})
})
}());
and have set up the following tests for it:
describe("mainController", function () {
var _geonames, _location, _scope;
beforeEach(module('cacApp'));
beforeEach(inject(function ($controller, $injector, $httpBackend) {
_geonames = $injector.get("geonames");
_location = $injector.get("$location");
_scope = $injector.get("$rootScope").$new();
httpBackend = $httpBackend;
spyOn(_location, "path");
$controller('mainController', {
$scope: _scope,
$location: _location,
geonames: _geonames
})
}))
it("should equal a length of 250", function () {
var url = 'http://api.geonames.org/countryInfoJSON?username=steveyz';
var httpResponse = [{}];
httpBackend.expectGET(url).respond(200, httpResponse);
expect(_geonames.countries.length).toBe(250);
})
})
The "$scope.countries" response from running geonames.countries() returns an array of 250 objects, and a $scope.countries.length of 250.
I want to test to verify that the length of the response is actually 250 in my code. But when I run the test currently, I get the error "Expected 0 to be 250."
Is there a specific reason why my result is showing 0 instead of 250?

Related

Method undefined in Angular JS service unit test

I am writing unit tests for my existing AngularJS app. There are just four methods in this service. I was able to getFollowUpList to work, but refresh() is not working and it is a very simple method.
The refresh method should simply set deferredGetFollowUpList = null and return true in my test.
There error I'm getting is: TypeError: Cannot read property 'then' of undefined, so my refresh method is undefined. Why is this the case? Thanks
Service
(function () {
"use strict";
angular
.module("all.patient.details")
.factory("followUpListService", ["$rootScope", "$http", "userContext", "$q", "$uibModal", "htmlBaseUrl", FollowUpListService]);
function FollowUpListService($rootScope, $http, userContext, $q, $uibModal, htmlBaseUrl) {
var deferredGetFollowUpList = null;
return {
getFollowUpList: getFollowUpList,
displayModal: displayModal,
refresh: refresh,
save: save
}
function refresh() {
deferredGetFollowUpList = null;
}
}
})();
Unit Test
describe("followUpListService", function () {
beforeEach(module("all.patient.details"));
var followUpListService = {};
var $httpBackend;
var htmlBaseUrlMock;
var returnedFollowUpListData;
var deferredGetFollowUpList;
var $rootScope;
var $q;
var $uibModal;
beforeEach(function () {
htmlBaseUrlMock = { format: function () { } };
module(function ($provide) {
$provide.value("htmlBaseUrl", htmlBaseUrlMock);
});
inject(function (_$rootScope_, _$httpBackend_, _$q_, _$uibModal_, _followUpListService_) {
$rootScope = _$rootScope_;
$httpBackend = _$httpBackend_;
$q = _$q_;
$uibModal = _$uibModal_;
followUpListService = _followUpListService_;
});
});
afterEach(function () {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it("calls refresh()", function () {
followUpListService.refresh()
.then(function (data) {
deferredGetFollowUpList = data;
});
expect(deferredGetFollowUpList).toBe(null);
});
As deferredGetFollowUpList is service level variable, Can you write your test as -
followUpListService.deferredGetFollowUpList = data; //Any Mock Data
followUpListService.refresh();
expect(followUpListService.deferredGetFollowUpList).toBe(null);

Mocking $httpBackend on controller initialisation with unknown json data

When mocking using $httpBackend, How do I create the mock when I do not know exactly the type of data being returned. I want the http call to be on controller initialsation. One caveat is that it will be a json object being returned.
(function () {
'use strict';
angular
.module('app')
.service('dataService', dataService);
function dataService($http) {
this.getMovies = getMovies;
////////////////
function getMovies() {
return $http.get('./src/app/movies/data.json')
.then(function (response) {
return response.data
})
}
};
})();
;
(function () {
'use strict';
angular.module('app')
.controller('moviesController', moviesController);
moviesController.$inject = ['dataService'];
function moviesController(dataService) {
var vm = this
vm.movies;
vm.getMovies = getMovies;
getMovies();
function getMovies() {
return dataService.getMovies()
.then(function (data) {
return vm.movies = data.movies;
});
}
};
}());
;
describe('moviesController', function () {
var $controller,
moviesController,
dataService,
$httpBackend;
beforeEach(angular.mock.module('app'));
beforeEach(angular.mock.module('ui.router'));
beforeEach(inject(function (_$controller_, _dataService_, _$httpBackend_) {
$controller = _$controller_;
dataService = _dataService_;
$httpBackend = _$httpBackend_;
moviesController = $controller('moviesController', { dataService: dataService });
}))
it('should be defined', function () {
expect(moviesController).toBeDefined();
});
it('should initialise with a call to dataService.getMovies()', function () {
var url = "./src/app/movies/data.json";
var movies = {};
$httpBackend.expectGET(url).respond(200, movies);
moviesController.getMovies();
expect(moviesController.movies).toEqual(movies);
$httpBackend.flush();
});
});
;
Expected undefined to equal Object({ }).
You can set the return to be an object you define in the spec.
var response = {};
it('should initialise with a call to dataService.getMovies()', function () {
$httpBackend.expectGET("./src/app/movies/data.json").respond(response);
$httpBackend.flush();
});

Angular karma testing controller

I'm trying to figure out these karma tests to test my Angular app. I can figure out simple things. But I am having problems with one that connects to my database.
I am wanting to test the $scope.getMultipleOptions function in the controller below:
$scope.options = [];
$scope.getMultipleOptions("form_field_1", $scope.options);
$scope.getMultipleOptions = function (key, opts) {
var id = key.replace("form_field_", "");
var promise = DynamicFormFactory.GetData('/DynamicForm/GetMultipleOptions?form_field_id=" + id);
promise.then(
function (success) {
angular.forEach(success, function (o) {
opts.push(o);
});
},
function (error) {
// Error
}
);
}
This is what my factory/service looks like:
dynamicFormApp.factory('DynamicFormFactory', ['$http', function ($http) {
return {
GetData: function (url) {
return $http.get(url)
.then(function (response) {
return response.data;
}, function (error) {
return error;
});
}
}]);
And this is what I've done to set up my karma test
describe('DynamicFormController', function () {
beforeEach(module('dynamicFormApp'));
var $controller;
var $rootScope;
beforeEach(inject(function (_$controller_, _$rootScope_) {
// The injector unwraps the underscores (_) from around the parameter names when matching
$controller = _$controller_;
$rootScope = _$rootScope_;
}));
describe('$scope.getMultipleOptions', function () {
var $scope, controller;
beforeEach(function () {
$scope = $rootScope.$new();
controller = $controller('DynamicFormController', { $scope: $scope });
$scope.fields = [];
});
it('$scope.getMultipleOptions', function () {
var key = "form_field_15";
var expectedResult = [{ desc: "DESCRIPTION", id: "ID" }];
$scope.getMultipleOptions(key, $scope.fields);
expect($scope.fields).toEqual(expectedResult);
});
});
});
The test always fails as $scope.fields is always empty. How do I do this?

Angular unit testing Controller with service

I'm trying to write a unit test using karma and jasmine for an Angular controller that depends on a service
storesController.js
(function () {
var app = angular.module('storesController', ['storesService']);
app.controller('StoresListController', function ($scope, StoresService) {
$scope.getStores = function () {
StoresService.getStores().then(function (data) {
$scope.stores = data.data;
});
};
$scope.getStores();
$scope.deleteStore = function (id) {
StoresService.deleteStore(id).then(function () {
$scope.getStores();
});
};
});
storesService.js
(function () {
var app = angular.module('storesService', []);
app.factory('StoresService', ['$http', function ($http) {
var stores = [];
stores.getStores = function () {
return $http.get(/api/getStores');
};
stores.deleteStore = function (storeID) {
return $http.delete(/api/deleteStore/'+storeID);
};
return stores;
}]);
})();
And the test,
controllers.spec.js
describe('StoresController', function () {
beforeEach(module('storesController'));
var scope;
var storesServiceMock;
var controller;
beforeEach(inject(function ($controller, $rootScope) {
storesServiceMock = {
getStores: function() {
},
deleteStores: function() {
}
};
spyOn(storesServiceMock, 'getStores').and.returnValue({name : 'TestName', country : 'TestCountry'})
scope = $rootScope.$new();
controller = $controller('StoresListController', {
$scope: scope, StoresService: storesServiceMock
});
}));
it('scope.stores should be defined', function () {
expect(scope.stores).toBeDefined;
});
});
And I'm getting
TypeError: StoresService.getStores(...).then is not a function at n.$scope.getStores
I've also tried width httpBackend but I'm not be able to make it work, any clue about what I'm doing wrong?
Have the spy return a promise.
With ES2015:
spyOn(storesServiceMock, 'getStores').and.returnValue(Promise.resolve({name : 'TestName', country : 'TestCountry'}));
With $q:
spyOn(storesServiceMock, 'getStores').and.callFake(function() {
var deferred = $q.defer();
deferred.resolve({name : 'TestName', country : 'TestCountry'}));
return deferred.promise;
});

Testing an http request where in success call another function with jasmine

I have a controller with an http request. On success it calls another function and I do not know how to test it. I am new to angular.
var app = angular.module('myApp', ['']);
app.controller('MainController', ['$scope', '$http', function ($scope, $http) {
$scope.source = '';
$scope.destination = '';
var selectedFiles = [];
$scope.deleteFiles = function(source) {
if (source == $scope.source) {
selectedFiles = selectedFilesSource;
} else if (source == $scope.destination) {
selectedFiles = selectedFilesDestination;
}
$http({
method: 'POST',
url: 'deleteFiles.php',
data:
{
"sourcePath": source,
"selectedFiles": selectedFiles
}
}).success(function(data) {
if (source == $scope.source) {
$scope.showFiles(source, 'source');
} else if (source == $scope.destination) {
$scope.showFiles(source, 'destination');
}
});
};
My testing file is like that:
describe("Testing to MainController", function(){
beforeEach(module('myApp'));
var mainController, scope, httpBackend, http;
beforeEach(inject(function($controller, $rootScope, $httpBackend, $http) {
scope = $rootScope;
httpBackend = $httpBackend;
http = $http;
httpBackend.when('POST', 'deleteFiles.php', function(data){return{"sourcePath": "source", "selectedFiles": ''}})
.respond(?????);
mainController = $controller('MainController', {
$scope: scope,
$http: http
});
}));
it('should call showFiles if sourcepath is source', function() {
scope.source = 'files/set1';
scope.deleteFiles('files/set1');
httpBackend.expectPOST('deleteFiles.php');
httpBackend.flush();
expect(scope.showFiles).toHaveBeenCalled();
});
});
Error message: Expected a spy, but got Function.
I do not how to use spy in here and I do not understand what should I have in httpBackend .respond
When you promise is resolved successfully then $scope.showFiles(source, 'source'); function is called. So create a spy on showFiles.
it('should call showFiles if sourcepath is source', function() {
spyOn(scope, 'showFiles');
scope.source = 'files/set1';
scope.deleteFiles('files/set1');
httpBackend.expectPOST('deleteFiles.php');
httpBackend.flush();
expect(scope.showFiles).toHaveBeenCalled();
});
it('', function() {
spyOn(scope, 'showFiles');
scope.source = 'files/set1';
scope.deleteImages('images/set1');
// rest of your test ...
});

Resources