Unit Test for controller in AngularJs Failed - angularjs

Here is my controller:
'use strict';
angular.module('pulseOneApp')
.config(function ($stateProvider) {
$stateProvider.state('about', {
url: '/about',
views: {
'content': {
templateUrl: 'components/version/about.html',
controller: 'AboutController'
}
},
authNotRequired: true
});
})
.controller('AboutController', ['$scope', '$state', 'session', '$pulseOneProps', '$filter', 'propertiesServices', function ($scope, $state, session, $pulseOneProps, $filter, propertiesServices) {
/**
* #function getServerVersion
* #description gets the serverVersion from $pulseOneProps if exist, else makes a REST Api call using propertiesServices.
* #returns string
*/
var getServerVersion = function () {
var systemProperties,serverVersion;
if ((angular.isDefined($pulseOneProps)) && $pulseOneProps !== null) {
systemProperties = $pulseOneProps.getProperties();
if(systemProperties) {
return $filter('filter')(systemProperties, {name: 'server_version'})[0].value;
}
else{
//when the session exist and not able to retrieve $pulseOneProps then do REST Api call and update the systemProperties
session.validateSession().then(function() {
propertiesServices.getPulseOneProperties().then(function (systemProperties) {
serverVersion=$filter('filter')(systemProperties, {name: 'server_version'})[0].value;
// This will update the UI when serverVersion is available
$scope.serverVersion = (serverVersion) ? serverVersion: false;
});
});
}
}
return null; // if none of the above cases are valid then don't display the server version.
};
var serverVersion=getServerVersion();
$scope.serverVersion = (serverVersion) ? serverVersion: false;
$scope.goTo = function() {
session.validateSession().then(function() {
$state.go('app.dashboard');
})
.catch(function() {
$state.go('login');
});
};
}]);
and Here is my Unit Test for this controller to make sure the function goTo is the function:
'use strict';
describe('Controller: AboutCtrl', function () {
// load the controller's module
beforeEach(module('ui.router'));
beforeEach(module('ps.authentication.services'));
beforeEach(module('ps.version'));
beforeEach(module('pulseOneApp'));
beforeEach(module('ps.components.properties'));
var scope, AboutController;
// Initialize the controller and a mock scope
beforeEach(inject(function ($rootScope, _$controller_) {
scope = $rootScope.$new();
AboutController = _$controller_('AboutController', {
$scope: scope
});
scope.$digest();
}));
it('should find to goTo function', function () {
expect(typeof scope.goTo).toBe('function');
});
});
The unit test is failed and I don't know what was wrong with this unit test.
Any suggestion what was the issue here.
Note : The error message is : scope is undefined.
Thanks in advance
-k

Related

I want to share data stored in variable from one controller to another

