Unit test of controller angularjs - angularjs

I have this simple controller, UserService is a service which return JSON
"use strict";
angular.module("controllers").controller('profileCtrl', ["$scope", "UserService",
function ($scope, UserService) {
$scope.current_user = UserService.details(0);
}
]);
I can not make the test. However this is my try
'use strict';
describe('profileCtrl', function () {
var scope, ctrl;
beforeEach(angular.mock.module('controllers'), function($provide){
$provide.value("UserService", {
details: function(num) { return "sdfsdf"; }
});
});
it('should have a LoginCtrl controller', function() {
expect(controllers.profileCtrl).toBeDefined();
});
beforeEach(angular.mock.inject(function($rootScope, $controller){
scope = $rootScope.$new();
$controller('profileCtrl', {$scope: scope});
}));
it('should fetch list of users', function(){
expect(controllers.scope.current_user.length).toBe(6);
expect(controllers.scope.current_user).toBe('sdfsdf');
});
});

The usage of $controller is correct, that's the way to instantiate a controller for a unit test. You can mock the UserService instance it gets directly in the $controller invocation.
You should be using its return value - this is the instance of your controller you're going to test.
You're trying to read stuff from controllers but its not defined anywhere in the test, I guess you're referring to the module.
This is how I would go about it + fiddle
//--- CODE --------------------------
angular.module('controllers', []).controller('profileCtrl', ["$scope", "UserService",
function ($scope, UserService) {
$scope.current_user = UserService.details(0);
}]);
// --- SPECS -------------------------
describe('profileCtrl', function () {
var scope, ctrl, userServiceMock;
beforeEach(function () {
userServiceMock = jasmine.createSpyObj('UserService', ['details']);
userServiceMock.details.andReturn('sdfsdf');
angular.mock.module('controllers');
angular.mock.inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
ctrl = $controller('profileCtrl', {
$scope: scope,
UserService: userServiceMock
});
});
});
it('should have a LoginCtrl controller', function () {
expect(ctrl).toBeDefined();
});
it('should fetch list of users', function () {
expect(scope.current_user).toBe('sdfsdf');
});
});
You're welcome to change the fiddle online to see how it affects testing results.

Related

AngularJS Karma Jasmine : Expected undefined to be defined

I am new to AngularJS and working on adding unit tests in Karma and Jasmine. I have a following controller code whose method I am trying to test. I am getting the error saying that Expected undefined to be defined. I am not sure why SpyOn is not able to recognize the method. Any help is appreciated. Thanks in advance.
newclaim.js
(function () {
'use strict';
var controllerId = 'createnewclaim';
angular.module('app').controller(controllerId, ['$location', '$routeParams', 'sessionKeys', 'securelogins',
'localStorageService', 'common', 'config', 'datacontext', createnewclaim]);
function createnewclaim($location, $routeParams, sessionKeys, securelogins, localStorageService, common, config, datacontext) {
//some code here
My test file code
describe('testing AngularJS Test Suite', function () {
beforeEach(module('app'));
describe('Testing AngularJS NewClaim Controller', function () {
var scope = {};
var ctrl;
var controllerId = 'createnewclaim';
beforeEach(inject(function ($controller, $rootScope, localStorageService, common, datacontext, sessionKeys, securelogins) {
scope = $rootScope.$new();
ctrl = function () {
$controller(controllerId, {
$scope: scope,
localStorageService: localStorageService,
common: common,
datacontext: datacontext,
sessionKeys: sessionKeys,
securelogins: securelogins
});
};
}));
it('controller defined', inject(function () {
expect(ctrl).toBeTruthy();
}));
it('controller function defined', inject( function () {
ctrl();
expect(ctrl.createnewclaim).toBeDefined();
}));
});
});
})();
Sorry. Ignore the return. You need to be using the scope as your test, not the ctrl.
describe('testing AngularJS Test Suite', function () {
beforeEach(module('app'));
describe('Testing AngularJS NewClaim Controller', function () {
var scope = {};
var ctrl;
var controllerId = 'createnewclaim';
beforeEach(inject(function ($controller, $rootScope, localStorageService, common, datacontext, sessionKeys, securelogins) {
scope = $rootScope.$new();
ctrl = function () {
return $controller(controllerId, {
$scope: scope,
localStorageService: localStorageService,
common: common,
datacontext: datacontext,
sessionKeys: sessionKeys,
securelogins: securelogins
});
};
}));
it('controller defined', inject(function () {
ctrl();
expect(scope).toBeTruthy();
}));
it('controller function defined', inject( function () {
ctrl();
expect(scope.createnewclaim).toBeDefined();
}));
});
});
})();

