AngularJS Controller Unit Testing - angularjs

I new in AngularJS and try Unit Testing.I am using Karma and Jasmine. I created the first test for my controller but its not working and I don't know why karma throughs an error.
So please help me out this.
BasicTabCtrl.js
// Basic Tab Controller
myApp.controller('BasicTabCrtl', ['$scope', '$modal', 'BasicTabService', function ($scope, $modal, BasicTabService) {
console.log("BAsic tab crtl");
$scope.name = 'testing';
$scope.tab1 = "BASIC";
$scope.tab2 = "ADVANCE";
$scope.tab3 = "FORM";
$scope.user = {};
// get user from service
$scope.Tablelist = BasicTabService.getUser();
// delete user
$scope.deleteUser = function (obj) {
console.log("OBJ => " + JSON.stringify(obj));
if (obj != -1) {
$scope.Tablelist.splice(obj, 1);
}
}
}]);
Here is my test case
example.js
describe('myApp',function(){
var scope,controller;
beforeEach(function(){
module('myApp');
});
describe('BasicTabCrtl',function(){
beforeEach(inject(function($rootScope,$controller){
scope = $rootScope.$new();
controller=$controller('BasicTabCrtl',{
'$scope':scope
});
console.log("d");
}));
it('set the name',function(){
expect(scope.name).toBe('testing');
});
});
});
Error
26 05 2016 20:47:50.890:INFO [watcher]: Changed file "/home/rahul/Documents/django_project/myfirstsite/test/example.js".
Firefox 46.0.0 (Ubuntu 0.0.0) myApp BasicTabCrtl set the tab1 name FAILED
minErr/<#/home/rahul/Documents/django_project/myfirstsite/static/js/angular.js:68:12
loadModules/<#/home/rahul/Documents/django_project/myfirstsite/static/js/angular.js:4587:15
forEach#/home/rahul/Documents/django_project/myfirstsite/static/js/angular.js:322:11
loadModules#/home/rahul/Documents/django_project/myfirstsite/static/js/angular.js:4548:5
createInjector#/home/rahul/Documents/django_project/myfirstsite/static/js/angular.js:4470:19
workFn#/home/rahul/Documents/django_project/myfirstsite/static/js/angular-mocks.js:2954:44
TypeError: scope is undefined in /home/rahul/Documents/django_project/myfirstsite/test/example.js (line 19)
#/home/rahul/Documents/django_project/myfirstsite/test/example.js:19:3
Firefox 46.0.0 (Ubuntu 0.0.0): Executed 1 of 1 (1 FAILED) ERROR (0.023 secs / 0.018 secs)

I believe the injection isn't working because of missing _ around angular methods
describe('myApp',function(){
var scope,controller;
beforeEach(function(){
module('myApp');
});
describe('BasicTabCrtl',function(){
beforeEach(inject(function(_$rootScope_, _$controller_){
scope = _$rootScope_.$new();
controller = $controller('BasicTabCrtl',{
'$scope':scope
});
console.log("d");
}));
it('set the name',function(){
expect(scope.name).toBe('testing');
});
});
});

Try this :
Create controller instance :
callController = function () {
return $controller('BasicTabCrtl', {
$scope: scope,
$routeParams: routeParams
});
};
Then test that it's defined or not . If this test pass then you can continue with unit test.
describe('null test', function () {
it('controller should be defined', function () {
ctrl = callController();
expect(ctrl).to.not.be.undefined;
});
});

