Testing an angular controller that uses a service as dependencies - angularjs

Hello I have this service :
angular.module('angularProtoApp')
.factory('ModelService',['$q', '$http', function ($q, $http) {
var folder = 'assets/';
var extension = 'Model.json';
return {
getModelFromJson : function (pageCode) {
return $http({
method : 'GET',
url : folder + pageCode + extension,
headers: {'Content-Type': 'application/json'}
}).then(
function (response) {
return response.data;
}
);
}
};
}]);
And I have this controller :
angular.module('angularProtoApp')
.controller('MainCtrl', ['$scope', '$location', 'ModelService', function ($scope, $location, ModelService) {
$scope.model = '';
ModelService.getModelFromJson('Ffco').then(
function (data) {
$scope.model = data;
if ($scope.model.isSeleniumTestRunning) {
$scope.slnPageCodeClass = 'sln' + $scope.model.pageCode;
}
$location.path('/' + $scope.model.pageCode);
},
function (error){
console.log(error);
}
);
}]);
But I don't know how to correctly test the controller.
I began to do something like this, but I don't think this is enough.
describe('Controller: MainCtrl', function () {
// load the controller's module
beforeEach(module('angularProtoApp'));
var MainCtrl,
scope,
ModelServiceMock;
beforeEach(inject(function ($controller, $rootScope, _ModelService_) {
scope = $rootScope.$new();
ModelServiceMock = _ModelService_;
spyOn(ModelServiceMock, 'getModelFromJson').and.callThrough();
$controller('MainCtrl', {
$scope: scope,
ModelService : ModelServiceMock
});
}));
it('should call getModelFromJson method on ModelService', function () {
scope.$digest();
expect(ModelServiceMock.getModelFromJson).toHaveBeenCalled();
});
});
I'm not sure I test the service correctly, I did not succeed in testing the scope variables of the controller.
Does somebody know how to test it properly ?
Thanks.

Related

Passing rootScope value from one controller to another controller

I am trying to pass the value from controller to another using $rootscope what I did is first I intialize rootScope like this
app.run(function ($rootScope) {
$rootScope.emp=0 ;
});
then I am changing the value of rootScope in one of my controller like this this
app.controller("datatableController", function ($scope, DTOptionsBuilder, $http, $rootScope) {
$scope.update = function (data) {
alert(data);
$scope.message = $http.post('http://localhost:5000/api/employee/view', data).
then(function (response) {
$scope.userEdit = response.data;
$rootScope.emp=$scope.userEdit[0].id;
alert($rootScope.emp);
});
window.location.href = "updateEmployee.html";
};
});
then i am trying to access this changed $rootScope.emp value in my second controller but getting the value that i set at the time of initialization which is 0
app.controller("UpdateController", function ($scope, $http, $rootScope) {
$scope.userid=$rootScope.emp;
alert($scope.userid);
});
Try This :
app.controller("datatableController", function ($scope, DTOptionsBuilder, $http, $rootScope) {
$scope.update = function (data) {
alert(data);
$scope.message = $http.post('http://localhost:5000/api/employee/view', data).
then(function (response) {
$scope.userEdit = response.data;
$rootScope.$apply(function(){
$rootScope.emp=$scope.userEdit[0].id;
});
alert($rootScope.emp);
});
window.location.href = "updateEmployee.html";
};
});
Detailed Answer can be found here

Error: unable to get property 'call' of undefined or null reference