I have data in one controller and now I want to share it with another but both controller has different modules. I have used $rootscope but it didn't work. I have used service it also didn't work. link here Service
Is there any other way to do. I have spent one week for this please help me.
toolbar.controler
(function ()
{
'use strict';
angular
.module('app.toolbar')
.controller('ToolbarController', ToolbarController);
function ToolbarController($rootScope, $mdSidenav, msNavFoldService, $translate, $mdToast, $location, $localStorage, $http, $scope)
{
var vm = this;
vm.name = $localStorage.name;
vm.userId = $localStorage._id;
vm.readNotifications = function(notifId){
$http({
url: 'http://192.168.2.8:7200/api/readNotification',
method: 'POST',
data: {notificationId: notifId, userId: vm.userId}
}).then(function(res){
vm.rslt = res.data.result1;
console.log(vm.rslt);
vm.refresh();
$location.path('/sharedwishlistdetails');
}, function(error){
alert(error.data);
})
}
}
})();
The data stored here in vm.reslt.
toolbar.module.js
(function ()
{
'use strict';
angular
.module('app.toolbar', [])
.config(config);
/** #ngInject */
function config($stateProvider, $translatePartialLoaderProvider)
{
$translatePartialLoaderProvider.addPart('app/toolbar');
}
})();
Now I want that result for this controller.
sharedwishlistdetails.controller.js
(function ()
{
'use strict';
angular
.module('app.sharedwishlistdetails')
.controller('SharedWishlistDetailsController', SharedWishlistDetailsController);
/** #ngInject */
//NotificationsController.$inject = ['$http', '$location'];
function SharedWishlistDetailsController($http, $location, $localStorage, $rootScope, $scope)
{
var vm = this;
vm.uid = $localStorage._id;
}
})();
shareddata.service.js
(function ()
{
'use strict';
angular
.module('app.core')
.factory('shareData', shareDataService);
/** #ngInject */
function shareDataService($resource,$http) {
var shareData = {};
return shareData;
}
})();
write a service in 'app.toolbar' module
angular.module('app.toolbar').service('ServiceA', function() {
this.getValue = function() {
return this.myValue;
};
this.setValue = function(newValue) {
this.myValue = newValue;
}
});
In your toolbarController , inject ServiceA and set data -
vm.readNotifications = function(notifId){
$http({
url: 'http://192.168.2.8:7200/api/readNotification',
method: 'POST',
data: {notificationId: notifId, userId: vm.userId}
}).then(function(res){
vm.rslt = res.data.result1;
ServiceA.setValue(vm.rslt);
console.log(vm.rslt);
vm.refresh();
$location.path('/sharedwishlistdetails');
}, function(error){
alert(error.data);
})
}
Now write another service for 'app.sharedwishlistdetails' module -
angular.module('app.sharedwishlistdetails',['app.toolbar']).service('ServiceB', function(ServiceA) {
this.getValue = function() {
return ServiceA.getValue();
};
this.setValue = function() {
ServiceA.setValue('New value');
}
});
Now inject ServiceB in your SharedWishlistDetailsController controller and access data -
var sharedData = ServiceB.getValue();
How could $rootScope failed in your code it would be appreciated if you paste your code: never mind here is an example that will help you out:
All applications have a $rootScope which is the scope created on the HTML element that contains the ng-app directive.
The rootScope is available in the entire application.If a variable has the same name in both the current scope and in the rootScope, the application use the one in the current scope.
angular.module('myApp', [])
.run(function($rootScope) {
$rootScope.test = new Date();
})
.controller('myCtrl', function($scope, $rootScope) {
$scope.change = function() {
$scope.test = new Date();
};
$scope.getOrig = function() {
return $rootScope.test;
};
})
.controller('myCtrl2', function($scope, $rootScope) {
$scope.change = function() {
$scope.test = new Date();
};
$scope.changeRs = function() {
$rootScope.test = new Date();
};
$scope.getOrig = function() {
return $rootScope.test;
};
});

Unit test controller

I make an ionic app and it finish but when i start to add tests to it I face a problem with $resources ,in this case I have this Controller :
.controller('newAccountCtrl', function($scope, $window, $rootScope, API, $ionicPopup, $state) {
$scope.newData = {};
$scope.$on('$ionicView.enter', function() {
$scope.newData = {};
});
$scope.newInfo = function() {
API.newAccountInfo().update({ restCode: $scope.newData.restore_code }, $scope.newData, function(res, header) {
$rootScope.popup('success', "OKAY");
$window.location.href = '#/login';
}, function(err) {
if (err.data == null)
$rootScope.popup("Error", "no connection");
else
$rootScope.popup('error', err.data.error);
});
}
})
and in the service i make a request using $resources in function :
angular.module('starter.services', [])
.factory('API', function($rootScope, $resource, $ionicPopup, $ionicLoading, $window) { return {
newAccountInfo: function() {
return $resource(base + '/restoreinfo/:restCode', { restCode: '#_restCode' }, {
update: {
method: 'PUT'
}
}, {
stripTrailingSlashes: false
});
}}});
and in the my test the following code:
describe('newAccountCtrl', function() {
var controller,
deferredLogup, scope, $q;
beforeEach(angular.mock.module('starter'));
// TODO: Load the App Module
beforeEach(module('starter.controllers'));
beforeEach(module('starter.services'));
// TODO: Instantiate the Controller and Mocks
beforeEach(inject(function($controller, _$q_, $rootScope, _API_) {
$q = _$q_;
scope = $rootScope.$new();
API = _API_;
spyOn(API, 'newAccountInfo').and.callThrough(function(callback) {
deferredLogup.promise.then(callback);
return { $promise: deferredLogup.promise };
});
controller = $controller('newAccountCtrl', {
'$scope': scope,
API: API
});
}));
it('#newAccountInfo', function() {
scope.newInfo();
expect(API.newAccountInfo.update).toHaveBeenCalled();
}) });
but I get the error :
Expected a spy, but got undefined.
What I misunderstand here, the code work perfect
just macke factory return the resources direct and remove the functions .

