defining current state in unit tests - angularjs

I've moved this 'reports' feature from a single module (called 'aam') into the core, so that other modules (such as 'bbc') can use it.
Now I'm rewriting the unit test(s).
The grunt error I'm getting is
should go state aam.reports with URL_NOT_SPECIFIED
reports-state spec
TypeError: 'null' is not an object
(evaluating 'BbpcConfiguration.getProperty(configProperty).then')
which indicates to me that $state is empty or not structured correctly.
Here is the report controller:
(function() {
'use strict';
angular.module('com.ct.bbpcCore')
.controller('reportController', ['$window', '$state', 'BbpcUserService', 'BbpcConfiguration', function ($window, $state, BbpcUserService,BbpcConfiguration) {
angular.element(document).ready(function () {
//Get url base on locale
var reportUrl = "URL_NOT_SPECIFIED";
var currentState = $state.current.name;
var configProperty = "";
var title = "";
if (currentState.indexOf('aam.reports')) {
configProperty = 'report.aam.link';
title = "AAM.REPORT";
};
if (currentState.indexOf('bbc.reports')) {
configProperty = 'report.bbc.link';
title = "BBC.REPORT";
};
BbpcConfiguration.getProperty(configProperty).then(function(response) {
if (response) {
var language = BbpcUserService.getLanguageCd() || "en_CA";
reportUrl = response[language] || reportUrl;
}
var spec = "width=" + $window.outerWidth + ", height=" + $window.outerHeight;
$window.open(reportUrl, title, spec);
});
});
}]);
}());
And here is report-controller.spec:
describe('reports-state spec', function() {
'use strict';
var $injector, $window, $rootScope,
$state, BbpcConfiguration, reportController, $controller, BbpcUserService;
beforeEach(function() {
module('com.ct.bbpcCore', function($provide) {
$provide.value('BbpcConfiguration', BbpcConfiguration = {
getProperty: function(key){
if('report.aam.link' === key){
return {
"fr_CA": "https://eng-link",
"en_CA": "https://fre-link"
};
}
return null;
}
});
});
inject(function(_$injector_) {
$injector = _$injector_;
$window = $injector.get('$window');
$state = $injector.get('$state');
$rootScope = $injector.get('$rootScope');
$controller =$injector.get('$controller');
BbpcUserService =$injector.get('BbpcUserService');
});
});
it('should go state aam.reports with URL_NOT_SPECIFIED', function() {
$state.current = {'name': 'aam.reports' };
spyOn($window, 'open').andCallFake(function(){});
reportController = $controller('reportController', {'$window':$window, '$state':$state, 'BbpcUserService':BbpcUserService, 'reportLink':undefined});
$state.go('aam.reports');
$rootScope.$apply();
expect($state.current.name).toEqual('aam.reports');
expect($window.open).toHaveBeenCalledWith('URL_NOT_SPECIFIED', 'AAM.REPORT', 'width=0, height=0');
});
});
I tried simply adding the line $state.current = {'name': 'aam.reports' }; in the 'it' block, but that's not what it's looking for.
Not sure how to debug unit tests. :P I can't use a console.log($state) to peek into it.

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;
};
});

How to use a service defined in another module than the controller calling it?

