Issue with Jasmine when mocking a service - javascript

I am having a controller like below
(function () {
var mockController = function ($scope, MockService) {
$scope.message = "This is a text message";
$scope.getCities = function () {
return MockService.getCities();
};
};
var mockService = function ($http) {
this.getCities = function () {
return $http.get("../rest/url", {
headers: {
'Accept': 'application/yang.data+json'
}
});
};
};
angular.module("MockApp", [])
.service("MockService", mockService)
.controller("MockController", mockController);
}())
I am trying to write a UT mocking the service like below
describe("MockController", function () {
var $scope;
beforeEach(function () {
module("MockApp");
inject(function (_$controller_, _$rootScope_, MockService) {
$scope = _$rootScope_.$new();
spyOn(MockService, "getCities").and.callFake(function () {
return [{
city: "Bangalore"
, country: "India"
}];
});
controller = _$controller_("MockController", {
$scope: $scope
});
});
});
describe("Test", function () {
it("Should be Bangalore", function () {
$scope.getCities()
.then(function (data) {
console.log("got it");
})
});
});
});
Its throwing an error saying
TypeError: $scope.getCities(...).then is not a function
Please help me.

I think:
$scope.getCities = function () {
return MockService.getCities();
};
should be:
$scope.getCities = function () {
return MockService(getCities());
};

Related

Spying on a method which calls another api method internally