The problem with your code is you are not injecting all of the dependencies when you instantiate your controller. Try this...
beforeEach(inject(['$scope', '$modal', 'BasicTabService', '$controller', '$rootScope', function ($scope, $modal, BasicTabService, $controller, $rootScope){
scope = $rootScope.$new();
controller=$controller('BasicTabCrtl',{
'$scope':$scope,
'$modal':$modal,
'BasicTabService': BasicTabService
});
console.log("d");
}));
Try my answer from Jasmine, Karma, Angular how to write test on my Angular app?. I describe how to test controllers and services and directives.

Related

Error in Karma/Jasmine Unit test

This is my AngularJS code:
angular.module('myapp', [])
.controller('MainCtrl', function($scope, $http, $rootScope, $routeParams) {
$scope.name = "Girish";
$scope.sayHello = function() {
$scope.greeting = "Hello " + $scope.name;
};
$scope.commonUrl = "/";
$rootScope.$watch('eng', function() {
$scope.currentLang = $rootScope.CURRENT_LANGUAGE;
});
$scope.homePageFirstSlider = function() {
$scope.anun = "Nar";
$http({
method: 'GET',
url: "/" + "eng" + '/api/getslideritems/main'
}).then(function successCallback(response) {
$scope.Data = response.data;
$scope.loadCss('mainCarousel');
},
function errorCallback(response) {});
};
});
This is a test file:
'use strict';
describe('myapp', function() {
beforeEach(module('myapp'));
var $controller;
beforeEach(inject(function(_$controller_) {
// The injector unwraps the underscores (_) from around the parameter names when matching
$controller = _$controller_;
}));
describe('$scope.sayHello', function() {
it('same tests', function() {
var $scope = {};
var controller = $controller('MainCtrl', { $scope: $scope });
$scope.name = 'Girish';
$scope.sayHello();
expect($scope.greeting).toEqual('Hello Girish');
});
});
});
After I run karma.conf.js file I have this error:
PhantomJS 2.1.1 (Linux 0.0.0) myapp $scope.sayHello same tests FAILED
***Error: [$injector:unpr] Unknown provider: $routeParamsProvider <- $routeParams <- MainCtrl***
http://errors.angularjs.org/1.5.0/$injector/unpr?p0=%24routeParamsProvider%20%3C-%20%24routeParams%20%3C-%20MainCtrl in /var/www/html/famboxv2/public/bower_components/angular/angular.js (line 4397)
loaded#http://localhost:9882/context.js:151:17
PhantomJS 2.1.1 (Linux 0.0.0): Executed 1 of 1 (1 FAILED) ERROR (0.025 secs / 0.004 secs)
Chromium 45.0.2454 (Ubuntu 0.0.0): Executed 1 of 1 (1 FAILED) ERROR (0.008 secs / 0.005 secs)
How can I solve this error?
Unknown provider: $routeParamsProvider <- $routeParams <- MainCtrl
$routeParams service is a part of ngRoute module. So you'll have to include it as a dependency on your module.
Here's how:
angular.module('myapp', ['ngRoute'])
Also you should be mocking the controller in the first beforeEach block instead of mocking it inside a specific test, so that it could be reusable in all your tests.
And your tests will still be failing because you've inject an empty object for $scope instead of creating a new scope using the $rootScope's $new function. So you should be doing the following changes to make them pass:
describe('myapp', function() {
beforeEach(module('myapp'));
//Replace this
beforeEach(inject(function($controller, _$rootScope_){
//With this
// beforeEach(inject(function($controller, _$rootScope_, _$routeParams_, _$http_){
//Uncomment the following comments if needed for writing tests for the $watch function.
// $rootScope = _$rootScope_;
$scope = _$rootScope_.$new();
// $http = _$http_;
// $routeParams = _$routeParams_;
controller = $controller('MainCtrl', {
$scope: $scope,
// $http: $http,
// $rootScope: $rootScope,
// $routeParams: $routeParams
});
}));
describe('$scope.sayHello', function() {
it('same tests', function() {
$scope.name = 'Girish';
$scope.sayHello();
expect($scope.greeting).toEqual('Hello Girish');
});
});
});

Error: spyOn could not find an object to spy upon for login()

I am trying on unit test for login using karma and jasmine. I got the following error when I test my code using karma start unit-tests.conf.js.
PhantomJS 1.9.8 (Mac OS X 0.0.0) LoginController doLoginAction should call login method on UserService FAILED
Error: spyOn could not find an object to spy upon for login()
Here I am including my login.controller.tests.js page.
describe('LoginController', function() {
var scope, controller, userServiceMock, stateMock;
beforeEach(module('user.controllers'));
beforeEach(inject(function($rootScope, $controller) {
scope = $rootScope.$new();
controller = $controller('LoginController',{
$scope: scope,
$state: stateMock,
UserService: userServiceMock
});
}));
beforeEach(function() {
scope.doLoginAction = jasmine.createSpy('doLoginAction')
});
describe('doLoginAction',function(){
it('should call odLoginAction method on LoginController', function(){
scope.doLoginAction();
});
it('should call login method on UserService', function(){
spyOn(userServiceMock,'login');
expect(userServiceMock.login).toHaveBeenCalledWith({
username:'riju#gmail.com',
password:'riju'
});
});
});
});
doLoginAction function in my controller page.
$scope.doLoginAction = function () {
UserService.login($scope.creds.username, $scope.creds.password)
.then(function (_response) {
alert("login success " + _response.attributes.username);
// transition to next state
$state.go('tab.list');
}, function (_error) {
alert("error logging in " + _error.message);
})
};
What I am doing wrong, please help me.
thanks
Must inject the userServiceMock service, refer below code.
beforeEach(module('user.controllers'));
beforeEach(module('YOUR SERVICE MODULE'));
beforeEach(inject(function($rootScope, $controller, userServiceMock) {
scope = $rootScope.$new();
controller = $controller('LoginController',{
'$scope' : scope,
'$state' : stateMock,
'UserService' : userServiceMock
});
}));

Issues unit testing controllerAs: logging controller returns a promise

I'm trying to test a controller which uses the controllerAs syntax. My problem is that when I try to test a function on the controller, I get "Expected undefined to be defined."
Controller (shortened version)
(function (angular) {
'use strict';
/* #ngInject */
function PreflightCtrl($state, $window, $timeout, $stateParams, toastr, accountService, servicesService, geoService, visitService, localStorageService, Notifications, service, UTILS) {
/* Exported Vars */
var vm = this;
/* Exported functions */
vm.verifyDob = verifyDob;
function verifyDob() {
if (!vm.form.dob || (vm.form.dob.length !== 8 && vm.form.dob.length !== 10)){
return;
}
if(vm.form.dob.length === 8){
var lastTwoDigits = vm.form.dob.substr(vm.form.dob.length-2);
if(lastTwoDigits === '19'){
return;
}
}
var dob = new Date(vm.form.dob);
vm.verifyingDob = true;
accountService.verifyDOB(dob)
.success(function(data){
vm.genderDisabled = false;
vm.dobError = false;
$timeout(function() {
dobInput.blur();
});
})
.error(function (status) {
vm.genderDisabled = true;
vm.dobError = true;
})
.finally(function () {
vm.verifyingDob = false;
});
}
}
angular
.module('app')
.controller('PreflightCtrl', PreflightCtrl);
}(angular));
Test
describe('PreflightCtrl', function(){
var PreflightCtrl, $state, $window, $timeout, $stateParams, toastr, accountService, servicesService, geoService, visitService, localStorageService, Notifications, service, UTILS, mockAccountService, mockServicesService;
beforeEach(module('app'));
beforeEach(inject(function($controller, _$state_, _$window_, _$timeout_, _$stateParams_, _toastr_, _accountService_, _servicesService_, _geoService_, _visitService_, _localStorageService_, _Notifications_, _UTILS_){
//mock services used in PreflightCtrl
mockAccountService = {
verifyDOB: function verifyDOB(dob){
return {
success: function(callback){
callback(dob);
}
}
},
isPermUser: function isPermUser(){
return {
success: function(callback){
callback(true);
}
}
},
profile: {
gender: 'male'
}
};
mockServicesService = {
isGenderAllowed: function isGenderAllowed(serviceCode, gender){
return true;
}
}
//prepare for dependency injection
$state = _$state_;
$window = _$window_;
$timeout = _$timeout_;
$stateParams = _$stateParams_;
toastr = _toastr_;
accountService = mockAccountService;
servicesService = mockServicesService;
geoService = _geoService_;
visitService = _visitService_;
localStorageService = _localStorageService_;
Notifications = _Notifications_;
service = {"id": 3, "code": "HL", "flags": {"multi_medicine": false}, "genders": ["male"], "name": "Hair Loss", "product": {"count": 3}, "visible": 1};
UTILS = _UTILS_;
//spy on the mocked services
spyOn(accountService, 'verifyDOB').and.callThrough();
spyOn(servicesService, 'isGenderAllowed').and.callThrough();
//create the controller
PreflightCtrl = $controller('PreflightCtrl', {
$state: $state,
$window: $window,
$timeout: $timeout,
$stateParams: $stateParams,
toastr: toastr,
accountService: accountService,
servicesService: servicesService,
geoService: geoService,
visitService: visitService,
localStorageService: localStorageService,
Notifications: Notifications,
service: service,
UTILS: UTILS
});
}));
it('should have a defined controller', function(){
expect(PreflightCtrl).toBeDefined();
});
it('should have a defined function called verifyDob', function(){
console.log(PreflightCtrl);
expect(PreflightCtrl.verifyDob).toBeDefined();
});
it('should verify a DOB', function(){
PreflightCtrl.form.dob = '01/01/1990';
PreflightCtrl.verifyDob();
expect(PreflightCtrl.verifyingDob).toBe(false);
});
});
When I run the test, this is the output that I get:
Running "karma:unit" (karma) task
PhantomJS 1.9.8 (Mac OS X 0.0.0) LOG: 'WARNING: Tried to load angular more than once.'
LOG: Promise{$$state: Object{status: 2, value: Error{message: ...}}}
PhantomJS 1.9.8 (Mac OS X 0.0.0) PreflightCtrl should have a defined function called verifyDob FAILED
Expected undefined to be defined.
at /Users/tracy/Projects/LemonaidClinic/src/views/preflight/preflight.controller.spec.js:80
PhantomJS 1.9.8 (Mac OS X 0.0.0) PreflightCtrl should verify a DOB FAILED
TypeError: 'undefined' is not an object (evaluating 'PreflightCtrl.form.dob = '01/01/1990'')
at /Users/tracy/Projects/LemonaidClinic/src/views/preflight/preflight.controller.spec.js:85
PhantomJS 1.9.8 (Mac OS X 0.0.0): Executed 15 of 15 (2 FAILED) (0.006 secs / 0.204 secs)
Warning: Task "karma:unit" failed. Use --force to continue.
Aborted due to warnings.
Line 80 is this line: expect(PreflightCtrl.verifyDob).toBeDefined();
and line 85 is this: PreflightCtrl.form.dob = '01/01/1990';
and you can see the first line is the log of the controller, which returns a promise which means none of the functions or variables are on the controller that need to be there.
I'm also unsure why Angular is trying to load more than once, but it doesn't seem to be affecting any other tests.
What am I doing wrong?
Thank you in advance.
I would do it more like this:
var scope = $rootScope.$new();
$controller('myController as vm', {$scope:scope, /*your dependency tree hell*/});
$rootScope.$apply();
vm = scope.vm;//This is your new controller, you can refer to it in tests.
I think the fact that you have to mock so much says your Controller has too many dependencies, directly and/or indirectly.
However, if you're not in a position to fix that, you can mock more easily by just creating a folder called "mocks" and dropping in files that have the same id as the real ones and pointing Karma to that folder. Those will override the actual dependencies. The downside is that you'll still have to do one-off mocks if you need something different than your registered mock, but it removes the task of having to set up mocks in each test.

Jasmine Testing with vm in Angular controller

Trying to test a simple test in Jasmine & Karma and AngularJs frameWork,
controller:
(function() {
'use strict';
angular
.module('bsp.account')
.controller('Account', Account);
/* #ngInject */
function Account(userService, accountService) {
var vm = this;
vm.title = 'Accounts';
vm.username = userService.getUsername();
vm.showPasswordModal = accountService.showPasswordModal;
vm.showLogoutModal = accountService.showLogoutModal;
activate();
////////////////
function activate() {
}
}
})();
Can anyOne tell me how do i write a simple test case using Jasmin with this code ? and also maybe a possible methode and its test,
My test code below:
describe('Account', function() {
var scope,
controller;
beforeEach(module('bsp.account'));
//sample testCase--
it('testCheck', function() {
expect('helloWorld').toBe("helloWorld");
});
describe('Account', function() {
//injecting the scope&controller--
beforeEach(inject(function($rootScope, $controller) {
scope = $rootScope.$new();
controller = $controller('Account', {
$scope: scope
});
scope.vm = controller;
}));
});
it("checkTitle",function(){
var vm = controller("Account",{$scope:scope});
expect(vm.title).toEqual("Accounts");
});
});
karma ,response:
Running "karma:unit:run" (karma) task
[2015-10-23 15:11:03.542] [DEBUG] config - Loading config /vagrant/frontend/build/karma-unit.js
✗ checkTitle
TypeError: 'undefined' is not a function (evaluating 'controller("Account",{$scope:scope})')
at /vagrant/frontend/src/app/account/account.controller.spec.js:33
LOG LOG: undefined
PhantomJS 1.9.8 (Linux 0.0.0) LOG: undefined
LOG LOG: '** if *********'
PhantomJS 1.9.8 (Linux 0.0.0) LOG: '** if *********'
PhantomJS 1.9.8 (Linux 0.0.0): Executed 37 of 37 (1 FAILED) (0.134 secs / 0.128 secs)
Warning: Task "karma:unit:run" failed. Use --force to continue.
Aborted due to warnings.
Completed in 10.849s at Fri Oct 23 2015 15:11:04 GMT-0700 (PDT) - Waiting...
Any suggestions is appreciated,Am new to Jasmin testing.Thank You
You are actually instantiating a BoardPerformance controller in your beforeEach block but the code you are showing is for Account, so I understand that's a mistake.
So for your simple test case to run try this:
describe('Account', function() {
var scope, controller, userServiceMock;
beforeEach(module('bsp'));
beforeEach(function() {
userServiceMock = {
getUsername: function(){}
}
});
beforeEach(inject(function($rootScope, $controller) {
scope = $rootScope.$new();
controller = $controller('Account', {
'userService': userServiceMock
});
}));
it('checkTitle', function(){
expect(controller.title).toEqual('Accounts');
});
});
So this is the new test case in Jasmin,
describe('Account', function() {
var scope, controller, userServiceMock,accountServiceMock;
beforeEach(module('bsp'));
beforeEach(function() {
userServiceMock = {
getUsername: function(){} //this is a method inside userService
};
accountServiceMock = {
showPasswordModal :function(){}//this is a method inside accountService
};
});
beforeEach(inject(function($rootScope, $controller) {
scope = $rootScope.$new();
controller = $controller('Account', {
'userService': userServiceMock,
'accountService':accountServiceMock
});
}));
describe('testing Title',function(){
it('checkTitle', function(){
expect(controller.title).toEqual('Accounts');
});
});
});
It is very basic but has necessary information for controllers with dependency and also the vm..thank to Pablo

AngularJS - Unit Test - Controller not defined

My controller definition is as follows:
angular.module("rmt.account-info").controller('AccountInfoController', ['$scope', '$rootScope', '$modal', 'AccountInfoServices', 'UserServices', 'Profile',
function ($scope, $rootScope, $modal, AccountInfoServices, UserServices, Profile) {
and I am trying to write Unit Test for this controller as follows:
describe("Account Info Module", function(){
describe("Account Info Controller", function(){
var scope, ctrl;
beforeEach(function(){
module("rmt.account-info");
var accountInfoMockService = {}, userMockService = {}, mockedProfileFactory = {};
var fakeModal =
{
result: {
then: function(confirmCallback, cancelCallback){
this.confirmCallback = confirmCallback;
this.cancelCallback = cancelCallback;
}
},
close: function(item){
this.result.confirmCallback(item);
},
dismiss: function(reason){
this.result.cancelCallback(reason);
}
};
module(function($provide, $modal){
$provide.value('AccountInfoServices', accountInfoMockService);
$provide.value('UserServices', userMockService);
$provide.value('Profile', mockedProfileFactory);
spyOn($modal, 'open').and.returnValue(fakeModal);
return null;
});
});
beforeEach(inject(function(_$rootScope_, _$controller_, _$modal_, _AccountInfoServices_, _UserServices_, _Profile_){
scope = _$rootScope_.new();
$rootScope = _$rootScope_;
$modal = _$modal_;
AccountInfoServices = _AccountInfoServices_;
UserServices = _UserServices_;
Profile = _Profile_;
ctrl = _$controller_("accountInfoController", {
$scope : scope,
$rootScope : $rootScope,
$modal : $modal,
AccountInfoServices : AccountInfoServices,
UserServices : UserServices,
Profile : Profile
});
}));
describe("Initial State", function(){
it("should instantiate the controller properly", function(){
expect(ctrl).not.toBeUndefined();
});
});
});
describe("Account Info Service", function(){
});
});
Please help to know where I am going wrong, I get the following error in my terminal:
Failed to instantiate module {0} due to:
{1}
Using Karma as Test Runner and Jasmine - testing framework
Console log error

Resources