Lazy loading angular services using require.js

I can lazy load a controller by doing the following,
Step1: Add an additional config...
rootModule.config([
"$controllerProvider", function($controllerProvider) {
rootModule.registerController = $controllerProvider.register;
}
]);
Step2: Define the controller against the registerController defined in step 1
angular.module("rootModule").registerController("authController",
function ($scope, $location, $rootScope, authService) {
$scope.userName = "";
$scope.userPwd = "";
$scope.authenticate = function ()...
$scope.testFunction = function ()...
});
Step3: load the controller during routing by doing this,
rootModule
.config([
'$routeProvider',
function ($routeProvider) {
$routeProvider.when('/',
{
templateUrl: 'templates/Login.html',
resolve: {
load: ["$q", function($q) {
var defered = $q.defer();
require(["Controllers/authController"], function() {
defered.resolve();
});
return defered.promise;
}]
}
}).
Now, the problem is I have a service called "authService", which I would like to lazy load, how to do it? Here is the service...
define(function() {
angular.module("rootModule").service("authService", function ($http) {
return {
/////Something code here//////
});
});
It was very simple in the end, thanks to this great blog written by Dan Wahlin.
To load a service in run time according to the routing, I had to do this...
Step 1: Get a reference to $provide.service() method in my rootModule's (module which contains the routing info) config...
rootModule.config(["$controllerProvider","$provide",
"$controllerProvider", "$filterProvider","$compileProvider", function ($controllerProvider, $provide) {
rootModule.registerController = $controllerProvider.register; //for controllers
rootModule.registerService = $provide.service; //for services
rootModule.registerFilter = $filterProvider.register; //for filters
rootModule.registerDirective = $compileProvider.directive; //for directives
rootModule.registerFactory = $provide.factory; //for factory
}
]);
Step 2: Register the service to be loaded dynamically
define(function() {
angular.module("rootModule").registerService("reviewReportsService", function () {
return {
sampleData: "This is some sample data"
}
});
});
Step 3: Resolve the service script file, to load when the respective route is loaded
when('/ReviewAndSubmit',
{
controller: "reviewAndSubmitController",
templateUrl: "templates/ReviewAndSubmit.html",
resolve: {
load: ["$q", function ($q) {
var defered = $q.defer();
require(["Controllers/reviewAndSubmitController"], function () {
defered.resolve();
});
require(["Services/reviewReportsService"], function () {
defered.resolve();
});
return defered.promise;
}]
}
})
Hope this helps someone....

angular modal ui bootstrap unit test - undefined is not a function

APP
(function() {
'use strict';
function ArticlesController($templateCache, $modal, articlesData, Articles, $state) {
var articles = this;
articles.data = articlesData.data;
console.log($modal);//Give me LOG: Object{open: function () { ... }}
articles.open = function (article) {
var modalInstance = $modal.open({ // The unit test point to this line
template: $templateCache.get('articles/templates/modalDestroy.html'),
controller: 'ArticleDestroyController',
controllerAs: 'article',
size: 'sm',
resolve: {
articleData: function(){
return article;
}
}
});
modalInstance.result.then(function (article) {
Articles.destroy(article._id).then(function(response) {
var data = [];
angular.forEach(articles.data, function(value, key) {
if( value._id !== article._id){
this.push(value);
}
}, data);
articles.data = data;
})
.catch(function(response) {
console.log(response);
});
});
};
}
function ArticleDestroyController($modalInstance, articleData, Articles) {
var article = this;
article.data = articleData;
article.ok = function () {
$modalInstance.close(articleData);
};
article.cancel = function () {
$modalInstance.dismiss('cancel');
};
}
angular.module('articles.controllers', [])
.controller('ArticlesController', ArticlesController)
.controller('ArticleDestroyController', ArticleDestroyController);
})();
TEST
'use strict';
/* global describe, beforeEach, it, before, after, afterEach, inject, expect, spyOn */
describe('Unit: ArticlesController', function() {
var $rootScope, $scope, $controller;
beforeEach(function() {
module('articles');
});
var fakeModal = {
result: {
then: function(confirmCallback, cancelCallback) {
//Store the callbacks for later when the user clicks on the OK or Cancel button of the dialog
this.confirmCallBack = confirmCallback;
this.cancelCallback = cancelCallback;
}
},
close: function( item ) {
//The user clicked OK on the modal dialog, call the stored confirm callback with the selected item
this.result.confirmCallBack( item );
},
dismiss: function( type ) {
//The user clicked cancel on the modal dialog, call the stored cancel callback
this.result.cancelCallback( type );
}
};
beforeEach(inject(function($modal) {
spyOn($modal, 'open').and.callFake(fakeModal);
}));
beforeEach(inject(function(_$rootScope_,_$controller_, $modal){
$rootScope = _$rootScope_;
$scope = $rootScope.$new();
$controller = _$controller_;
var articlesData = {data:[{title:'my title',content:'my content'}]};
$controller('ArticlesController as articles', {$scope: $scope, $modal: $modal, articlesData:articlesData});
}));
it('articles.data should create an array with at least one article object ', function() {
expect($scope.articles.data.length).toBe(1);
$scope.articles.open($scope.articles.data[0]);
});
});
When I run gulp unit
I've got
TypeError: undefined is not a function
at ArticlesController.articles.open
point to line 9
var modalInstance = $modal.open
but if I try to check $modal it gives me
console.log($modal);//Give me LOG: Object{open: function () { ... }}
Do you see what's the problem ?
spyOn($modal, "open").and.callFake(function() {
return fakeModal;
});
Ran into this exact issue at work and resolved it in this way based on the documentation for Jasmine 2.0(http://jasmine.github.io/2.0/introduction.html).

Resolve not resolved before loading controller

I am trying to fetch the value from server side before any controller loads. I am using resolvers to achieve this. Since fetched value needs to be visible to all controllers I extended routeConfig on the following way:
'use strict';
angular.module('myApp', [.....]).
config(['$routeProvider', function ($routeProvider) {
var universalResolves = {
user: function(User, $q, $rootScope) {
var deffered = $q.defer();
User.query({},
function (users) {
deffered.resolve(
$rootScope.activeUser = users[0]
)
}, function(){
deffered.reject();
}
);
return deffered.$promise;
}
};
var customRouteProvider = angular.extend({}, $routeProvider, {
when: function(path, route) {
route.resolve = (route.resolve) ? route.resolve : {};
angular.extend(route.resolve, universalResolves);
$routeProvider.when(path, route);
return this;
}
});
customRouteProvider.when('/users', {
templateUrl: 'partials/users.html',
controller: 'UserController'
});
customRouteProvider.otherwise({redirectTo: '/home'});
}]);
But when I try to print activeUser from the controller I am getting 'undefined'.
.controller('UserController', ['$scope', function ($scope) {
console.log($scope.activeUser.id);
.....
};
Here I am getting the following error:
TypeError: Cannot read property 'id' of undefined.
Why the value is not resolved before loading controller?
There is no such property $promise of deferred object, it is promise:
user: function(User, $q, $rootScope) {
var deffered = $q.defer();
User.query({}, function(users) {
deffered.resolve($rootScope.activeUser = users[0]);
}, function() {
deffered.reject();
});
return deffered.promise;
// ^ don't put $ here
}
Also it's better to inject resolved user to controller then using $rootScope:
.controller('UserController', ['$scope', 'user', function ($scope, activeUser) {
console.log(activeUser.id);
};
An finally just for better codding style, this assignment
$rootScope.activeUser = users[0]
is a little confusing. It's more readable:
$rootScope.activeUser = users[0];
deffered.resolve(users[0]);

Resources