I am using AngularJs. When getting data from controller.js to service.js, I am getting the error. Below is the code used:
//controller.js
angular.module('testApp.controllers', []).
controller('testController', function ($scope, testAPIService, $timeout, $window, $location, $anchorScroll, $http) {
$scope.show = function() {
testAPIService.getDataSummary().success(function (response) {
console.log(response);
}).error(function (response) {
alert(response.responseText);
});
}
});
In Service.js
angular.module('testApp.services', []).
factory('testAPIService', ['$http', function ($http) {
var testAPIService = {};
testAPIService.getDataSummary = function () {
var request = {
url: urlBase + 'GetDataSummary',
method: 'Get',
headers: {
'accept': 'application/json'
}
}
return $http(request);
};
return testAPIService;
}]);
How to fix this? Thanks
This might be the result of including any of your app javascript file before the angularjs file.
Make sure you include angularjs file before the rest of your app files.
You're creating two different modules:
The first module testApp.controllers is created when you create the controller
Another module testApp.services is created when you create the service.
So the controller and the service are never part of the same module!
Try attaching to the same testApp module as follows:
app.js
// With [] means to create a new module.
angular.module('testApp', []);
controller.js
// Without [] means to retrieve an existing module.
angular.module('testApp').
controller('testController', function($scope, testAPIService, $timeout, $window, $location, $anchorScroll, $http) {
$scope.show = function() {
testAPIService.getDataSummary().success(function(response) {
console.log(response);
}).error(function(response) {
alert(response.responseText);
});
}
});
service.js
// Without [] means to retrieve an existing module.
angular.module('testApp').
factory('testAPIService', ['$http', function($http) {
var testAPIService = {};
testAPIService.getDataSummary = function() {
var request = {
url: urlBase + 'GetDataSummary',
method: 'Get',
headers: {
'accept': 'application/json'
}
}
return $http(request);
};
return testAPIService;
}]);
index.html
And change your ng-app directive to point to the testApp module
<html ng-app="testApp">

AngularJS : returning data from service to controller

I am trying to create a service to get json and pass it to me homeCtrl I can get the data but when a pass it to my homeCtrl it always returns undefined. Im stuck.
My Service:
var myService = angular.module("xo").factory("myService", ['$http', function($http){
return{
getResponders: (function(response){
$http.get('myUrl').then(function(response){
console.log("coming from servicejs", response.data);
});
})()
};
return myService;
}
]);
My Home Controller:
var homeCtrl = angular.module("xo").controller("homeCtrl", ["$rootScope", "$scope", "$http", "myService",
function ($rootScope, $scope, $http, myService) {
$scope.goData = function(){
$scope.gotData = myService.getResponders;
};
console.log("my service is running", $scope.goData, myService);
}]);
You should return promise from getResponders function, & when it gets resolved it should return response.data from that function.
Factory
var myService = angular.module("xo").factory("myService", ['$http', function($http) {
return {
getResponders: function() {
return $http.get('myUrl')
.then(function(response) {
console.log("coming from servicejs", response.data);
//return data when promise resolved
//that would help you to continue promise chain.
return response.data;
});
}
};
}]);
Also inside your controller you should call the factory function and use .then function to get call it when the getResponders service function resolves the $http.get call and assign the data to $scope.gotData
Code
$scope.goData = function(){
myService.getResponders.then(function(data){
$scope.gotData = data;
});
};
This is an example how I did for my project, it work fine for me
var biblionum = angular.module('biblioApp', []);//your app
biblionum.service('CategorieService', function($http) {
this.getAll = function() {
return $http({
method: 'GET',
url: 'ouvrage?action=getcategorie',
// pass in data as strings
headers: {'Content-Type': 'application/x-www-form-urlencoded'} // set the headers so angular passing info as form data (not request payload)
})
.then(function(data) {
return data;
})
}
});
biblionum.controller('libraryController', function($scope,CategorieService) {
var cat = CategorieService.getAll();
cat.then(function(data) {
$scope.categories = data.data;//don't forget "this" in the service
})
});

Mocking HTTP service unit test with AngularJS and Jasmine