I have a module with a service defined:
var ngError = angular.module('ngError', []);
ngError.service('ErrorService', ['$scope', function($scope) {
$scope.displayErrors = function(errors) {
alert(errors);
}
}]);
Then I have another module:
var ngLogin = angular.module('ngLogin', ['ngError']);
Which has a controller that attempts to use the first service defined on ngError:
ngLogin.controller('LoginCtrl', ['$scope', 'LoginService', 'ErrorService', function($scope, LoginService, ErrorService) {
$scope.user = {};
$scope.user.id = 0;
$scope.user.token = '';
$scope.login = function(callback) {
LoginService.login($scope.user.username, $scope.user.password, function(token) {
$scope.setToken(token);
$scope.$apply();
if (typeof callback === 'function') {
callback(callback);
}
}, function(errors) {
ErrorService.displayErrors(errors);
});
};
}]);
But some reason this is throwing the following error:
Unknown provider: $scopeProvider <- $scope <- ErrorService
You cannot use $scope within a service. Change the service as follows and it will work:
var ngError = angular.module('ngError', []);
ngError.service('ErrorService', [function() {
this.displayErrors = function(errors) {
alert(errors);
}
}]);
Try like this , working best for me
var app = angular.module('MyApp', []);
app.service('MyService', function () {
var property = 'First';
this.myFunc = function (x) {
return x*5;
}
});
//
controller 2 under second app module
var app = angular.module('AnotherApp',[]);
app.controller("AnotherAppCtrl", function($scope,MyService) {
$scope.value = MyService.myFunc(4);
});

Jasmine Testing angularjs controller

I am trying to test my controller but I get undefined when running karma start
This is my controller Code:
(function() {
'use strict';
angular
.module('tariffOptionsExtras')
.controller('tariffOptionsExtrasBookCtrl', tariffOptionsExtrasBookCtrl);
tariffOptionsExtrasBookCtrl.$inject = ['tariffOptionsExtrasSrv', '$location', 'cache', 'authSrv', '$stateParams',
'tariffOptionsExtrasBookSrv', 'minimumDuration', '$rootScope', 'userTypes', 'messageCtrl', '$state'];
function tariffOptionsExtrasBookCtrl(tariffOptionsExtrasSrv, $location, cache, authSrv, stateParams, tariffOptionsExtrasBookSrv, minimumDuration, $rootScope, userTypes, messageCtrl, $state) {
var vm = this;
var cacheName = 'tariffOptionsExtras';
var cacheCollection = cache.getCollection(cacheName);
vm.date = new Date();
vm.minimumDuration = minimumDuration;
//if statement commented out. prepaid users should be able to enter the flow.
Date(vm.bookOption.startDate)
}
if (!vm.bookOption) {
$state.go(pagesConfig.tariffOptionsExtras.name);
} else {
vm.infoLink = vm.bookOption.infoUrl;
}
/**
* Runs booking tarif extra post and in case of success the view is changed
*/
vm.book = function() {
//If bookoption not present, redirect to chooser
tariffOptionsExtrasBookSrv.bookTariffExtra(vm.bookOption).then(function(response) {
$rootScope.$broadcast('transactionFinished');
var item = response['salesOrderVBO'][0]['orderItems']['orderItem'][0];
if (item.product.action == 'BOOKED') {
vm.success = true;
}
}, function(reason) {
vm.errorMessage = reason.data.faultMessage;
});
};
vm.success = false;
vm.subscription = authSrv.getUserContract();
vm.msisdn = vm.subscription.subscription.msisdn;
}
})();
Unit Test with jasmine
describe('tariffOptionsExtras module', function() {
describe('tariffOptionsExtrasBook Controller', function() {
var tariffOptionsExtrasBookCtrl, tariffOptionsExtrasSrv, tariffOptionsExtrasBookSrv, authSrv;
// Step 1: Import the module this controller belongs to, and its dependencies
beforeEach(function() {
module('app.common');
module('tariffOptionsExtras');
});
// Step 2: Mock any service that initially used when the controller instantiate
// beforeEach(module(function($provide) {
// $provide.factory('tariffOptionsExtrasBookSrv', function() {
// var getSync;
// getBookedExtras = function() {
// return {
// then:function(){}
// };
// };
// getTariffBookableOptions = function() {
// return {
// then:function(){}
// };
// };
// return {
// getBookedExtras: getBookedExtras,
// getTariffBookableOptions:getTariffBookableOptions
// };
// });
// }));
beforeEach(module(function($provide) {
$provide.factory('authSrv', function() {
getUserContract = function() {
return {
subscription:{
msisdn:'491741660390',
mboName:'27434975'
},
contract:{
mboName:'27434975',
ban:'106491816',
}
};
};
return {
getUserContract: getUserContract,
};
});
}));
// Step 3: Inject $controller with its dependencies
beforeEach(function() {
// 1. Import the module
module('app');
// 2. Inject $controller
inject(function($controller, $rootScope, _authSrv_, _tariffOptionsExtrasSrv_, _tariffOptionsExtrasBookSrv_) {
authSrv = _authSrv_;
tariffOptionsExtrasSrv = _tariffOptionsExtrasSrv_;
tariffOptionsExtrasBookSrv = _tariffOptionsExtrasBookSrv_;
// 3. Use $controller to instantiate the controller
tariffOptionsExtrasBookCtrl = $controller('tariffOptionsExtrasBookCtrl', {
'authSrv': authSrv,
'tariffOptionsExtrasSrv': tariffOptionsExtrasSrv,
'tariffOptionsExtrasBookSrv': tariffOptionsExtrasBookSrv
});
});
});
// Step 4: Test the controller
it('Should return sum of 1+1', function() {
expect(1+1).toBe(2);
});
});
});
When running karma Start I get this screen:
enter image description here
Also when I comment this block of code it works:
tariffOptionsExtrasBookCtrl = $controller('tariffOptionsExtrasBookCtrl', {
'authSrv': authSrv,
'tariffOptionsExtrasSrv': tariffOptionsExtrasSrv,
'tariffOptionsExtrasBookSrv': tariffOptionsExtrasBookSrv
});
first you have to inject the $controller param must be enclosed with underscores
then assign it to the $controller variable as this example
beforeEach(inject(function ($rootScope, _$controller_) {
scope = $rootScope.$new();
$controller = _$controller_;
$controller('nameController', {$scope: scope});
}));

