angularjs http service unit testing - angularjs

I am trying to test a simple service for learning purposes..However; I can't figure out how it must be done:
service:
.factory('myService', function($http) {
var myService = {
async: function() {
var promise = $http.get('test.json').then(function (response)
{
return response.data;
});
return promise;
}
};
return myService;
});
controller:
myService.async().then(function(d) {
$scope.data = d;
$scope.e = $scope.data.txt;
});
test:
'use strict';
describe("myService", function(){
beforeEach(module("testingExpApp"));
var myService,
$httpBackend;
beforeEach(inject(function(myService, _$httpBackend_){
myService = myService;
$httpBackend = _$httpBackend_;
}));
describe("get", function(){
it('should return test.json data', function () {
var url = "../mock/test.json";
var x = $httpBackend.expectGET(url).respond(200, 'txt from json');
// flush response
$httpBackend.flush();
expect(x).toBe('txt from json');
});
});
});
I get 'no pending request to flush!'
I just want to test that myservice.get() get the test.json file data..I have tried everything but can't get it working..
Any tips?
Thanks a lot in advance!

What I was missing is to call service function
it had to be:
it('should return test.json data', function () {
var url = "../../mock/test.json";
$httpBackend.expectGET(url).respond(200, 'data from test.json');
//Execute service func here..
myServiceFunc.async().then(function(result) {
console.log(result);
expect(result).toEqual('data from test.json');
});
$httpBackend.flush();
});

Related

Is it possible to test $resource success and error callbacks in a controller?

I would like to test $resource success and error callbacks in my controller. I don’t want to use $httpBackend as that would be used to test the data service. It seems that there is no way to do it though - the only solution I have found is to use promises instead which I could either resolve or reject. Does this sound right? Anyway, here is what I have at the moment - currently it only tests whether the $resource get() is called:
The controller:
angular
.module('myModule')
.controller('MyCtrl', MyCtrl);
MyCtrl.$inject = [
'dataService'
];
function MyCtrl(
dataService
) {
var vm = this;
vm.getData = getData;
function getData() {
dataService.getData().get(function(response) {
// stuff to test
},
function(error) {
// stuff to test
});
}
The test:
describe('Controller: MyCtrl', function() {
var MyCtrl;
var rootScope;
var scope;
var dataServiceMock = {
getData: jasmine.createSpy('getData')
};
beforeEach(function()
inject(function($controller, $rootScope) {
rootScope = $rootScope;
scope = $rootScope.$new();
MyCtrl = $controller('MyCtrl as vm', {
dataService: dataServiceMock,
});
});
});
describe('vm.getData()', function() {
beforeEach(function() {
dataServiceMock.getData.and.returnValue({
get: jasmine.createSpy('get')
});
});
it('gets the data', function() {
scope.vm.getData();
expect(dataServiceMock.getData().get).toHaveBeenCalled();
});
});
});
Try this
function getData (query) {
var deferred = $q.defer();
var httpPromise = $resource(query,{},{
post:{
method:"GET",
isArray: false,
responseType: "json"
}
});
httpPromise.post({}, {},
function(data) {
try {
var results = {}
results.totalItems = data.response;
deferred.resolve(results);
} catch (error) {
console.log(error.stack);
deferred.reject();
}
},
function(error) {
deferred.reject();
}
);
return deferred.promise;
}

Karma testing controller that calls service with http

