Mock a function present in angularJS controller using jest - testing - javascript

I've a small controller written in angularJS.
1st function is actually calling a 2nd one to perform a calculation and return it back.
I want to mock the 2nd function in my testing, so that it returns value I've provided in mock instead of calling the function.
ABCService.js
var app = angular.module('mathModule', []);
app.controller('mathService', ['$scope', function($scope){
$scope.first = 0;
$scope.second = 0;
$scope.addTwoNumbers = function(x, y) {
return x + y;
};
$scope.callAddFunction = function() {
return $scope.addTwoNumbers(10, 20);
}
}]);
ABCServic.test.js
require('./mathService.js');
describe('Math service', function() {
beforeEach(
angular.mock.module('mathModule')
);
var $controller;
beforeEach(inject(function(_$controller_) {
$controller = _$controller_;
}));
describe('Test using 2 numbers', function() {
var $scope, controller;
beforeEach(function() {
$scope = {};
controller = $controller('mathService', { $scope: $scope });
});
it("Nested function", function() {
var total = $scope.callAddFunction();
expect(total).toEqual(31);
});
});
});
Here I want to mock addTwoNumbers() so that instead of calling we get value we've provided during testing.
Something like, Mock(addTwoNumbers(x,y)) = 0, so now callAddFunction will return 0 instead of 30, which it should be returning if not mocked.

Related

bcbankApp.accsummary module AccountSummaryController should have a getAccountSummary function FAILED in angular js

I am working on Banking app using Angularjs on hackerrank where I am stuck at point.I am trying to call my function from Account summary controller but It is saying that No such function exist in my controller
Here is my code
AccountSummarycontroller.js
// Create the controller AccountSummaryController with getAccountSummary function that access accountSummaryService which is already defined in account-summary.service.js. Use $state for Transition from one page to another.
(function() {
'use strict';
var appContr = angular.module('abcbankApp.accountSummary', ['abcbankApp.accountSummaryService']);
appContr.controller('AccountSummaryController', function(AccountSummaryService) {
var ActSumCtrl = this;
// this.AccountSummaryService.getAccountSummary();
ActSumCtrl.accountList = [];
ActSumCtrl.accountList = AccountSummaryService.getAccountSummary();
});
})();
AccountSumaaryService.js
// Create the service AccountSummaryService with getAccountSummary function which should return the account details from data/account-summary.json using $http.get.
(function() {
'use strict';
var appServc = angular.module('abcbankApp.accountSummaryService', []);
appServc.factory('AccountSummaryService', ['$http',
function($http) {
return {
getAccountSummary: function() {
var data;
$http.get('./data/account-summary.json')
.then(function(response) {
data = response.data;
});
return data;
}
};
}]);
})();
But I am getting error something like below
abcbankApp.accsummary module AccountSummaryController should have a getAccountSummary function FAILED.Expected false to be true.
Testfile.js
describe('AccountSummaryController', function() {
it('Controller definition', function() {
expect(AccountSummaryController).toBeDefined();
});
it('should have a getAccountSummary function', function() {
expect(angular.isFunction(AccountSummaryController.getAccountSummary)).toBe(true);
});
});
});
})();
Any Help will be Appreciated.Thanks in advance
Well to answer your question lets begin with your test case as it is showing that AccountSummaryController.getAccountSummary should be defined
So you should call your function with your controller name and function name
Here is modified code
(function() {
'use strict';
var appContr = angular.module('abcbankApp.accountSummary', ['abcbankApp.accountSummaryService']);
appContr.controller('AccountSummaryController', function(AccountSummaryService) {
var ActSumCtrl = this;
// this.AccountSummaryService.getAccountSummary();
ActSumCtrl.accountList = [];
ActSumCtrl.getAccountSummary=function()
{
//move your logic here
}
ActSumCtrl.accountList = AccountSummaryService.getAccountSummary();
});
})();
Let me know in comment weather it worked or not

Checking whether a function is called when another function is triggered