I have a function inside a controller, which calls a method of an object "mapping".
$scope.createParameter = function (parameter) {
var apiObj = {};
mapping.createApiService(apiObj)
}
that object structure is as follows, and this method 'createApiService' calls a 'create' method of apiService.
var mapping = {
createApiService : apiService.create
}
I have injected that apiService into my Testsuite. and a spyon is also been added as follows.
spyOn(apiService, "create").and.callFake(function () {
return {
then: function (callback) {
callback(createResponse);
return {
catch: function () {
}
}
}
}
but when I execute my it block with following expectation it gives an error "expected spy create to have been called.
expect(apiService.create).toHaveBeenCalled();
can some one help me with this?
EDIT: Added testing code
describe("Controller", function () {
beforeEach(angular.mock.module("ui.router"));
beforeEach(angular.mock.module("PpmApp"));
var $controller, $scope, $state, $httpBackend, parameterDetails, apiService, constantsProvider;
beforeEach(inject(function (_$controller_, _$rootScope_, _$state_, _$httpBackend_, _apiService_, _constantsProvider_) {
$controller = _$controller_;
$scope = _$rootScope_.$new();
$state = _$state_;
$scope.header = {};
$state.current = {};
$httpBackend = _$httpBackend_;
apiService = _apiService_;
constantsProvider = _constantsProvider_;
$controller = $controller("Controller", { "$scope": $scope, "parameterDetails": parameterDetails });
}));
describe("create", function () {
it("should succeed with valid Input", function () {
var parameter = {
ParameterType: 1,
ParameterId: 2,
LookupCurveStructures: [{
Name: "Parameter name",
XAxisName: "XAxisName",
YAxisName: "YAxisName",
XAxisDataType: 1,
YAxisDataType: 2
}]
};
var createResponse = {
Data: [],
IsSuccess: true,
Message: "Parameter added successfully"
};
spyOn(apiService, "create").and.callFake(function () {
return {
then: function (callback) {
callback(createResponse);
return {
catch: function () {
}
}
}
}
});
$scope.createParameter(parameter);
expect($scope.createPopupInfo.validationErrors.isError).toEqual(false);
expect(apiService.create).toHaveBeenCalled();
expect($scope.parameterDetails.Parameters).toEqual([]);
});
});
});

Mocking service inside a service in AngularJS

I have the following services:
DataService.js
app.service("DataService", [
function () {
this.getData = function () { return "original value" }
}
]);
LocationService.js
app.service("LocationService", ["DataService",
function(dataSvc) {
this.getLocationData = function () {
return dataSvc.getData();
}
}
]);
Now for testing LocationService.js, how do mock DataService inside of LocationService?
This is what I currently have for LocationService_tests.js:
describe("LocationService", function () {
var locationSvc;
beforeEach(module('myModule'));
beforeEach(inject(function (LocationService) {
locationSvc = LocationService;
}));
describe("getLocationData", function () {
it("returns the location data", function () {
var mockLocationDataValue = "mocked value";
// ???
// I want to mock dataSvc.getData within getLocationData
// so it returns "mocked value" instead of "original value"
expect(locationSvc.getLocationData()).toBe(mockLocationDataValue);
});
});
});
You could mock whole service using $provide API's service method, and change your service to returned mock data.
describe("LocationService", function () {
var locationSvc;
beforeEach(module('myModule'));
beforeEach(module(function($provide) {
$provide.service('LocationService', function() {
this.getData = function() {
return "mock value";
}
});
});
beforeEach(inject(function (LocationService) {
locationSvc = LocationService;
}));
...
});

Unit-testing $timeout execution inside an async call

I'm trying to unit-test a piece of my code contained inside an async call, like this:
function init() {
asyncFunc().then(function (data) {
$timeout(function () {
$scope.isInside = true;
});
});
}
The whole code:
(function (angular) {
// Create module
var myApp = angular.module('myApp', []);
// Controller which counts changes to its "name" member
myApp.controller('MyCtrl', ['$scope', '$http', '$timeout', function ($scope, $http, $timeout) {
$scope.isInside = false;
init();
function init() {
asyncFunc().then(function (data) {
$timeout(function () {
$scope.isInside = true;
});
});
}
function asyncFunc() {
return new Promise((resolve, reject) => {
$http.get('https://httpbin.org/get').success((data) => {
resolve(data);
}).error((error) => {
reject(error);
});
});
}
}]);
})(angular);
My intention is to test the $scope.isInside value. This is my test:
describe('myApp', function () {
var scope,
controller;
beforeEach(function () {
module('myApp');
});
describe('MyCtrl', function () {
var $httpBackend, endpointCall, $timeout;
beforeEach(inject(function ($rootScope, $controller, _$httpBackend_, _$timeout_) {
$httpBackend = _$httpBackend_;
$timeout = _$timeout_;
endpointCall = $httpBackend.expect('GET', 'https://httpbin.org/get').respond({data: 'data'});
scope = $rootScope.$new();
controller = $controller('MyCtrl', {
'$scope': scope
});
}));
it('initializes', function () {
$httpBackend.flush();
$timeout.flush();
expect(scope.isInside).toBe(true);
});
});
});
The test is failing, the value is "false", but I'm expecting to see a "true" there.
JSFiddle here: http://jsfiddle.net/KarmaCop213/tj6akcyk/1/

Angular JS UT to verify whether a method on service is called or not

I am having a controller like below
(function () {
var newPlaceController = function ($scope, PlacesService, $mdDialog) {
$scope.newPlace = {
"city": "",
"country": ""
};
$scope.addCity = function () {
$scope.places.push($scope.newPlace);
PlacesService.addCity($scope.newPlace);
$mdDialog.hide();
};
$scope.cancel = function(){
$mdDialog.hide();
};
};
angular.module("module.place")
.controller('NewPlaceController', newPlaceController);
}());
Also I have a test file like below which tests whether the initialization value of newPlace is correct.The code is like below
describe("NewPlaceController", function () {
var $scope, ctrl;
beforeEach(module("module.place"));
beforeEach(
inject(function (_$controller_) {
$scope = {};
controller = _$controller_('NewPlaceController', {
$scope: $scope
});
}));
describe("Initialization", function () {
it("asdasd", function () {
expect($scope.newPlace).toEqual({
city: ''
, country: ''
});
})
});
});
It's working fine. My doubt is how can I test the addCity and cancel functions in the controller.
You can use it like this
it("Should call addCity", function () {
var spy = spyOn(PlacesService, 'addCity');
controller.addCity();
expect(spy).toHaveBeenCalled();
})
it("Should call mdDialog hide", function () {
var spy = spyOn($mdDialog, 'hide');
controller.cancel();
expect(spy).toHaveBeenCalled();
})

How to test a controller function calling a private function that in turn calls a asynchronous function in angularjs

[plunkr][1]http://plnkr.co/edit/Jk1Rp3nEgUQTmDOs3xBl?p=preview
My current code is structured as below.
angular.module("app",[])
.service("dataService",function($http){
this.get = function (url) {
return $http.get(url);
};
})
.service("mainService",function(dataService){
this.getData = function(pattern){
return dataService.get(pattern+"/abc");
}
})
.controller("mainController",function($scope,mainService){
$scope.refreshData = function(pattern){
loadData(pattern);
}
function loadData(pattern){
mainService.getData(pattern)
.success(function(data){
console.log(data);
})
.error(function(error){
console.log(error);
})
}
})
I have been trying to make sense of how to test it by reading blogs but each blog has either a different approach or the blog is 2-3 years old. I would like to know how do I test the controller?
Should I test each function? If yes, then how should I test the private function? Is using the private function a good idea or should I just add the private function code to the scoped function?
Also is there any better way to do write this function?
Most important part where we are going to create stub:
beforeEach(function() {
var $httpResponse = {
success: function() {
return $httpResponse;
},
error: function() {
return $httpResponse;
}
};
var _stubMainService_ = {
getData: jasmine.createSpy('getData').and.returnValue($httpResponse)
};
angular.module('app')
.value('mainService', _stubMainService_);
});
and test that uses it:
it('rereshes data', function() {
var pattern = 'abcde';
scope.refreshData(pattern);
expect(mainService.getData).toHaveBeenCalledWith(pattern);
});
angular.module("app", [])
.service("dataService", function($http) {
this.get = function(url) {
return $http.get(url);
};
})
.service("mainService", function(dataService) {
this.getData = function(pattern) {
return dataService.get(pattern + "/abc");
}
})
.controller("mainController", function($scope, mainService) {
$scope.refreshData = function(pattern) {
loadData(pattern);
}
function loadData(pattern) {
mainService.getData(pattern)
.success(function(data) {
console.log(data);
}).error(function(error) {
console.log(error);
})
}
})
describe('mainController()', function() {
var scope, controller, mainService, $q;
beforeEach(module('app'));
beforeEach(function() {
var $httpResponse = {
success: function() {
return $httpResponse;
},
error: function() {
return $httpResponse;
}
};
var _stubMainService_ = {
getData: jasmine.createSpy('getData').and.returnValue($httpResponse)
};
angular.module('app')
.value('mainService', _stubMainService_);
});
beforeEach(inject(function($controller, $rootScope, _mainService_) {
scope = $rootScope.$new();
controller = $controller('mainController', {
$scope: scope
});
mainService = _mainService_;
}));
it('rereshes data', function() {
var pattern = 'abcde';
scope.refreshData(pattern);
expect(mainService.getData).toHaveBeenCalledWith(pattern);
});
})
<link href="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine.css" rel="stylesheet" />
<script src="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine-2.0.3-concated.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular-mocks.js"></script>

Categories

Resources