Can someone please tell me the best way to run tests on my controller function getData and the factory function too. I've very confused and don't know where to start. How would you write tests for the code below?
myApp.controller('myController', ['$scope', 'myFactory', function ($scope, myFactory) {
$scope.getData = function(id) {
var promise = myFactory.GetData('/dta/GetData?Id=' + id);
promise
.then(function (success) {
$scope.result = success;
}, function (error) {
$scope.error = true;
});
}
});
myApp.factory('myFactory', ['$http', function ($http) {
return {
GetData: function (url) {
return $http.get(url)
.then(function (response) {
return response.data;
}, function (error) {
return error;
});
}
}
}]);
You'll want to test each component in isolation (that's what unit tests are for). So something like this for the controller
describe('myController test', () => {
let scope, myFactory;
beforeEach(() => {
myFactory = jasmine.createSpyObj('myFactory', ['GetData']);
module('your-module-name');
inject(function($rootScope, $controller) {
scope = $rootScope.$new();
$controller('myController', {
$scope: scope,
myFactory: myfactory
});
});
});
it('getData assigns result on success', inject(function($q) {
let id = 1, success = 'success';
myFactory.GetData.and.returnValue($q.when(success));
scope.getData(id);
expect(myFactory.GetData).toHaveBeenCalledWith('/dta/GetData?Id=' + id);
scope.$digest(); // resolve promises
expect(scope.result).toBe(success);
}));
it('getData assigns error on rejections', inject(function($q) {
myFactory.GetData.and.returnValue($q.reject('error'));
scope.getData('whatever');
scope.$digest();
expect(scope.error).toEqual(true);
}));
});
For your factory, you would create a separate describe and inject and configure $httpBackend. There are plenty of example in the documentation.
FYI, you should omit the error handler in your factory, ie
return $http.get(url).then(response => response.data);
or if you don't like ES2015
return $http.get(url).then(function(response) {
return response.data;
});
as you are currently converting a failed request into a successful promise.
In fact, I'd go a bit further to make your GetData factory more useful than a mere $http wrapper
GetData: function(id) {
return $http.get('/dta/GetData', {
params: { Id: id }
}).then(function(res) {
return res.data;
});
}

Mocking AngularJS Webservice using Jasmine Unit Test

I want to mock my Angular JS method using Jamine. My code is:-
<script type="text/javascript">
var app = angular.module('mymodulee', []);
app.controller('mycontroller', function ($scope, $http, $log) {
$scope.ButtonClick = function (Id) {
var response = $http({
method: "get",
url: http://localhost:8080/Access/Tasks.DefectManagement/Services/Services.asmx/GetEligibilityDetails",
params: {
CovId: Id
}
});
return response;
}
});
And my Jasmine Test Case is:-
it('EligibilityDetails', function () {
var myserv, httpBackend;
inject(function ($httpBackend, _myserv_) {
myserv = _myserv_;
httpBackend = $httpBackend;
});
afterEach(function () {
httpBackend.verifyNoOutstandingExpectation();
httpBackend.verifyNoOutstandingRequest();
});
var $scope = {};
var controller = $controller('PatientDefectManagementCtrl', { $scope: $scope });
var returnData = {};
httpBackend.expectGET("http://localhost:8080/Access/Tasks.DefectManagement/Services/Services.asmx/GetEligibilityDetails").respond(returnData);
var returnedPromise = myserv.get(3904142);
var result;
returnedPromise.then(function (response) {
result = response.data;
});
httpBackend.flush();
expect(result).toEqual(returnData);
});
But its is giving an error. Can anyone please tell what changes I should make in my code so that i can run the test case using Jasmine Unit test.
Please help.
Thanks
describe('test',function(){
afterEach(function () {
httpBackend.verifyNoOutstandingExpectation();
httpBackend.verifyNoOutstandingRequest();});
var myserv, httpBackend;
beforeEach(inject(function(_$httpBackend_,_myserv__){
myserv = _myserv_;
httpBackend = $httpBackend;});
it('EligibilityDetails', function () {
var $scope = {};
var controller = $controller('PatientDefectManagementCtrl', { $scope: $scope });
var returnData = {};
httpBackend.expectGET("http://localhost:8080/Access/Tasks.DefectManagement/Services/Services.asmx/GetEligibilityDetails").respond(returnData);
var returnedPromise = myserv.get(3904142);
var result;
returnedPromise.then(function (response) {
result = response.data;
});
httpBackend.flush();
expect(result).toEqual(returnData);});});

How to write a test unit for a service that returns a promise

Here is my factory in my app.js
app.factory('userInfoFacrory', ['$http' , "$q", function($http,$q){
return {
getNames:function(){
var differed = $q.defer();
$http.get("http://localhost/ang/api/v1/users/names")
.success(function(data) {
differed.resolve(data);
}).error(function(msg) {
differed.reject(msg);
});
return differed.promise;
}
}
}])
I use this factory in my controller like bellow , and it works fine :
app.controller('mainController', ['$scope','userInfoFacrory','$log', function($scope,userInfoFacrory,$log){
var promise = userInfoFacrory.getNames();
promise.then(function (data) {
$log.info(data); // I get my data correctly here
}, function (msg) {
$log.error(data);
})
}])
And here , I've tried to write a test unit , with karma-jasmine
describe('userInfoFacrory', function() {
var factory ,$rootScope,$scope,$q,onTaskComplete , promise;
beforeEach(function() {
module("testApp");
inject(function ($injector) {
$q = $injector.get("$q");
factory = $injector.get("userInfoFacrory");
$rootScope = $injector.get("$rootScope");
$scope = $rootScope.$new();
promise = factory.getNames(); // this function comes from my factory which returns a promise
});
});
it('should return a promise', function() {
// This test will pass , so no error so far
expect(typeof promise.then).toEqual('function');
});
});
But I can't figure out how to test to so if my promise will have my data ( that comes from my api ) or not , any suggestion would be appreciated.
thanks
it('should return a promise resolved with the http response data if the http request is successful', inject(function($httpBackend) {
var expectedData = 'fake data';
$httpBackend.expectGET('http://localhost/ang/api/v1/users/names').respond(expectedData);
var promise = factory.getNames();
var actualData;
promise.then(function(result) {
actualData = result;
});
$httpBackend.flush();
expect(actualData).toEqual(expectedData);
}));
it('should return a promise rejected with the http response data if the http request is in error', inject(function($httpBackend) {
var expectedData = 'fake data';
$httpBackend.expectGET('http://localhost/ang/api/v1/users/names').respond(400, expectedData);
var promise = factory.getNames();
var actualData;
promise.catch(function(result) {
actualData = result;
});
$httpBackend.flush();
expect(actualData).toEqual(expectedData);
}));
Working plunkr: http://plnkr.co/edit/NfO6KXWLs1QT5HG8MK0J?p=preview
Note that your code is correct, but doesn't really leverage the chaining capabilities of promises. It could simply be written as
getNames: function() {
return $http.get("http://localhost/ang/api/v1/users/names")
.then(function(response) {
return response.data;
}, function(response) {
return $q.reject(response.data);
});
};
}
Working plunkr: http://plnkr.co/edit/C5x8wRYCQ0wetjozEd0a?p=preview

