Why simple JasmineJS and AngularJS based unit test not working - javascript

I am trying to write a simple test using Jasmine. The test checks if $scope.testFlag is set to false.
Here is my test code
describe('Abc Controller', function() {
var $scope = null;
var ctrl = null;
//you need to indicate your module in a test
beforeEach(module('myApp'));
beforeEach(inject(function($rootScope, $controller) {
$scope = $rootScope.$new();
ctrl = $controller('abcController', {
$scope: $scope
});
}));
// test 1
it('testFlag should be set to False', function() {
expect( $scope.testFlag).toEqual(false);
});
});
But for some reason I get this error:
Error: Unknown provider: ConfigProvider <- Config <- collectionMetaFactory
Here is how my application's app.js looks like which I am including in testRunner.html
var app = angular.module('myApp')
app.constant('Config',
{
baseURL : serviceURL,
httpTimeout : 3600000 // 1 minute
});
app.config(function($logProvider) {
$logProvider.debugEnabled(true);
});
What am I missing?
Here is controller's snippet
app.controller('abcController', function ($scope, $log,abcFactory, Config) {
$scope.testFlag = false;
// more code follows
});
Let me know if you need see more of the application's code (like factory, services and controller)

You haven't provided your test with Config, so it doesn't recognize what Config is and that's why you are getting this error.
A solution would be to inject Config into your test by using the $provide module. Here's how:
describe('Abc Controller', function() {
var $scope = null;
var ctrl = null;
var Config = {
baseURL : 'someURL',
httpTimeout : 3600000 // 1 minute
};
beforeEach(function(){
beforeEach(module('myApp'));
module(function (_$provide_) {
$provide = _$provide_;
$provide.value('Config', Config);
});
});
//you need to indicate your module in a test
beforeEach(inject(function($rootScope, $controller) {
$scope = $rootScope.$new();
ctrl = $controller('abcController', {
$scope: $scope
});
}));
// test 1
it('testFlag should be set to False', function() {
expect( $scope.testFlag).toEqual(false);
});
});
This should run the tests successfully.
Hope this helps others facing a similar problem.

Related

Unable to unit test http call happening through the controller