TypeError: undefined is not a constructor (evaluating 'angular.controller('myView')')

I'm getting the below error while doing karma/jasmine unit testing for both the test cases.I tried by modifying the controller by adding angular.controller in the spec file even then it is not working.Is there any way to fix?
TypeError: undefined is not a constructor (evaluating 'angular.controller('myView')')
myView.spec.js
// myView.spec.js
(function(){
describe('controller: myView', function(){
var module,myView,$q, $rootScope, $scope, uiGridConstants, overviewService, commonService, $timeout;
beforeEach(function() {
module = angular.module('app.myView');
controller= angular.controller('myView')
});
beforeEach(inject(function ($controller, _$q_, _$rootScope_, _$timeout_) {
$q= _$q_;
$rootScope = _$rootScope_;
$timeout= _$timeout_;
myView= $controller('myView', {
$q : _$q_,
$rootScope : _$rootScope_,
$timeout: _$timeout_
});
}));
describe("myViewto be defined", function() {
it("should be created successfully", function () {
expect(controller).toBeDefined();
});
it("overview should be defined", function () {
expect(myView()).toBeDefined();
});
});
});
})();
and myView.js
(function() {
'use strict';
angular
.module('app.myView')
.controller('myView', myView);
function myView($q, $rootScope, $scope, uiGridConstants, myViewService, commonService, $timeout) {
var vm = this;
vm.callFeedback = function () { };
})();
Sharing following code
// myView.spec.js
(function(){
describe('myView', function(){
var $controller, myView;
//we use angular-mocks to specify which modules we'll need within this
//test file.
beforeEach(angular.mock.module('app.myView'));
// Inject the $controller service to create instances of the controller
//(myView) we want to test
beforeEach(inject(function(_$controller_) {
$controller = _$controller_;
myView = $controller('myView', {});
}));
// Verify our controller exists
it('should be defined', function() {
expect(myView).toBeDefined();
});
});
})();
We set _$controller_to the $controller variable we created and then create an instance of our controller by calling $controller('myView', {}). The first argument is the name of the controller we want to test and the second argument is an object of the dependencies for our controller.
You should pass the injected parameters to your controller as shown:
(function() {
'use strict';
angular
.module('app.myView')
.controller($q,$rootScope,$scope,uiGridConstants,'myView', myView);
function myView($q, $rootScope, $scope, uiGridConstants, myViewService, commonService, $timeout) {
var vm = this;
vm.callFeedback = function () { };
})();
Also make sure that your module has all the necesary dependences in the angular.module('app.myView',['uiGridConstants', ...'etc']);

How to check if a function is available in instantiated controller for unit testing in Jasmine

I am trying to unittest a controller in AngularJS for the first time. I want to test if the login-function in this controller calls the right service but I get the error, that the function doesn't exist in the controller. What did I do wrong? Do I have to mock more? But I shouldn't have to mock the functions in the controller to be tested because if I would do that the whole testing would be senseless, or am I wrong?
Controller-Snippet:
function LoginController($scope, $state, myService, ngToast) {
$scope.loginUser = loginUser;
activate();
function activate() {}
function loginUser(credentials) {
myService.authenticate(/*things*/);
}
}
Test-Code:
describe('Login Controller', function () {
'use strict';
//globals
var controller, scope;
var $controller, $state, myService, ngToast;
//needed modules
beforeEach(module('app.login'));
beforeEach(module('app.core'));
beforeEach(module('ui.router'));
//instanciate Controller
beforeEach(inject(function (_$controller_, _$state_, _myService_, _ngToast_) {
scope = {};
$state = _$state_;
myService = _myService_;
ngToast = _ngToast_;
$controller = _$controller_;
controller = $controller('LoginCtrl', {
$scope: scope,
$state: $state,
myService: myService,
ngToast: ngToast
});
}));
it('should have an existing controller', function () {
expect(controller).toBeDefined();
});
/*************************** unit-tests ***************************/
describe('.loginUser()', function () {
it('should exist', function () {
expect(controller.loginUser).toBeDefined();
});
});
});
The Error I am getting when running karma start:
.loginUser()
✗ should exist
TypeError: controller.loginUser is not a function
at Object.<anonymous> (src/login/login.controller.spec.js:74:31)
But it seems to me that the controller does exist, because this test doesn't fail:
Login Controller
✓ should have an existing controller
it is because loginUser is defined on $scope and not on the controller so loginUser is not bound to your controller object in your test.
To test loginUser please do the following:
Inject $rootScope in your beforeEach
Set scope = $rootScope.$new()
The controller should be created with this scope
Your test should check if loginUser is defined on the scope
describe('Login Controller', function () {
'use strict';
//globals
var controller, scope;
var $controller, $state, myService, ngToast;
//needed modules
beforeEach(module('app.login'));
beforeEach(module('app.core'));
beforeEach(module('ui.router'));
//instanciate Controller
beforeEach(inject(function (_$controller_, _$state_, _myService_, _ngToast_, _$rootScope_) {
scope = _$rootScope_.$new();
$state = _$state_;
myService = _myService_;
ngToast = _ngToast_;
$controller = _$controller_;
controller = $controller('LoginCtrl', {
$scope: scope,
$state: $state,
myService: myService,
ngToast: ngToast
});
}));
it('should have an existing controller', function () {
expect(controller).toBeDefined();
});
/*************************** unit-tests ***************************/
describe('.loginUser()', function () {
it('should exist', function () {
expect(scope.loginUser).toBeDefined();
});
});
});
If you want to test loginUser on the controller itself then make use of the controller as syntax where you would set this.loginUser = loginUser instead of $scope.loginUser = loginUser. Then you will be able to use controller.loginUser in your test.

why the message property is undefined?

I make one controller in Angularjs and try to test that controller using Jasmine. I got this error Cannot read property 'message' of undefined why ?
Here is my code.
controller
(function(){
'use strict';
angular.module('app.home').controller('homeCntrl',homeCntrl);
function homeCntrl(){
var home=this;
home.clickbtn=function(){
home.message='test';
alert(home.message)
}
}
})();
Testing
(function(){
'use strict';
describe('http controller test', function() {
var $rootScope,
$scope,
controller,
$q,
$httpBackend;
beforeEach(function() {
module('app');
inject(function($injector) {
$rootScope = $injector.get('$rootScope');
$scope = $rootScope.$new();
controller = $injector.get('$controller')('homeCntrl', {
$scope: $scope
})
})
})
describe('Init value', function() {
it('check name value', function() {
expect(controller.message).toBeUndefined();
})
})
it('it should be true', function() {
expect(true).toBeTruthy();
})
})
})();
any update ?durning testing I got this error .. ? can we do testing of this controller ?Every thing is fine on angular js code problem is on test code..only check appspec.js
Just an hint
app
(function() {
'use strict';
function HomeController() {
var home = this;
home.title = 'Home';
}
angular.module('home.controllers', [])
.controller('HomeController', HomeController);
})();
test
'use strict';
describe('home controller', function() {
var $controller;
var scope;
beforeEach(module('home.controllers'));
beforeEach(inject(function(_$controller_, $rootScope) {
$controller = _$controller_;
scope = $rootScope.$new();
$controller('HomeController as home', {$scope: scope});
}));
it('should have text = "Home"', function() {
expect(scope.home.title).toEqual('Home');
});
});
in your case the test should be like
scope.home.clickbtn();
expect(scope.home.message).toEqual('test');
Take a look at http://www.bradoncode.com/tutorials/angularjs-unit-testing/ to master unit test in angular

Jasmine Testing Angular Controller Method

So I have my blank tests passing with this setup.
describe('loginController', function() {
var scope, createController;
beforeEach(module('souply'));
beforeEach(inject(function ($rootScope, $controller, _$location_) {
$location = _$location_;
scope = $rootScope.$new();
createController = function() {
return $controller('loginController', {
'$scope': scope
});
};
}));
And here are the tests...
describe('processGoogleLogin', function(){
describe('successful', function(){
beforeEach(function() {
});
it('should connect to google plus', function () {
expect(true).toBe(true);
});
This one passes no problem.
QUESTION: How can I test a method on the login controller?
Here is the method I want to test on the login controller:
$scope.processGoogleLogin = function(){
console.log('process login was clicked');
window.location.replace('/#/dashboard');
};
The test I have so far is:
it('should sign you into the dashboard', function () {
scope.processGoogleLogin();
//$controller.processGoogleLogin();
//expect(window.location).toBe('/#/dashboard');
});
This test throws an error of:
'undefined' is not a function (evaluating 'scope.processGoogleLogin()')
This needed this line.
var ctrl = $controllerConstructor('myController', {$scope: scope, myResolve: {}, state: state});

Resources