I am new to AngularJS and Jasmine. Given the following controller, how do I test whether the allPanelsRetrieved() function is called when the $scope.getPanels is triggered?
angular.
module('panelList').
controller('PanelListController', ['Panel', 'PanelSelection', '$scope', '$location', '$uibModal', '$rootScope',
function PanelListController(PanelSelection, $scope, $location, $uibModal, $rootScope) {
$scope.maxAbv = 2;
$scope.minAbv = 12;
this.allPanelsRetrieved = (index, before, filterParams) => {
.....
};
$scope.getPanels = () => {
const filterParams = {};
filterParams.abv_lt = $scope.minAbv;
filterParams.abv_gt = $scope.maxAbv;
$scope.currentPagePanels = this.allPanelsRetrieved (1,[], filterParams);
};
}]).
component('panelList', {
templateUrl: '/components/panel-list/panel-list.template.html',
controller:'PanelListController',
});
Assuming you want allPanelsRetrived to be called, then simply use a boolean.
var bool = false
this.allPanelsRetrieved = (index, before, filterParams) => {
.....
bool=true;
};
$scope.getPanels = () => {
if (bool) {
const filterParams = {};
filterParams.abv_lt = $scope.minAbv;
filterParams.abv_gt = $scope.maxAbv;
$scope.currentPagePanels = this.allPanelsRetrieved (1,[], filterParams);
} else {
// allPanelsRetrieved was not called
}
};
I can see that allPanelsRetrieved seems to be a private(local) method and used inside that controller.
You need not test private(local) methods execution.
If you still want to check if the method is triggered or not you can use jasmine's toHaveBeenCalled() method
execept(myMethod).toHaveBeenCalled();
passes when method is called.

How to unit test .then function with jamsine