I am trying to write a code to test the service call which is done in my controller . I am trying to unit test that particular function in controller which is doing the service call and bringing the data . Currently i am trying with local json , but it will actually do a service call .
I got to know that first i have to create a spy object but i am getting the error, my goal is to successfully unit test the http call happening in the controller.
i am new to unit testing .Pasting my code , request you to help me please , struggling in this from many days now.Also i have gone through many solutions , they are so different making be confused.Your help is greatly appreciated
Service code :
//xlpApp is the module name
xlpApp.factory('xlpServices', ['$rootScope', '$http', function($rootScope,
$http) {
var xlpServices = {};
xlpServices.getProgramData = function(){
return $http.get(scripts/services/data/unitTesting.json');
};
unitTesting.json code :
{
"name":"unit testing"
}
Controller Code :
$scope.events = {
programData: function(){
xlpServices.getProgramData().then(function(response) {
if (response && response.data) {
$scope.testVariable= response.data.name;
}
});
},
selectSortingType : function(type) {
$scope.selectedSorting = type;
selectedFilter.sortingBy = $scope.selectedSorting;
}
}
$scope.events.programData();
Unit Test Code :
describe('myProgramGpmCtrl', function() {
beforeEach(module('xlp'));
var $controller;
beforeEach(inject(function(_$controller_){
$controller = _$controller_;
}));
describe('service call test', function() {
var xlpServices , myService , $q;
var $scope = {};
beforeEach(inject(function(xlpServices,_$q_){
xlpServices = xlpServices;
$q = _$q_;
var controller = $controller('myProgramGpmCtrl', { $scope: $scope });
myService = jasmine.createSpyObj('xlpServices',['getProgramData']);
}));
it('Service call test ', function() {
expect(myService.getProgramData).toHaveBeenCalled();
});
});
});
ERROR :
Expected spy xlpServices.getProgramData to have been called.
Try something like,
describe('service call test', function() {
var xlpServicesMock , myService , $q;
var $scope = {};
beforeEach(inject(function(xlpServices,_$q_){
xlpServicesMock = xlpServices;
$q = _$q_;
spyOn(xlpServicesMock ,'getProgramData').and.callFake(function() {
// we can return promise instead this custom object
return {
then: (callback, errorCallback) => {
callback('data to be passed to then callback');
/* `callback` function should be invoked when you wanted to test the service for success response with status code 200.
`errorCallback` function should be invoked with 500 status code when you wanted to test the api failure
Ex: callback({status: 200, data: <your data here>);
errorCallback({status: 500, data: <your error data>})
You can prepare the response to be passed as you wanted.
*/
}
};
});
var controller = $controller('myProgramGpmCtrl', { $scope: $scope, xlpServices: xlpServicesMock });
}));
it('Service call test ', function() {
$scope.events.programData();
expect(myService.getProgramData).toHaveBeenCalled();
});
});
There are good resources available online.
check here and here

testing angular controller (method / service calls) using Jasmine

I am trying to test a small controller written in AngularJS using Jasmin.
(function() {
'use strict';
angular
.module('bsp.account')
.controller('Account', Account);
/* #ngInject */
function Account(userService, accountService) {
var vm = this;
vm.title = 'Account';
vm.username = userService.getUsername();
vm.showPasswordModal = accountService.showPasswordModal;
vm.showLogoutModal = accountService.showLogoutModal;
}
})();
I want to test vm.username ,vm.showPersonModal and vm.showLogoutModal.these are all the reference to the service injected in the controller.
I am fairly new and slowly trying to build my concept in testing.
Below is the piece of test cases running now,
describe('Account', function() {
var scope, controller, userServiceMock,accountServiceMock;
beforeEach(module('bsp'));
beforeEach(function() {
userServiceMock = {
getUsername: function(){}
};
accountServiceMock = {
showPasswordModal :function(){}
};
});
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('Account');
});
});
});
Thank You for all your suggestions
Only problems I can see is that
You're bootstrapping the wrong module (should be 'bsp.account' instead of 'bsp')
You've not provided a means to test that your service methods are called
You can address the latter using spies. For example
describe('Account', function() {
var controller, userServiceMock, accountServiceMock;
beforeEach(function() {
module('bsp.account');
userServiceMock = jasmine.createSpyObj('userService', ['getUsername']);
userServiceMock.getUsername.and.returnValue('testUser');
accountServiceMock = jasmine.createSpyObj('accountService', ['showPasswordModal', 'showLogoutModal']);
inject(function($controller) {
controller = $controller('Account', {
userService: userServiceMock,
accountService: accountServiceMock
});
});
});
it('assigns values from services', function() {
expect(userServiceMock.getUsername).toHaveBeenCalled();
expect(controller.username).toEqual('testUser');
expect(controller.showPasswordModal).toBe(accountServiceMock.showPasswordModal);
expect(controller.showLogoutModal).toBe(accountServiceMock.showLogoutModal);
});
});

Angular Jasmine UI router inject resolve value into test

