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
Related
I am trying to do unit test of my angular app with karma. I am getting some error. Am i missing something? A
This my controller
(function () {
"use strict"
angular
.module("myApp")
.controller("userCtrl",['$scope', '$state', 'userService', 'appSettings','md5','currentUser','$rootScope',
function ($scope, $state, userService, appSettings,md5,currentUser, $rootScope) {
$scope.login = function() {
$scope.loading = true;
if($scope.password != null){
var user ={
username:$scope.username,
password:md5.createHash($scope.password)
}
var getData = userService.login(user);
getData.then(function (response) {
console.log(response);
$scope.loading = false;
currentUser.setProfile(user.username, response.data.sessionId);
$state.go('videos');
}, function (response) {
console.log(response.data);
});
}else{
$scope.msg = "Password field is empty!"
}
}
}])
}());
This is my test codes
'use strict';
describe('userCtrl', function() {
beforeEach(module('myApp'));
var scope, userCtrl, apiService,q, deferred, currentUser;
describe('$scope.login', function(){
beforeEach(function(){
apiService = {
login: function () {
deferred = q.defer();
return deferred.promise;
};
};
});
beforeEach(inject(function($controller, $rootScope, $q, _currentUser_){
var user ={name:'ali',password:'password'};
scope = $rootScope.$new();
q = $q;
// The injector unwraps the underscores (_) from around the parameter names when matching
userCtrl = $controller('userCtrl', {
$scope:scope,
userService:apiService
});
//userService = _userService_;
currentUser = _currentUser_;
}));
it('should call user service login', function() {
spyOn(apiService, 'login').and.callThrough();
scope.login();
deferred.resolve(user);
expect(apiService.login).toHaveBeenCalled();
});
it('checks the password field', function() {
scope.login();
expect(scope.msg).toEqual('Password field is empty!');
});
});
});
And i am getting this error
enter image description here
If you have to test controller then use to spyon for service method and in case of service then use HttpBackend
describe('Testing a Controller that uses a Promise', function() {
var $scope;
var $q;
var deferred;
beforeEach(module('search'));
beforeEach(inject(function($controller, _$rootScope_, _$q_, searchService) {
$q = _$q_;
$scope = _$rootScope_.$new();
// We use the $q service to create a mock instance of defer
deferred = _$q_.defer();
// Use a Jasmine Spy to return the deferred promise
spyOn(searchService, 'search').and.returnValue(deferred.promise);
// Init the controller, passing our spy service instance
$controller('SearchController', {
$scope: $scope,
searchService: searchService
});
}));
it('should resolve promise', function() {
// Setup the data we wish to return for the .then function in the controller
deferred.resolve([{
id: 1
}, {
id: 2
}]);
// We have to call apply for this to work
$scope.$apply();
// Since we called apply, not we can perform our assertions
expect($scope.results).not.toBe(undefined);
expect($scope.error).toBe(undefined);
});
});
This for same using spyon for service method then use $appy method to make it work.
I'm trying to test a method that deletes an item from a list after user confirmation.
Controller:
app.controller('mainCtrl', ['$scope', '$window', 'dataService', function($scope, $window, dataService) {
var vm = this;
vm.delete = function(id, index) {
if($window.confirm('Are you sure?')) {
dataService.deleteById(id).then(function() {
vm.list.splice(index, 1)
});
}
};
}]);
Sevice:
app.service('dataService', ['$http', function($http) {
this.deleteById = function(id) {
return $http.delete('delete-item?id=' + id);
};
}]);
Test:
describe('Testing RecipesController', function() {
var scope, ctrl, dataServiceMock, q, deferred, window;
beforeEach(function() {
dataServiceMock = {
deleteById: function() {
deferred = q.defer();
return deferred.promise;
}
};
});
beforeEach(function() {
module('app');
inject(function($rootScope, $controller, $q, $window) {
q = $q;
window = $window;
scope = $rootScope.$new();
ctrl = $controller('mainCtrl', {
$scope: scope,
dataService: dataServiceMock
});
});
});
it('should delete recipe if the user clicked "OK"', function() {
spyOn(window, 'confirm').and.returnValue(true);
spyOn(dataServiceMock, 'deleteById').and.callThrough();
var item= {
id: 2,
name: 'Shirt'
};
ctrl.list = ['Hat', 'Shirt'];
ctrl.delete(item, 1);
expect(dataServiceMock.deleteById).toHaveBeenCalled();
expect(ctrl.list.length).toBe(1);
});
});
I successfully mocked the confirm dialog and the delete method, and the test to check if the method been called even passes.
But, The promise.then() isn't working.
After I run the test I got this message "Expected 2 to be 1".
I see one thing for sure, which is that you never resolve or reject your promise in the data service mock. Try changing the mock to this:
beforeEach(function() {
dataServiceMock = {
deleteById: function() {
deferred = q.defer();
deferred.resolve({ /* whatever data you want to resolve with */ });
return deferred.promise;
// You could also shorten this whole mock function to just:
// return $q.resolve({ /* some data */ });
}
};
});
Also, don't forget to execute the $digest() function on the $rootScope at the end of your test... you're actually executing it on your controller's scope, NOT the root scope.
Hold onto the actual $rootScope object - change your beforeEach to:
var $rScope;
beforeEach(function() {
module('app');
inject(function($rootScope, $controller, $q, $window) {
q = $q;
window = $window;
$rScope = $rootScope;
ctrl = $controller('mainCtrl', {
$scope: $rootScope.$new(),
dataService: dataServiceMock
});
});
});
Then in your test, execute $digest on the root scope at the end:
it('should delete recipe if the user clicked "OK"', function() {
// all your test codez...
$rScope.$digest();
});
I'm trying to write test cases for a javascript method but my jasmine is not able to call the js method. It is giving me error that the function is not defined.
Below is Controller Code
(function () {
"use strict";
angular.module('rbApp').controller('PQRCtrl', PQRCtrl);
PQRCtrl.$inject = ['$scope', '$state', 'baseURL', 'PQRCtrlFactory', '$cookieStore'];
function PQRCtrl($scope, $state, baseURL, PQRCtrlFactory, $cookieStore) {
var funcB= function(){
console.log("This line should called from jasmine ")
}
}
}());
My jasmine spec
describe('PQRCtrl Controller Test Suite', function() {
var mockPQRCtrl,mockrootScope, mockscope, mockstate,mockcookies, mockstateparams, mockgetSourcePostsService, mockPQRCtrlFactory;
var baseURL = "****";
beforeEach(module('rbApp'));
beforeEach(module("ui.router"));
beforeEach(module("ngRoute"));
beforeEach(module("ngCookies"));
beforeEach(module("ui.bootstrap"));
beforeEach(module("toggle-switch"));
beforeEach(module("ngFileUpload"));
beforeEach(module("ngDraggable"));
beforeEach(module("angular-loading-bar"));
beforeEach(module("ngAnimate"));
beforeEach(module("ngGrid"));
beforeEach(module("kendo.directives"));
beforeEach(module('ui.bootstrap'));
beforeEach(inject(function($injector, _$rootScope_, _$controller_, _$httpBackend_, _$stateParams_, _$state_,_$cookieStore_,_PQRCtrlFactory_){
var userData = {'token' : 'abc'};
mockrootScope = _$rootScope_;
mockstateparams = _$stateParams_;
mockscope = mockrootScope.$new();
mockstate = _$state_;
mockcookies = _$cookieStore_;
mockPQRCtrlFactory = _PQRCtrlFactory_;
mockcookies.put('userInfo', userData);
var userInfo = mockcookies.get('userInfo');
var token = userInfo.token;
mockPQRCtrlFactory = _$controller_('PQRCtrl',
{
'$scope': mockscope,
'$state': mockstate,
'baseURL' : baseURL,
'PQRCtrlFactory': mockPQRCtrlFactory ,
'$cookieStore' : mockcookies
});
}));
it("Test: PQRCtrl Controller exists or not", function() {
expect(mockPQRCtrl).toBeDefined();
});
it("Test: funcB() Success", function() {
funcB(); // its not calling my actual function in the controller
// it is saying that its not defined
})
});
Your funcB is defined inside the controller PQRCtrl. Put it outside:
(function () {
"use strict";
var funcB;
angular.module('rbApp').controller('PQRCtrl', PQRCtrl);
PQRCtrl.$inject = ['$scope', '$state', 'baseURL', 'PQRCtrlFactory', '$cookieStore'];
function PQRCtrl($scope, $state, baseURL, PQRCtrlFactory, $cookieStore) {
funcB = function(){
console.log("This line should called from jasmine ")
}
}
I'm very new to jasmine and I got some issue trying to mock a provider.
I have a provider that looks like :
angular.module('myApp')
.factory('MyService', function ($resource) {
return {
actionResource : function(projectId, actionId){
var url = 'blablabla';
if(actionId){
url += "/"+actionId;
}
return $resource(url, {}, {
'create': {
method: 'POST'
}
});
},
};
});
I have a controller using this factory
angular.module('myApp')
.controller('myCtrl', function ($scope, MyService, $state) {
$scope.addAction = function(){
MyService.actionResource($scope.projectId).create($scope.action,
function(){
$state.go('somewhere', {});
});
};
});
and I'd really like to test this controller, at the moment I'm doing something like :
'use strict';
describe('[test] [controller] - myCtrl', function() {
beforeEach(angular.mock.module('myApp'));
//mock creation
beforeEach(
module(function($provide) {
$provide.factory('MyService', function() {
var actionResource = function(projectId, actionId){
var create = function(){return {}};
return {create:create};
}
return {actionResource:actionResource}
}
)})
);
var $httpBackend, $rootScope, myController, mockMyService;
var scope = {};
beforeEach(angular.mock.inject(function($injector, $rootScope, MyService) {
var $controller = $injector.get('$controller');
scope=$rootScope.$new();
mockMyService = MyService;
spyOn(mockPilotageService, 'actionResource').and.callThrough();
spyOn(mockPilotageService.actionResource(), 'create');
createController = function() {
return $controller("myCtrl", {$scope:scope, myService:mockMyService});
};
}));
it('myCtrl - addAction() calls actionRessource.create() method', function() {
createController();
scope.addAction();
expect(mockMyService).toBeDefined();
expect(mockMyService.actionResource).toHaveBeenCalled();
expect(mockMyService.actionResource().create).toHaveBeenCalled();
});
});
and I'm getting this error :
Error: Expected a spy, but got Function.
at /Users/*****/myController.spec.js:86
So it's able to spy on mockMyService.actionResource but not on mockMyService.actionResource().create. I can't understand why
any help would be more than welcome
thanks
My controller:
angularMoonApp.controller('SourceController', ['$scope', '$rootScope', '$routeParams', 'fileService', function ($scope, $rootScope, $routeParams, fileService) {
$scope.init = function() {
$rootScope.currentItem = 'source';
fileService.getContents($routeParams.path).then(function(response) {
$scope.contents = response.data;
$scope.fileContents = null;
if(_.isArray($scope.contents)) {
// We have a listing of files
$scope.breadcrumbPath = response.data[0].path.split('/');
} else {
// We have one file
$scope.breadcrumbPath = response.data.path.split('/');
$scope.breadcrumbPath.push('');
$scope.fileContents = atob(response.data.content);
fileService.getCommits(response.data.path).then(function(response) {
$scope.commits = response.data;
});
}
});
}
$scope.init();
}]);
My unit test:
(function() {
describe('SourceController', function() {
var $scope, $rootScope, $httpBackend, $routeParams, $q, createController, fileService, deferred;
beforeEach(module('angularMoon'));
beforeEach(inject(function($injector) {
$httpBackend = $injector.get('$httpBackend');
$rootScope = $injector.get('$rootScope');
$routeParams = $injector.get('$routeParams');
$scope = $rootScope.$new();
$q = $injector.get('$q');
deferred = $q.defer();
fileService = $injector.get('fileService');
var $controller = $injector.get('$controller');
createController = function() {
return $controller('SourceController', {
'$scope': $scope,
'$routeParams': $routeParams,
'fileService': fileService
});
};
}));
it("should set the current menu item to 'source'", function() {
createController();
$scope.init();
expect($rootScope.currentItem).toBe('source');
});
it("should get test the getContents call of the fileService", function() {
spyOn(fileService, 'getContents').andCallThrough();
createController();
$scope.init();
expect(fileService.getContents).toHaveBeenCalled();
});
it("should return an object with multiple files", function() {
var multipleFiles = [{path: '.DS_Store'}, {path: '.bowerrc'}];
deferred.resolve(multipleFiles);
spyOn(fileService, 'getContents').andReturn(deferred.promise);
createController();
$scope.init();
expect($scope.contents).toBe(multipleFiles);
expect($scope.breadcrumbPath).toBe('');
});
});
})();
The last test fails with:
Expected undefined to be [ { path : '.DS_Store' }, { path : '.bowerrc' } ].
Expected undefined to be ''.
Why is the $scope undefined here?
Your controller is expecting you to inject in $rootScope which you are not doing in your unit test.
You have:
createController = function() {
return $controller('SourceController', {
'$scope': $scope,
'$routeParams': $routeParams,
'fileService': fileService
});
But but should have:
createController = function() {
return $controller('SourceController', {
'$scope': $scope,
'$rootScope': $rootScope,
'$routeParams': $routeParams,
'fileService': fileService
});
Also, you will want to call this code:
createController();
$scope.init();
before you resolve your promise:
deferred.resolve(multipleFiles);
The scope is not undefined. What is undefined is $scope.contents and $scope.breadcrumbPath.
And that's because promise callbacks are always being called asynchronously. You need to call
$scope.$apply()
before verifying your expectations.