Here is my test code, and always get the error message above.
'use strict';
describe('getmodules', function () {
window.__env.platform = 'jasmine'; // web || mobile || desktop
beforeEach(function () { module('myApp', 'ngMockE2E', 'ngCookies'); });
var service, $httpBackend, defaultAlertFactory, $cookies, $http;
var $controller;
var $rootScope;
beforeEach(inject(function ($injector) {
service = $injector.get('dashboardService');
$httpBackend = $injector.get('$httpBackend');
$rootScope = $injector.get('$rootScope');
$http = $injector.get('$http');
}));
it("should return a list of getmodules", function () {
debugger;
var result1 = null;
$httpBackend.when('GET', '/home/modulesInfo').respond(true, ['david', 'James', 'Sam']);
/* Code Under Test */
$http({
method: 'GET',
url: '/home/modulesInfo'
}).then(function (success,response) {
result1 =response;
}, function (error) {
});
$httpBackend.flush();
expect(result1).toEqual(["david", "James", "Sam"]);
});
});
========================================================
Not sure why? have the $http.get(), and use the flush() to call the fack httpBackend call, should be good. still not work
You need to change your thenable function syntax as like below:
And check out this working Plunker
$http({
method: 'GET',
url: '/home/modulesInfo'
}).then(function(response) {
console.log('data: ' + JSON.stringify(response.data));
result1 = response.data;
}, function(error) {
});
Related
Im trying to test $http requests and no matter what I do I cant seem to get it to work. I have a factory that holds the 4 request type GET, POST, PUT, DELETE.
Im trying to test the response from a get request but my scope variable that is assigned the response in the controller is giving an error or undefined = the response from the get request.
The factory code is as follows:
app.factory('requestService', ['$http', function ($http) {
// reusable requests
return {
//reuable get request
getRequest: function (url) {
return $http({
method: 'GET',
dataType: "json",
url: url
});
},
//reuable post request
postRequest: function (url, data) {
return $http({
method: 'POST',
data: data,
url: url
});
},
//reuable put request
putRequest: function (url, data) {
return $http({
method: 'PUT',
data: data,
url: url
});
},
//reuable delete request
deleteRequest: function (url) {
return $http({
method: 'DELETE',
url: url
});
}
}
}]);
The following is in the controller.
//get the teams
$scope.getTeams = function(){
requestService.getRequest('https:.../teams').then(function (response) {
$scope.teams = response;
});
}
$scope.getTeams();
Jasmine code:
describe('Controller Test', function() {
var $rootScope, controller;
//Tell the $httpBackend to respond with our mock object
var teamsResponse = {// Teams Data //};
beforeEach(function() {
module('myApp')
});
beforeEach(inject(function($rootScope, $controller, _$httpBackend_, $http) {
$scope = $rootScope.$new();
controller = $controller;
controller('Controller', {$scope: $scope});
$httpBackend = _$httpBackend_;
$httpBackend.whenGET('https:...../teams').respond(200, teamsResponse);
}));
it('should load a list of teams', function() {
$scope.getTeams();
$httpBackend.flush();
expect($scope.teams).toBe(teamsResponse);
});
});
The error I get is:
Expected undefined to be {// Teams Data //}
describe("Testing Common Get JSON Service", function () {
var service, $httpBackend;
beforeEach(inject(function($injector,$rootScope) {
service = $injector.get('CommonService');
$httpBackend = $injector.get('$httpBackend');
scope = $rootScope.$new();
successCallback = jasmine.createSpy();
errorCallback = jasmine.createSpy();
$httpBackend.when('GET', getFlightIncidentLookupUrl).respond(getFlightIncidentLookup);
successCallback();
}));
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it('test getServiceJSON works fine and calls a GET method', function () {
service.getServiceJSON(getFlightIncidentLookupUrl).then(function(response) {
expect(response.data.incidentLookup.length).toEqual(1);
});
$httpBackend.flush();
});
});
This worked for me . here CommonService is a service in Angular js which calls a get method. I got the response correctly.
I'm trying to test a controller that calls a method on a service. The service method returns a promise, and the controller immediately invokes .then() inline after calling the service method. I'm trying to stub the service using sinon and Jasmine keeps throwing an error saying that then is undefined and not a function.
Here is the controller:
var loginModalController = function ($scope, authenticationService) {
this.submit = submit;
function submit(user, password) {
$scope.email = user;
authenticationService.login(user, password)
.then(handleSuccessLogin, handleErrorLogin);
}
}
Here is the service:
function authenticationService($http, $q, endPointService) {
var baseUri = endPointService.getApiEndpoint();
var service = {
getTermsAndConditions: getTermsAndConditions,
login: login,
acceptTerms: acceptTerms
};
return service;
function getTermsAndConditions() {
...
};
function login(user, password) {
var deferred = $q.defer();
$http({ method: 'POST', url: baseUri + '/api/tokens', data: { username: user, password: password } }).
success(function (data, status, headers, config) {
$http.defaults.headers.common.Authorization = 'Basic ' + data.EncryptedTokenId;
deferred.resolve(data);
}).
error(function (data, status, headers, config) {
deferred.reject(status);
});
return deferred.promise;
};
function acceptTerms() {
...
};
}
And here is the test:
describe('loginModalController', function () {
var scope, loginModalController, authenticationServiceMock, localSaverServiceMock;
var loginInformationMock = { 'firstName': 'Testuser' };
beforeEach(function () {
module('clientAppModule');
inject(function ($rootScope, $controller, authenticationService, localSaverService) {
scope = $rootScope.$new();
authenticationServiceMock = sinon.stub(authenticationService)
.login.returns({ then: function () { return loginInformationMock } });
localSaverServiceMock = sinon.stub(localSaverService);
loginModalController = $controller('loginModalController', {
$scope: scope,
$state: {},
authenticationService: authenticationServiceMock,
errorCodes: {},
localSaverService: localSaverServiceMock
});
});
});
it('should login', function () {
loginModalController.submit("test", "test");
});
});
Four issues with my code:
I was unnecessarily using Sinon
I was using the return value of stub() rather than just letting it stub the service.
I wasn't using $q to return a deferred promise to match the login function.
I needed to call $digest() on the scope to get the deferred promise to resolve before asserting.
So here is the fixed test code:
beforeEach(module('clientAppModule'));
describe('loginModalController', function () {
var scope, authenticationService, localSaverService;
var loginInformationMock = { 'firstName': 'Testuser' };
beforeEach(inject(function ($injector, $rootScope, $controller, $q) {
scope = $rootScope.$new();
scope.$close = function () { };
authenticationService = $injector.get('authenticationService');
localSaverService = $injector.get('localSaverService');
spyOn(authenticationService, 'login').and.callFake(function () {
var deferred = $q.defer();
deferred.resolve(loginInformationMock);
return deferred.promise;
});
spyOn(localSaverService, 'saveLoginInformation').and.stub();
$controller('loginModalController', {
$scope: scope,
$rootScope: {},
$state: {},
authenticationService: authenticationService,
errorCodes: {},
localSaverService: localSaverService
});
}));
it('should call login on authenticationService', function () {
// Arrange
// Act
scope.submit("test", "test");
// Assert
expect(authenticationService.login).toHaveBeenCalled();
});
it('should save login info after successful login', function () {
// Arrange
// Act
scope.submit("test", "test");
scope.$digest();
// Assert
expect(localSaverService.saveLoginInformation).toHaveBeenCalled();
});
});
I am trying to write unit tests cases around an Angular service. What I am basically trying to test is that the http request is made.
Service
app.service("myService", [
"$http", function ($http) {
this.result = "initial value";
this.get = function (param1, param2) {
return $http({
method: "GET",
url: "api/someService/Get/" + param1 + "/" + param2
})
.success(function (data) {
this.parent.result = data;
console.log(data);
console.log(this.parent.result);
return data;
})
.error(function () {
return "Error occurred";
})
;
};
}
]);
Below is what I have tried.
describe("Surcharge Increase Formula", function () {
var controller;
var scope;
var httpBackend;
var myService;
beforeEach(inject(function($controller, $rootScope, $httpBackend, _myService_) {
scope = $rootScope.$new();
httpBackend = $httpBackend;
myService = _myService_;
});
it('waiver service makes API call', function () {
var response = "This is the response";
httpBackend.when('GET', "api/SurchargeWaiver/Get/0/0").respond(response);
waiverService.get(0, 0);
//httpBackend.flush();
expect(waiverService.result).toEqual(response);
});
What I would like to do is make a call similar to expect(...).toHaveBeenCalled() to see if the api call has been made, or any other way to just test the http call.
Any suggestions?
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.
I am new to Angular testing.
I am trying to test a simple method in a service that gets some data via an ajax call and returns a promise using Jasmine.
So far very unsuccessfully.
This is the method I am testing:
function getDefaultFibonnacci() {
var deferred = $q.defer();
$http({ method: 'GET', url: '/api/fibonnacci/get' })
.success(function (data) {
deferred.resolve(data);
})
.error(function (data, status) {
deferred.reject(status);
});
return deferred.promise;
}
This is my test code: (Please note all other tests pass apart from 'should return 0,1,1,2,3'
describe('datacontext', function () {
var $httpBackend;
var $rootScope;
var datacontext;
var $q;
beforeEach(function () {
module('app');
inject(function (_$httpBackend_, _$rootScope_, _$q_, _datacontext_) {
$httpBackend = _$httpBackend_;
$rootScope = _$rootScope_;
datacontext = _datacontext_;
$q = _$q_;
});
});
it('should have a getDefaultFibonnacci() function', function () {
expect(angular.isFunction(datacontext.getDefaultFibonnacci)).toBe(true);
});
it('should return a promise', function () {
expect(datacontext.getDefaultFibonnacci().then).toBeDefined();
});
it('should return 0,1,1,2,3', function () {
var sequence = '123';
$httpBackend.when('GET', 'app/dashboard/dashboard.html').respond('');
$httpBackend.when('GET', '/api/fibonnacci/get').respond('0,1,1,2,3');
var deferred = $q.defer();
var promise = deferred.promise;
promise.then(function (response) {
sequence = response.success;
});
datacontext.getDefaultFibonnacci().then(function (data) { deferred.resolve(data); });
$rootScope.$digest();
expect(sequence).toEqual('0,1,1,2,3');
});
});
Guys thanks for all your comments. I learnt a lot through this exercise.
This is the code I ended up with for a passing test.
function getDefaultFibonnacci() {
return $http({ method: 'GET', url: '/api/fibonnacci/get' });
}
it('should return 0,1,1,2,3', function () {
var sequence;
$httpBackend.whenGET('app/dashboard/dashboard.html').respond('');
$httpBackend.expectGET('/api/fibonnacci/get').respond('0,1,1,2,3');
datacontext.getDefaultFibonnacci().then(function (data) {
sequence = data.data;
});
$httpBackend.flush();
expect(sequence).toEqual('0,1,1,2,3');
});
$httpBackend has a flush() method for exactly this reason.
flush() simulates the http server responding, so it will trigger the resolution of your $http.get(). Until you call flush(), nothing will happen (the server hasn't responded yet).
As such, replace your $rootScope.digest() code with $httpBackend.flush() and work from there.
Furthermore, you can save a lot of effort by understanding that $http methods themselves return promises.
This:
function getDefaultFibonnacci() {
var deferred = $q.defer();
$http({ method: 'GET', url: '/api/fibonnacci/get' })
.success(function (data) {
deferred.resolve(data);
})
.error(function (data, status) {
deferred.reject(status);
});
return deferred.promise;
}
Can be simplified to this:
function getDefaultFibonnacci() {
return $http({ method: 'GET', url: '/api/fibonnacci/get' })
}
And will do the same thing.
Finally you don't need another promise in your test. This is enough (remove all reference to $q and deferred and put this directly after your $httpBackend.when(... code):
datacontext.getDefaultFibonnacci()
.then(function (data) {
sequence = data;
});
Are you expecting an object {success: "0,1,1,2,3"} as the response from the http service? You're using response.success when promise resolved
promise.then(function (response) {
sequence = response.success;
});
whereas you're returning a string '0,1,1,2,3'
$httpBackend.when('GET', '/api/fibonnacci/get').respond('0,1,1,2,3');
Also, from the code I see that you don't need to create another promise to test your method.
Try this:
it('should return 0,1,1,2,3', function () {
var sequence = '123';
$httpBackend.when('GET', 'app/dashboard/dashboard.html').respond('');
$httpBackend.when('GET', '/api/fibonnacci/get').respond('0,1,1,2,3');
datacontext.getDefaultFibonnacci().then(function (data) { sequence = data; });
$rootScope.$digest();
expect(sequence).toEqual('0,1,1,2,3');
});
The most important think you forgot to do is call $httpBackend.flush() at some point after making the requests before using the data.
Also you don't need to create an extra promise.
it('should return 0,1,1,2,3', function () {
var sequence;
// Use the shorthand method whenGET
$httpBackend.whenGET('app/dashboard/dashboard.html').respond('');
// We should probably test that this request is actually made, so use expect<method>
$httpBackend.expectGET('/api/fibonnacci/get').respond('0,1,1,2,3');
// Leave out the extra promise code.
// var deferred = $q.defer();
// var promise = deferred.promise;
// promise.then(function (response) {
// sequence = response.success;
// });
// datacontext.getDefaultFibonnacci().then(function (data) { deferred.resolve(data); });
datacontext.getDefaultFibonnacci().then(function (response) {
sequence = response.success;
});
$httpBackend.flush(); // Flush the backend. Important!
// $rootScope.$digest(); // I don't think this is necessary.
expect(sequence).toEqual('0,1,1,2,3');
});
The html template won't be called if you set up your app