I'm trying to mock calls to localStorage.getItem, but getting error "Function expected". Here is my test code:
describe("AuthService Tests", function() {
var authSvc, httpBackend, scope;
var fakeItem = "{\"access_token\":\"giant_access_token\",\"token_type\":\"bearer\",\"expires_in\":1209599,\".issued\":\"Thu, 11 Feb 2016 13:22:45 GMT\",\".expires\":\"Thu, 25 Feb 2016 13:22:45 GMT\",\"accountType\":\"Administrator\",\"certifiedForAccess\":true}";
var returnFakeToken = function(key) { return fakeItem; }
beforeEach(module('app'));
beforeEach(inject(function (_AuthService_, $q, $rootScope, $httpBackend, $state, _config_, _messages_) {
scope = $rootScope.$new();
spyOn(localStorage, 'getItem').and.callFake(returnFakeToken);
authSvc = _AuthService_;
httpBackend = $httpBackend;
}));
describe('Test suite 1', function () {
it('should return true if user is Administrator', function () {
var result = authSvc.isAdministrator(); // error here
expect(result).toBe(true);
});
});
});
Service under test:
(function () {
'use strict';
angular
.module('app.services')
.factory('AuthService', AuthService);
AuthService.$inject = ['$q', '$rootScope', '$http', '$state', 'config', 'messages'];
function AuthService($q, $rootScope, $http, $state, config, messages) {
var userIdKey = 'userId';
var tokenKey = 'tokenKey';
var userAuthKey = 'userAuth';
var svc = {
isAdministrator: isAdministrator
};
return svc;
function isAdministrator() {
var item = localStorage.getItem(tokenKey); // eror here
var jsonparse = JSON.parse(item);
return jsonparse.accountType == 'Administrator';
}
})();
When I run tests, my mocked function returnFakeToken hadn't even been called and I got error (lines of code where error occured are marked with comments):
TypeError: Function expected
What am I doing wrong?
Thanks!
You don't need to spy on localStorage. It is a function that is built into the browser as part of the HTML5 standard. What you should be testing is that your service returns the expected value. Also, you may need to mock out localStorage if you are testing in PhantomJS.
Related
I am writing unit tests for my existing AngularJS app. There are just four methods in this service. I was able to getFollowUpList to work, but refresh() is not working and it is a very simple method.
The refresh method should simply set deferredGetFollowUpList = null and return true in my test.
There error I'm getting is: TypeError: Cannot read property 'then' of undefined, so my refresh method is undefined. Why is this the case? Thanks
Service
(function () {
"use strict";
angular
.module("all.patient.details")
.factory("followUpListService", ["$rootScope", "$http", "userContext", "$q", "$uibModal", "htmlBaseUrl", FollowUpListService]);
function FollowUpListService($rootScope, $http, userContext, $q, $uibModal, htmlBaseUrl) {
var deferredGetFollowUpList = null;
return {
getFollowUpList: getFollowUpList,
displayModal: displayModal,
refresh: refresh,
save: save
}
function refresh() {
deferredGetFollowUpList = null;
}
}
})();
Unit Test
describe("followUpListService", function () {
beforeEach(module("all.patient.details"));
var followUpListService = {};
var $httpBackend;
var htmlBaseUrlMock;
var returnedFollowUpListData;
var deferredGetFollowUpList;
var $rootScope;
var $q;
var $uibModal;
beforeEach(function () {
htmlBaseUrlMock = { format: function () { } };
module(function ($provide) {
$provide.value("htmlBaseUrl", htmlBaseUrlMock);
});
inject(function (_$rootScope_, _$httpBackend_, _$q_, _$uibModal_, _followUpListService_) {
$rootScope = _$rootScope_;
$httpBackend = _$httpBackend_;
$q = _$q_;
$uibModal = _$uibModal_;
followUpListService = _followUpListService_;
});
});
afterEach(function () {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it("calls refresh()", function () {
followUpListService.refresh()
.then(function (data) {
deferredGetFollowUpList = data;
});
expect(deferredGetFollowUpList).toBe(null);
});
As deferredGetFollowUpList is service level variable, Can you write your test as -
followUpListService.deferredGetFollowUpList = data; //Any Mock Data
followUpListService.refresh();
expect(followUpListService.deferredGetFollowUpList).toBe(null);
New to Jasmine tests for angular. I am trying to test if the controller I defined is defined or not to begin with but I am getting error saying Expected undefined to be defined.
Here is my main code:
// controller logic MatchController.js
(function () {
'use strict';
angular.module('app.match')
.controller('MatchController', MatchController);
MatchController.$inject = ['APP_CONFIG', '$authUser', '$http', '$rootScope', '$state', '$stateParams', 'SearchService', 'ConfirmMatchService', 'MusicOpsService', 'ContentOpsService', 'MatchstickService', 'MatchService', 'Restangular'];
function MatchController(APP_CONFIG, $authUser, $http, $rootScope, $state, $stateParams, searchService, confirmMatchService, musicOpsService, contentOpsService, matchstickService, matchService, Restangular) {
var vm = this;
.
.
.
}
})();
Here is the test file
// MatchController.spec.js
(function(){
'use strict';
describe('Match Controller Tests', function(){
var module, MatchTestController;
beforeEach(function() {
module = angular.module('app.match');
});
beforeEach(inject(function ($controller) {
MatchTestController = $controller('MatchController', {});
}));
describe("Match controller to be defined", function() {
it("should be created successfully", function () {
expect(MatchTestController).toBeDefined();
});
});
});
})();
I keep getting the error:
TypeError: 'undefined' is not a function (evaluating 'angular.controller('MatchController')')
undefined
at /Users/rgoti/match-ui/match-ui/public/src/app/match/match.controller.spec.js:16
at invoke (/Users/rgoti/match-ui/match-ui/public/bower_components/angular/angular.js:4219)
at workFn (/Users/rgoti/match-ui/match-ui/public/bower_components/angular-mocks/angular-mocks.js:2475)
Expected undefined to be defined.
at /Users/rgoti/match-ui/match-ui/public/src/app/match/match.controller.spec.js:22
Not sure what I am doing wrong here.
You should inject all the dependencies in the controller first before mocking it.
Try this:
// MatchController.spec.js
(function(){
'use strict';
describe('controller: MatchController', function(){
var module, MatchController, APP_CONFIG, $authUser, $http, $rootScope, $state, $stateParams, SearchService, ConfirmMatchService, MusicOpsService, ContentOpsService, MatchstickService, MatchService, Restangular;
beforeEach(function() {
module = angular.module('app.match');
});
beforeEach(inject(function ($controller, _APP_CONFIG_, _$authUser_, _$http_, _$rootScope_, _$state_, _$stateParams_, _SearchService_, _ConfirmMatchService_, _MusicOpsService_, _ContentOpsService_, _MatchstickService_, _MatchService_, _Restangular_) {
APP_CONFIG = _APP_CONFIG_;
$authUser = _$authUser_;
$http = _$http_;
$rootScope = _$rootScope_;
$state = _$state_;
$stateParams = _$stateParams_;
SearchService = _SearchService_;
ConfirmMatchService = _ConfirmMatchService_;
MusicOpsService = _MusicOpsService_;
ContentOpsService = _ContentOpsService_;
MatchstickService = _MatchstickService_;
MatchService = _MatchService_;
Restangular = _Restangular_;
MatchController = $controller('MatchController', {
APP_CONFIG: _APP_CONFIG_,
$authUser: _$authUser_,
$http: _$http_,
$rootScope: _$rootScope_,
$state: _$state_,
$stateParams: _$stateParams_,
SearchService: _SearchService_,
ConfirmMatchService: _ConfirmMatchService_,
MusicOpsService: _MusicOpsService_,
ContentOpsService: _ContentOpsService_,
MatchstickService: _MatchstickService_,
MatchService: _MatchService_,
Restangular: _Restangular_
});
}));
describe("Match controller to be defined", function() {
it("should be created successfully", function () {
expect(MatchController).toBeDefined();
});
});
});
})();
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 am not clear how to use SpyOn in Unit Testing...
I have the following controller
(function () {
'use strict';
angular.module('otpConfigureDatasets').controller('otpActivityCardController', otpActivityCardController);
otpActivityCardController.$inject = ['$location', '$state', 'otpWebMapApp', 'otpWMDeltaTracker', 'otpWMStateCache', '$scope', '$timeout', 'otpActivityCardService', 'otpControlCenterData'];
function otpActivityCardController($location, $state, otpWebMapApp, otpWMDeltaTracker, otpWMStateCache, $scope, $timeout, otpActivityCardService, otpControlCenterData) {
var vm = this;
vm.cards = [];
otpActivityCardService.getActivityCards().then(function (resolve) {
vm.cards = resolve;
});
//.....Some code ....
})();
I need to test the GetActivityCards().then(function ...
I tried test it using the code below
'use strict';
describe('Test controller (activityCard) in Page MyDatasets', function() {
var MainCtrl, $state, scope, otpWebMapApp, otpWMDeltaTracker, otpWMStateCache, otpActivityCardService, otpControlCenterData;
var card;
beforeEach(function() {
module('otpConfigureDatasets');
});
beforeEach(inject(function ($controller, $rootScope, _$state_, _otpWebMapApp_, _otpWMDeltaTracker_, _otpWMStateCache_, _otpActivityCardService_, _otpControlCenterData_) {
scope = $rootScope.$new();
scope.$parent = { $parent: { menuParentGroupClick: function menuParentGroupClick() { } } };
MainCtrl = $controller('otpActivityCardController', {
$scope: scope
});
otpWebMapApp = _otpWebMapApp_;
otpWMDeltaTracker = _otpWMDeltaTracker_;
otpWMStateCache = _otpWMStateCache_;
otpActivityCardService = _otpActivityCardService_;
otpControlCenterData = otpControlCenterData;
}));
it('Test Function', function() {
spyOn(otpActivityCardService, 'getActivityCards');
expect(otpActivityCardService.getActivityCards).toHaveBeenCalled();
});
});
But I am getting this error:
Expected spy getActivityCards to have been called.
Error: Expected spy getActivityCards to have been called.
What is wrong?
You created a spy to the "getActivityCards" function, but you didn't call it in your test (unless you hid this line of code from the example).
When you create a Jasmine Spy to a function, you are only "watching" this function, you can check if it was called, you can mock the return values of it, you can check the parameters of a call to it, i.e, you can check a lot of things about the call history of the function, but you still need to explicity make a call to the function (or to a function in your controller that calls the spied function from it).
So you are spying the Service, and you are testing the Controller, your test should look something like:
it('Test Function', function() {
spyOn(otpActivityCardService, 'getActivityCards');
otpActivityCardService.getActivityCards();
expect(otpActivityCardService.getActivityCards).toHaveBeenCalled();
});
On a side note, to be more testable, your controller should encapsulate your service call in a function in your controller, like:
(function () {
'use strict';
angular.module('otpConfigureDatasets').controller('otpActivityCardController', otpActivityCardController);
otpActivityCardController.$inject = ['$location', '$state', 'otpWebMapApp', 'otpWMDeltaTracker', 'otpWMStateCache', '$scope', '$timeout', 'otpActivityCardService', 'otpControlCenterData'];
function otpActivityCardController($location, $state, otpWebMapApp, otpWMDeltaTracker, otpWMStateCache, $scope, $timeout, otpActivityCardService, otpControlCenterData) {
var vm = this;
vm.cards = [];
vm.getCards = function () {
otpActivityCardService.getActivityCards().then(function (resolve) {
vm.cards = resolve;
});
}
vm.getCards();
//.....Some code ....
})();
So you could create a test that really tested a function in your controller (because the way you are describing your test case, it really should be a Service test only)
it('Better test case', function() {
spyOn(otpActivityCardService, 'getActivityCards');
MainCtrl.getCards();
expect(otpActivityCardService.getActivityCards).toHaveBeenCalled();
});
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.