Implementing Promises in angularJS

I'm attempting to implement some http.get() requests in an angular service, returning a promise.
Here is the excerpt from my initial service:
angular.module('dashboard').service('DashboardHTTP', ['$q', '$http', function ($q, $http) {
this.get_info = function () {
var deferred = $q.defer();
$http.get('/dashboard/4/api/info', { cache: true }).success(function (data) {
deferred.resolve(data);
}).error(function () {
deferred.reject('Could Not Complete Request');
});
return deferred.promise;
}
}]);
And here is an excerpt from the portion of my controller where I call the service:
DashboardHTTP.get_info().then(
function (response) {
var resp = response;
$rootScope.dash_info = resp;
},
function (response) {
return 'error';
},
function (response) {
return 'notify';
});
My questions:
I'm struggling with determining how much testing is needed for an interaction like this. I currently have the following test, which is testing at the service level, but I'm wondering if I need to test at the controller level and if so what sort of testing needs to occur?
beforeEach(inject(function (_$httpBackend_, $injector) {
service = $injector.get('DashboardHTTP');
$httpBackend = _$httpBackend_;
}));
afterEach(function () {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
describe('get_info', function () {
it(' should get info from the url /api/info', function () {
var returnData = { data: 'lots of data' };
$httpBackend.expectGET('/dashboard/4/api/info').respond(returnData);
var returnedPromise = service.get_info();
var result;
returnedPromise.then(function (response) {
result = response;
});
$httpBackend.flush();
expect(result).toEqual(returnData);
});
});
My goal is that I want to set $rootScope.dash_info to the response from the HTTP request made by Service.get_info(). Is my implementation in my controller appropriate? If so, how do I test that the correct data is being passed in at the controller level?
This is probably a partial answer, but here's my input:
Your call is asynchronous, therefore your test should be. Use done.
it(' should get info from the url /api/info', function (done) {
var returnData = { data: 'lots of data' };
$httpBackend.expectGET('/dashboard/4/api/info').respond(returnData);
var returnedPromise = service.get_info();
var result;
returnedPromise.then(function (response) {
result = response;
expect(result).toEqual(returnData);
done();
});
$httpBackend.flush();
});
Also, you do know that http.get returns a promise, right? It has also success and error functions, but it is still a promise.

Resources