I have written one component which post data from some service.
Am not able to cover then function in Unit Test. How to enter test `then' function?
angular.module('myapp')
.component('performAnalysis', {
templateUrl: 'analysis.component.html',
controller: PerformAnalysisController,
controllerAs: 'vm'
});
function PerformAnalysisController(UnitySizerService, SizingService, MarshallDTO, CommonService) {
let vm = this;
vm.$onInit = $onInit;
function $onInit() {
let unitySizerDTO = MarshallDTO.generateDTO();
let previousDTO = CommonService.getProperty('previousDTO');
vm.dataChanged = JSON.stringify(unitySizerDTO) === JSON.stringify(previousDTO);
/* Call Backend API only if DTO is changed */
if (!vm.dataChanged) {
/* Loader On */
vm.activateLoader = true;
SizingService.postSizingResults(unitySizerDTO).then(function (data) {
UnitySizerService.resultSummary = data;
/* New Data coming from Backend */
vm.dataChanged = true;
/* Loader Off */
vm.activateLoader = false;
CommonService.setProperty('previousDTO', unitySizerDTO);
vm.unitySizerService = UnitySizerService;
});
}
else {
vm.unitySizerService = UnitySizerService;
}
}
}
This is test file which I have written, but am not able to cover then function inside this:
describe('my Component', function () {
beforeEach(module('myApp'));
let vm;
let $rootScope;
let $componentController;
let UnitySizerService, SizingService;
beforeEach(inject(function (_$componentController_, _$rootScope_, _UnitySizerService_, _SizingService_) {
$componentController = _$componentController_;
$rootScope = _$rootScope_;
UnitySizerService = _UnitySizerService_;
SizingService = _SizingService_;
vm = $componentController('performAnalysis');
}));
it('should be defined', function () {
expect(vm).toBeDefined();
expect(vm.$onInit).toBeDefined();
expect(UnitySizerService).toBeDefined();
});
it('should show loader', function () {
vm.$onInit();
vm.dataChanged = false;
expect(vm.activateLoader).toBeTruthy();
});
});
In order to mock .then of a Promise in jasmine, you can do something like this
var deferred = $q.defer();
var whatServiceReturns = "test";
// we are returning promise from service function
SizingService.postSizingResults.and.returnValue({$promise:deferred.$promise});
// now let's call the original function
vm.$onInit();
// we will resolve our promise so that we can reach inside 'then'
// here, 'whatServiceReturns' resembles your 'data' parameter in 'then' function
deferred.resolve(whatServiceReturns);
$rootScope.$digest();
// here we can expect things like 'dataChanged' and 'activateLoader' if we see from your example
expect(...).toEqual(...);
You can use deferred.reject(someError); for error.
Edit: added comments to elaborate the code

Testing that an $interval gets fired 3 times in AngularJS

I have an AngularJS service that looks like this (I've removed the unrelevant code):
myApp.factory('myService', ['$interval', function ($interval) {
return {
startWatch: function(onSuccess) {
var watcher = $interval(onSuccess, 250);
return watcher;
},
stopWatch: function(watcher) {
$interval.cancel(watcher);
}
};
}]);
To test this service, I have the following:
describe('myApp', function() {
beforeEach(function() {
module('myApp');
});
describe('myService', function () {
var myService = null;
beforeEach(inject(function (myService) {
myService = myService;
}));
it('should run successfully 3 times', function() {
var count = 0;
var w = myService.startWatch(function() {
count = count + 1;
console.log('fired ' + count + ' times.');
});
});
});
});
When the test gets ran, it just races through it one time. I do not understand how to actually test 1. the interval piece 2. the number of times it gets fired. There will be information in the service that changes over time. I want to test that the information is behaving as expected. For that reason, I'm trying to test a number of things over time. How do I do this?
Thank you for your help!
Try $interval.flush(millis):
describe('myApp', function() {
beforeEach(function() {
module('myApp');
});
describe('myService', function () {
var myService = null;
var $interval = null;
beforeEach(inject(function (myService) {
myService = myService;
$interval = _$interval_;
}));
it('should run successfully 3 times', function() {
var count = 0;
var w = myService.startWatch(function() {
count = count + 1;
});
$interval.flush(751); // greater than 250 * 3
expect(count).toEqual(3);
});
});
});
Remember to reference angular mock to your test: http://code.angularjs.org/1.2.0/angular-mocks.js .The version should be the same with your angular version.

angular watch object not in scope

I have a service in which values can change from outside Angular:
angularApp.service('WebSocketService', function() {
var serviceAlarms = [];
var iteration = 0;
this.renderMessages = function(alarms, socket) {
if (! angular.equals(serviceAlarms, alarms)) {
serviceAlarms = alarms;
iteration++;
}
};
this.getAlarms = function () {
return serviceAlarms;
};
this.iteration = function () {
return iteration;
};
this.socket = initSocketIO(this);
});
The initSocketIO function makes callbacks to this services renderMessages() function and serviceAlarms variable gets changed on a steady basis.
Now i am trying to watch for changes in this service like so:
controllers.controller('overviewController', ['$scope', 'WebSocketService', function ($scope, WebSocketService) {
$scope.$watch(
function () {
return WebSocketService.iteration();
},
function(newValue, oldValue) {
$scope.alarms = WebSocketService.getAlarms();
},
true
);
}]);
to no avail. The second function provided to $watch never gets executed except on controller initialization.
I have tried with and without true as third parameter.
You should use $rootScope.$watch (not $scope.$watch)
I ended up using the solution below since $watch didn't work as excpected.
I refactored the solution to use $rootScope in combination with:
angularApp.run(['$rootScope', function($rootScope){
$rootScope.socket = {};
$rootScope.socket.alarms = [];
$rootScope.socket.faults = [];
$rootScope.socket.renderErrors = function(faults, socket) {
var faultArray = [];
angular.forEach(faults, function(error) {
error.value ? faultArray.push(error) : null;
});
if (! angular.equals($rootScope.socket.faults, faultArray)) {
$rootScope.socket.faults = faultArray;
$rootScope.apply();
}
};
$rootScope.socket.renderMessages = function(alarms, socket) {
if (! angular.equals($rootScope.socket.alarms, alarms)) {
$rootScope.socket.alarms = alarms;
$rootScope.$apply();
}
};
$rootScope.socket.socket = initSocketIO($rootScope.socket);
}]);
Now i have my socket-updated-model in all scopes to use freely in controllers and views.
Controller example:
$scope.acknowledgeAlarm = function(alarm) {
$scope.socket.socket.emit('acknowledgeAlarm', {
hash:alarm.icon.hash,
id:alarm.id
});
};
View example:
<div ng-repeat="alarm in socket.alarms">
{{alarm.name}} {{alarm.icon.progress}}
</div>

Categories

Resources