In my Angular app, UI router resolves a promise into the controller. When trying to test this controller, Karma is complaining about an unknown provider. How do I inject a fake object into the test to represent this resolve object.
My app's code looks something like:
angular.module('myapp')
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('tab.name', {
...
resolve: {
allTemplates: function(Templates) {
return Templates.all().then(function(templates) {
return templates;
});
}
}
})
})
.controller('QueriesCtrl', function(allTemplates, UserQuery) {
var vm = this;
vm.queries = allTemplates;
vm.goToUrl = function(index, data) {
var processedUrl = UserQuery.process(data, vm.queryTyped[index]);
UserQuery.goToUrl(processedUrl);
};
});
When trying to run tests I get the error
Unknown provider: allTemplatesProvider <- allTemplates <- QueriesCtrl
I've tried creating a spy and injecting it, but this does not work. Here's my test at the moment:
describe('Unit: queriesCtrl', function() {
var controller,
scope,
UserQuery;
beforeEach(function() {
module('myapp');
inject(function($injector) {
UserQuery = $injector.get('UserQuery');
allTemplates = jasmine.createSpyObj('allTemplates', [{a:1}, {a:2}, {b:3}]);
});
});
describe('goToUrl', function() {
beforeEach(inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
controller = $controller('QueriesCtrl as ctrl', {
'$scope': scope
});
}));
it('should call UserQuery.process()', function() {
spyOn(UserQuery, 'process');
scope.ctrl.goToUrl();
expect(UserQuery.process).toHaveBeenCalled();
});
});
});
Since there is no route involved in unit test you would have to inject the allTemplates as a normal object with $controller function. Can you try:
controller = $controller('QueriesCtrl as ctrl', {
'$scope': scope,
'allTemplates':allTemplates
});
Else you can use the $provide API to create a dummy service.
module(function ($provide) {
$provide.value("allTemplates", {[{a:1}, {a:2}, {b:3}]});
Do it first thing in your beforEach block.

Angular UI-Router verify onEnter in test

I am in the middle of writing some tests for my application (AngularJS).
As we speak I encountered a problem with verifying if onEnter property of my state was called correctly.
Let me share some code with You
describe('Midway :: routesTest', function () {
var $state,
$rootScope,
$injector,
navigationService;
beforeEach(function () {
module('springatom', function ($provide) {
$provide.value('navigationService', navigationService = {});
});
states.configure();
inject(function (_$rootScope_, _$state_, _$injector_, $templateCache) {
$rootScope = _$rootScope_;
$state = _$state_;
$injector = _$injector_;
// We need add the template entry into the templateCache if we ever
// specify a templateUrl
$templateCache.put('/static/sa/views/home/home.html', '');
$templateCache.put('/static/sa/tpls/grid.html', '');
});
navigationService.getNavigationModel = jasmine.createSpy('getNavigationModel').and.returnValue([]);
navigationService.setNavigatorModel = jasmine.createSpy('setNavigatorModel').and.callFake(function (arg) {
});
});
it("should have a working home route", inject(function () {
var homeState = $state.get('home');
expect(homeState).toBeDefined();
expect($state.href(homeState)).toEqual('#/sa');
$rootScope.$apply(function () {
$state.go(homeState);
});
var current = $state.current;
expect($injector.invoke(current.resolve.actionModel)).toEqual([]);
expect($injector.invoke(current.onEnter)).toHaveBeenCalled();
}));
});
The failing assertion is the last one I am trying to verify therefore mentioned onEnter.
Error is:
Error: [$injector:unpr] Unknown provider: actionModelProvider <- actionModel
http://errors.angularjs.org/1.3.8/$injector/unpr?p0=actionModelProvider%20%3C-%20actionModel
As it is expected Angular tries to resolve actionModel which is the property from the resolve.
I dont know what I might be doing wrong here, so any help will be gladly welcomed.
I am attaching the state configuration as well:
define(
[
'views/home/homeController',
'views/home/recentlyUpdatedController',
// angular deps
'services/navigation'
],
function homeState(homeController, recentlyUpdatedController) {
return {
name : 'home',
definition: {
url : '/sa',
templateUrl: '/static/sa/views/home/home.html',
resolve : {
actionModel: function (navigationService) {
return navigationService.getNavigationModel('main.navigation')
}
},
onEnter : function (actionModel, navigationService) {
navigationService.setNavigatorModel('main.navigation');
},
views : {
'': {
controller : recentlyUpdatedController,
templateUrl: '/static/sa/tpls/grid.html'
}
}
}
}
}
);

angularjs karma test typeerror $route

I am trying to test a controller for angularjs using karma, the controller inject a $route to get the current path but when I try to run karma test on it I get.
TypeError: 'undefined' is not an object( evaluating '$route.current')
Here is my controller:
angular.module('myApp').controller('EditController',['$scope', '$http', '$route', function($scope,
$http,$route){
var myId = $route.current.params.myId;
$scope.var1 = 'var1';
console.log(myId);
}]);
Here is my Karma file:
'use strict';
describe('Controller: EditController', function(){
beforeEach(module('myApp'));
var EditCtrl,scope,route;
beforeEach(inject(function($controller,$rootScope,$route,$http){
scope=$rootScope.$new();
EditCtrl = $controller('EditCtrl',{
$scope:scope,
$route:route
});
}));
it('should have var1 equal to "var1"',function(){
expect(scope.var1).toEqual('var1');
});
});
Your beforeEach hook isn't injecting the $route service. Change it to this.
beforeEach(inject(function($controller,$rootScope,$route,$http){
scope=$rootScope.$new();
route = $route;
EditCtrl = $controller('EditCtrl',{
$scope:scope,
$route:route
});
}));
You may also want to mock the $route.current object in case it isn't instantiated properly, since there's no routing going on in your test. In which case you could just add
$route.current = { params: { myId: 'test' } };
in the hook as well.

Categories

Resources