I am attempting to build a mock service so that my unit tests can verify certain functions are called and updated accordingly. Unfortunately I cannot get this to work.
Im currently getting an error undefined is not a function on this line:
spyOn(statusService, 'getModuleStatus').andCallThrough();
My actual service looks like this:
serviceStatusServices.factory('serviceStatusAppAPIservice', function ($http) {
var serviceStatusAppAPI = {};
serviceStatusAppAPI.getModuleStatus = function () {
return $http({
method: 'JSON',
url: '/settings/getservicestatusandconfiguration'
});
}
serviceStatusAppAPI.setModuleStatus = function (module) {
return $http({
method: 'POST',
url: '/settings/setservicestatusandconfiguration',
data: { moduleId: module.ModuleId, configData: module.ConfigValues }
});
}
return serviceStatusAppAPI;
});
My update function
serviceStatusControllers.controller('serviceStatusController', ['$scope', 'serviceStatusAppAPIservice', '$filter', '$timeout', function ($scope, serviceStatusAppAPIservice, $filter, $timeout) {
$scope.update = function () {
$scope.loading = true;
serviceStatusAppAPIservice.getModuleStatus().then(function (response) {
$scope.modules = $filter('orderBy')(response.data.moduleData, 'ModuleName')
...
My tests look like this
describe('ServiceStatusController', function () {
beforeEach(module("serviceStatusApp"));
var scope;
var statusService;
var controller;
var q;
var deferred;
// define the mock people service
beforeEach(function () {
statusService = {
getModuleStatus: function () {
deferred = q.defer();
return deferred.promise;
}
};
});
// inject the required services and instantiate the controller
beforeEach(inject(function ($rootScope, $controller, $q) {
scope = $rootScope.$new();
q = $q;
controller = $controller('serviceStatusController', {
$scope: scope, serviceStatusAppAPIservice: statusService });
}));
describe("$scope.update", function () {
it("Updates screen", function () {
spyOn(statusService, 'getModuleStatus').andCallThrough();
scope.update();
deferred.resolve();
expect(statusService.getModuleStatus).toHaveBeenCalled();
expect(scope.modules).not.toBe([]);
});
});
});
Also, how do I pass any mock data returned from the service to the caller. Currently in my model I do serviceStatusAppAPI.getModuleStatus(data) then use data.Data to get out the returned JSON.
I assume if you are doing something like this in your ctrl
scope.update = function() {
serviceStatusAppAPIservice.setModuleStatus(url).then(function (data) {
scope.modules = data;
})
};
Service which returns promise
.factory('serviceStatusAppAPI', function($http, $q) {
return {
getModuleStatus: function() {
var defer = $q.defer();
$http({method: 'GET', url: '/settings/getservicestatusandconfiguration'})
.success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
defer.resolve(data);
})
.error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
window.data = data;
});
return defer.promise;
}
};
});
So in you controller you will get data like this
serviceStatusAppAPI.getModuleStatus().then(function (data) {
$scope.modules = $filter('orderBy')(data.moduleData, 'ModuleName')
})
This is how you can run your unit test case
beforeEach(function() {
var statusService = {};
module('myApp', function($provide) {
$provide.value('serviceStatusAppAPIservice', statusService);
});
statusService.modalStatus = {
moduleData: [{ModuleName: 'abc'}, {ModuleName: 'def'}]
};
inject(function ($q) {
statusService.setModuleStatus = function () {
var defer = $q.defer();
defer.resolve(this.modalStatus);
return defer.promise;
};
statusService.getModuleStatus = function () {
var defer = $q.defer();
defer.resolve(this.modalStatus);
return defer.promise;
};
});
});
beforeEach(inject(function ($rootScope, $controller, _$stateParams_) {
scope = $rootScope.$new();
stateParams = _$stateParams_;
controller = $controller;
}));
var myCtrl = function() {
return controller('ServiceStatusController', {
$scope: scope,
});
};
it('should load status', function () {
myCtrl();
scope.update();
scope.$digest();
expect(scope.modules).toBe({
status: 'active'
});
});

Angularjs factory: errors on passing $scope,$route,$http?

Why my factory below keep throwing an error when the $scope, $route, $http are present?
app.factory("factoryContacts",function($scope,$route,$http){
return {
getContacts: function(){
return $http({
method: 'GET',
url:'php/listContacts.php'
}).then(function(response) {
$scope.contacts = response.data;
});
}
};
});
can't I pass $scope, $route, $http into a factory?
I tested with this basic one and it gives me the same error,
app.provider('helloWorld', function($scope) { // note $scope is present
// In the provider function, you cannot inject any
// service or factory. This can only be done at the
// "$get" method.
this.name = 'Default';
this.$get = function() {
var name = this.name;
return {
sayHello: function() {
return "Hello, " + name + "! From Provider!!"
}
}
};
this.setName = function(name) {
this.name = name;
};
});
What should I do?
the error,
Error: [$injector:unpr] http://errors.angularjs.org/1.2.6/$injector/unpr?p0=%24scopeProvider%20%3C-%20%24scope%20%3C-%20factoryContacts ... <ng-view class="ng-scope">
can't I pass $scope, $route, $http into a factory?
why not $scope
You can't inject $scope into service/factory, its singleton and has local scope. But you can use $rootScope
To pass $route and $http use injection and write like:
app.factory("factoryContacts",['$route','$http', function($route,$http){
return {
getContacts: function(){
return $http({
method: 'GET',
url:'php/listContacts.php'
}).then(function(response) {
//....
});
}
};
}]);

Resources