How to test vm.variable - function(){..} unit testing with jasmine?

I am using karma- jasmine framework to test my angular application. I'm facing a problem in calling the functions of the controller or service form my test-spec. I tried using controller. as well as scope. but both of them didn't work for me.
The controller code is
(function () {'use strict';
angular.module('selfUi').controller('AttendeesController', AttendeesController);
AttendeesController.$inject = ['$state', '$stateParams', 'AttendeeService', 'settings', '$log'];
function AttendeesController($state, $stateParams, AttendeeService, settings, $log) {
var vm = this;
if ($stateParams.attendeeData === null) {
vm.pageType = "Add Attendee";
vm.isEdit = false;
} else {
var tempAttendee = $stateParams.attendeeData;
vm.pageType = "Edit Attendee";
vm.isEdit = true;
vm._id = tempAttendee._id;
vm.firstName = tempAttendee.firstName;
vm.lastName = tempAttendee.lastName;
}
vm.checkAvailable = function(email){
//Check email
if(email === null || angular.isUndefined(email) || email.trim().length === 0){
vm.invalidEmail = true;
}else{
// Check if email is already present or not
success = function(data, status, headers, config) {
if(data[0].success){
vm.validEmail = true;
}else{
if(data[0].message){
modalData = {
success : false,
};
}else{
vm.validEmail = false;
}
}
};
failure = function(data, status, headers, config) {
vm.invalidEmail = false;
};
AttendeeService.checkEmail(email, success, failure);
}
};
} })();
My test spec is:
describe('AttendeesController', function(){
beforeEach(module('SS'));
var state, $stateParams, stateParams, settings, AttendeeService, log;
var email= "temp#email.com";
var controller, $scope;
var vm;
$stateParams= {_id : "1",
attendeeType : "attendee",
firstName : "Pen",
lastName : "Red",
email : "temp#email.com",
company : "SWG",
jobTitle : "Speaker",
biography : "bio",
tagsInterest : "interests"}
beforeEach(inject(function($rootScope, _AddAttendeeService_, $controller, $state, $stateParams,settings, $log) {
AttendeeService= _AttendeeService_;
state= $state;
$scope = $rootScope.$new();
controller = function() {
return $controller('AttendeesController', {
$scope : scope,
$stateParams : $stateParams
});
};
}));
it('should be instantiated', function() {
expect(AttendeeService).toBeDefined();
});
it('should have controller.methods defined', function(){
expect(controller).toBeDefined();
expect(controller.checkAvailable).toBeUndefined();
controller.checkAvailable(email);
});
});
My service code looks like this:
(function() {
'use strict';
angular.module('SS').service('AttendeeService', AttendeeService);
AttendeeService.$inject = ['SSFactory', 'settings', '$rootScope'];
function AttendeeService(SelfSFactory, settings, $rootScope){
this.addAttendee = function(data, success, failure){
var responsePromise = SelfServiceFactory.httpPostRequest(settings.createAttendeeURL, data, config);
responsePromise.success(success);
responsePromise.error(failure);
return responsePromise;
};
}});
When I run my test spec, it gives me a error
TypeError: 'undefined' is not a function (evaluating 'controller.checkAvailable(email)')
at C:/Users/IBM_ADMIN/WebstormProjects/Self/self-service-ui.git/src/tests/addAttendees.controller.spec.js:53
I tried calling the checkAvailable function with the scope variable too, but it didn't work. I need to know how to call such methods in the controller from my test spec.

Angularjs and qunit testing

I have a angularjs web application and want to use qunit for unit testing in it. I have a controller:
function RootCtrl($scope, $rootScope, $window, $location) {
// logger is empty at the start
$scope.logger = '';
// we have no login error at the start
$scope.login_error = '';
//
// Get values array of object
//
$rootScope.values = function (obj) {
var vals = [];
for( var key in obj ) {
if(key !== '$$hashKey' && key !== 'checked')
vals.push(obj[key]);
}
return vals;
}
}
Now i want to write unit test for values function with qunit. I included all js files to the test/index.html and qunit.css. Now my test.js has following content:
var injector = angular.injector(['ng', 'myApp']);
var init = {
setup : function () {
this.$scope = injector.get('$rootScope').$new();
}
}
module('RootCtrl', init);
test('RootCtrl', function(){
var $controller = injector.get('$controller');
$controller('RootCtrl', {
$scope : this.$scope,
$location : this.$location
});
equal(['value'], $controller.values({'key' : 'value'}))
});
But i'm getting error: http://docs.angularjs.org/error/$injector/unpr?p0=$rootElementProvider%20%3C-%20$rootElement%20%3C-%20$location%20%3C-%20$route at:
$controller('RootCtrl', {
$scope : this.$scope,
$location : this.$location
});
How to inject correctly controller and use $scope, $rootScope, $location and another services from it?
Thank you.
Try this instead of your controller
$controller('RootCtrl',['$scope', '$rootScope', '$location','$route', function ($scope, $rootScope, $location, $route) {
$scope : this.$scope,
$location : this.$location
}]);
Had similar problem, so since no other answer here.
I ended up using:
client side code:
var myApp= angular.module('myApp', []);
myApp.controller('myCtrl', function ($scope) {
//angular client side code
$scope.canSubmit = function () {
//some logic
return true;
}
}
Qunit tests:
var ctrl, ctrlScope, injector;
module("Testing the controller", {
setup: function () {
angular.module('myApp');
injector = angular.injector(['ng', 'myApp']);
ctrlScope = injector.get('$rootScope').$new();
ctrl = injector.get('$controller')('myCtrl', { $scope: ctrlScope });
ctrlScope.model = {
//model object
};
},
teardown: function () {
}
});
test("Given something happened then allow submit", function () {
ok(ctrlScope.someFunction(...), "some functionality happened");
equal(true, ctrlScope.canSubmit());
});
This blog post was useful.
One can easily inject more into the controller under test.

Resources