AngularJS $httpBackend expectGET not working - angularjs

I am writing QUnit tests for an AngularJS factory. Here's the code for the factory:
var app = angular.module('App', []);
app.factory('$groupFactory', function($rootScope, $http) {
return {
'getAll': function(_callback) {
$http.get("get/values/from/server", {
headers: {
'Content-type': 'application/json'
}
}).success(function(data, status, headers, config) {
_callback(data);
}).
error(function(data, status, headers, config) {
_callback(data);
});
},
}
});
Also see the below Qunit test cases. The test-1 gets the http response from the $httpBackend works, but in test-2, it doesn't.
var $scope,
$rootScope,
$http,
$httpBackend,
$groupFactory,
injector = angular.injector(['ng', 'App', 'ngMockE2E']),
init;
init = {
setup: function() {
$rootScope = injector.get('$rootScope').$new();
$groupFactory = injector.get('$groupFactory');
$httpBackend = injector.get('$httpBackend');
$httpBackend
.when('GET', "get/values/from/server")
.respond({'response': 'success'});
}
};
module('$groupFactory', init);
// test-1
test("getAll", function() {
expect(1);
$groupFactory.getAll(function(data) {
equal(data.response, 'success', "success casse");
start();
});
stop();
});
// test-2
test("getAll", function() {
expect(1);
$httpBackend.expectGET("get/values/from/server").respond(404, {
response: 'failure'
});
$groupFactory.getAll(function(data) {
equal(data.response, 'failure', "failure casse");
start();
});
stop();
});
Any idea why is it not working?
Here is a demo on jsFiddle.

Calling $httpBackend.flush() after stop() will work:
stop();
$httpBackend.flush();
Here's the updated demo.

Related

Store data from controller to service in angularjs

Although there are many questions regarding the subject , yet I am unable to figure it out , how to proceed further.
I am new in AngularJS. I want to pass data coming from API in Controller and pass it to another function. For this I know I have to create a Service. But after coming to this extend of code I am unable to figure it, how to store it in Service and pass it on other Controller or of function within same Controller. I am new in making Service.
Controller:
$scope.GetR = function (){
$scope.X = null;
$scope.Y = null;
$http({method: 'POST', url: 'http://44.43.3.3/api/infotwo',
headers: {"Content-Type": "application/json"},
data: $scope.ResponseJson
})
.success(function(data, status, headers, config) {
$scope.X = data.X;
$scope.Y = data.Y;
//console.log($scope.X+"and"+$scope.Y);
//Seding RS to API to get AAs
$scope.RJson = {
"ICl": $scope.ICl,
"RS": $scope.X
};
$http({method: 'POST', url: 'http://44.128.44.5/api/apithree',
headers: {"Content-Type": "application/json"},
data: $scope.RJson
})
.success(function(data, status, headers, config) {
$scope.At = data;
$scope.Eq = data.AA.Eq;
$scope.FIn = data.AA.FIn;
$scope.MM = data.AA.MM;
console.log("Eq:"+$scope.Eq+" FIn:"+$scope.FIn+" MM:"+$scope.MM);
}).error(function(data, status, headers, config) {
console.log("API failed...");
});
}).error(function(data, status, headers, config) {
console.log("Something went wrong...");
});
};
Now I want to pass this data to Service so that I can call this output on other API input
.success(function(data, status, headers, config) {
$scope.At = data;
$scope.Eq = data.AA.Eq;
$scope.FIn = data.AA.FIn;
$scope.MM = data.AA.MM;
console.log("Eq:"+$scope.Eq+" FIn:"+$scope.FIn+" MM:"+$scope.MM);
This shows how to create a service and share data between two controllers.
The service:
(function() {
'use strict';
angular
.module('myAppName') // Replace this to your module name
.service('MyService', MyService);
MyService.$inject = [];
function MyService() {
this.data = null;
}
})();
First controller:
(function() {
'use strict';
angular
.module('myAppName') // Replace this to your module name
.controller('MyFirstController', MyFirstController);
MyFirstController.$inject = ['MyService', '$http'];
function MyFirstController(MyService, $http) {
var vm = this;
vm.data = MyService.data;
$http.post('/someUrl', whatEverData).then(resp=> {
MyService.data = resp.data;
})
}
})();
Second controller:
(function() {
'use strict';
angular
.module('myAppName') // Replace this to your module name
.controller('MySecondController', MySecondController);
MySecondController.$inject = ['MyService', '$http'];
function MySecondController(MyService, $http) {
var vm = this;
vm.data = MyService.data; // Here you can use the same data
}
})();
Not sure if this is what you are looking for. Below code is not tested (May have syntax errors)
Service:
function() {
'use strict';
angular
.module('myAppName')
.factory('MyService', MyService);
MyService.$inject = [];
function MyService() {
var data = null;
return {
getData: function() {
return data;
},
setData: function(d) {
data = d;
}
}
}
})();
Controller:
(function() {
'use strict';
angular
.module('myAppName')
.factory('controller', controller);
controller.$inject = ['$scope', '$http', 'MyService'];
function controller($scope, $http, MyService) {
$scope.GetR = function() {
$scope.X = null;
$scope.Y = null;
var promise = $http({
method: 'POST',
url: 'http://44.43.3.3/api/infotwo',
headers: {
"Content-Type": "application/json"
},
data: $scope.ResponseJson
});
promise.success(function(data, status, headers, config) {
$scope.X = data.X;
$scope.Y = data.Y;
//console.log($scope.X+"and"+$scope.Y);
//Seding RS to API to get AAs
$scope.RJson = {
"ICl": $scope.ICl,
"RS": $scope.X
};
}).error(function(data, status, headers, config) {
console.log("Something went wrong...");
});
return promise;
};
$scope.sendRS = function() {
var promise = $http({
method: 'POST',
url: 'http://44.128.44.5/api/apithree',
headers: {
"Content-Type": "application/json"
},
data: $scope.RJson
});
promise.success(function(data, status, headers, config) {
$scope.At = data;
$scope.Eq = data.AA.Eq;
$scope.FIn = data.AA.FIn;
$scope.MM = data.AA.MM;
console.log("Eq:" + $scope.Eq + " FIn:" + $scope.FIn + " MM:" + $scope.MM);
}).error(function(data, status, headers, config) {
console.log("API failed...");
});
return promise;
}
var init = function() {
$scope.GetR().then(function() {
$scope.sendRS().then(function(data) {
MyService.setData({
At: data,
Eq: data.AA.Eq,
FIn: data.AA.FIn,
MM: data.AA.MM
});
})
})
}
init();
}
})();
Other controller
(function() {
'use strict';
angular
.module('myAppName')
.controller('controller1', controller1);
controller1.$inject = ['$scope', 'MyService'];
function controller1($scope, MyService) {
$scope.data = MyService.getData();
}
})();

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;
}

Testing factory toBeDefined error

Just started jasmine karma.
the test is failing due to following errors:
PhantomJS 2.1.1 (Mac OS X 0.0.0) dataservice spec should have dataservice be defined FAILED
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
Error: [$injector:unpr] Unknown provider: dataserviceProvider <- dataservice
i have provided all dependencies namely $http and $q still getting unknown provider error.
the factory has been described inside app.core module, which i have
included into the karma conf file
What am i missing.
the factory works fine inthe project
unit testing the following http factory
(function() {
'use strict';
angular
.module('app.core', [])
.factory('dataservice', dataservice);
dataservice.$inject = ['$http', '$q'];
function dataservice($http, $q) {
return {
makeRequest: makeRequest,
};
function makeRequest(params) {
var defer = $q.defer();
if (params.method == "GET") {
$http({
method: params.method,
url: params.url,
headers: params.headers
})
.then(function(response) {
defer.resolve(response);
},
function(response) {
defer.reject(response);
})
}
if (params.method == "POST") {
$http({
method: params.method,
url: params.url,
data: params.parameters,
headers: params.headers
})
.then(function(response) {
console.log(response);
defer.resolve(response);
},
function(response) {
console.log("error");
defer.reject(response);
})
}
return defer.promise;
})();
test spec:
(function(){
'use strict'
describe('dataservice spec',function(){
var dataservice;
beforeEach(function($injector){
angular.module('app.core');
//dataservice=$injector.get('dataservice')
});
beforeEach(inject(function (_dataservice_,_$http_,_$q_) {
dataservice = _dataservice_;
$http=_$http_;
$q=_$q_;
}));
// beforeEach(inject(function() {
// var $injector = angular.injector(['app.core']);
// dataservice = $injector.get('dataservice');
// }));
it('should have dataservice be defined', function () {
expect(dataservice).toBeDefined();
});
})
})();
You'll need to update your scripts as follows:
(function () {
'use strict';
angular
.module('app.core', [])
.factory('dataservice', dataservice);
dataservice.$inject = ['$http', '$q'];
function dataservice($http, $q) {
return {
makeRequest: makeRequest
};
function makeRequest(params) {
var defer = $q.defer();
if (params.method == "GET") {
$http({
method: params.method,
url: params.url,
headers: params.headers
})
.then(function (response) {
defer.resolve(response);
},
function (response) {
defer.reject(response);
})
}
if (params.method == "POST") {
$http({
method: params.method,
url: params.url,
data: params.parameters,
headers: params.headers
})
.then(function (response) {
console.log(response);
defer.resolve(response);
},
function (response) {
console.log("error");
defer.reject(response);
})
}
return defer.promise;
}
}
})();
The Unit test:
(function () {
'use strict'
describe('dataservice spec', function () {
var dataservice,
$http,
$q;
beforeEach(module('app.core'));
beforeEach(inject(function (_dataservice_, _$http_, _$q_) {
dataservice = _dataservice_;
$http = _$http_;
$q = _$q_;
}));
it('should have dataservice be defined', function () {
expect(dataservice).toBeDefined();
});
})
})();
Just make sure you're loading your module properly: beforeEach(module('app.core'));

Unit Test Angular http.post with Data in Header

I am trying to write a unit test for service that performs a http.post to an api that passes credentials in the header.
Controller:
app.controller('LoginController', function($scope, $http, signInService) {
$scope.LogIn = function(usrnm, pwd) {
signInService.authUser(usrnm, pwd)
.success(function (data, status, headers, config) {
// Display success message
$scope.gotToAddress = data.successUrl;
})
.error(function (data, status, headers, config) {
// Display error message
}
}
});
signInService:
app.service('signInService', function($http) {
this.authUser = function (usrnm, pwd) {
return $http({
url: '/api/json/authenticate',
method: "POST",
data: '{}',
headers: {
'Content-Type': 'application/json',
'X-app-Username': usrnm,
'X-app-Password': pwd
}
});
};
});
Unit test:
describe('mocking service http call', function() {
beforeEach(module('myApp'));
var LoginController, $scope;
describe('with httpBackend', function() {
beforeEach(inject(function($controller, $rootScope, $httpBackend) {
$scope = $rootScope.$new();
$httpBackend.when('POST', '/api/json/authenticate', {}, function(headers) {
return {
'Content-Type': 'application/json',
'X-app-Username': 'admin',
'X-app-Password': 'admin'
};
}).respond(200)
LoginController = $controller('LoginController', { $scope: $scope });
$httpBackend.flush();
}));
it('should set data to "things and stuff"', function() {
expect($scope.data).toEqual({things: 'and stuff'});
});
});
});
When running the test i am seeing the following error: mocking service http call » with httpBackend
Error: No pending request to flush !
Controller with service on .succeed:
app.controller('LoginController', function($scope, $http, signInService, cookieSrv) {
$scope.LogIn = function(usrnm, pwd) {
signInService.authUser(usrnm, pwd)
.success(function (data, status, headers, config) {
// Display success message
var cookieID = 'myCookie';
cookieSrv.createCookie(cookieID, data.token, 3, data.redirectUrl);
})
.error(function (data, status, headers, config) {
// Display error message
}
}
});
cookieSrv.js
app.service('cookieSrv', function() {
return {
createCookie : function(cookieID, token, days, redirectUrl) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
document.cookie = cookieID+"="+token+expires+"; path=/";
window.location.assign(redirectUrl)
}
}
});
Your controller defines a method logIn on the $scope but you do not call this function in the test, and hence actual http request is not made.
Modify the test by calling $scope.logIn before you call flush
LoginController = $controller('LoginController', { $scope: $scope });
$scope.logIn("Test","test"); // Add this
$httpBackend.flush();

TypeError: Cannot set property 'highlight' of undefined angular-typeahead

I am trying to add angular-typeahead to my app for search suggestion taking help from this Plunkr.
This is the code of app.js file:
var myApp = angular.module('myApp', ['ngRoute','siyfion.sfTypeahead']);
myApp.factory('websitesSvc',function($http, $log, $q) {
return {
getwebsites: function(){
//Create a promise using promise library
var deferred = $q.defer();
$http({method: 'GET', url: '/api/websites/'}).
success(function(data, status, headers,config){
deferred.resolve(data);
}).
error(function(data, status, headers,config){
deferred.reject(status);
});
return deferred.promise;
}
};
});
myApp.controller('MyCtrl', ['$scope','websitesSvc','$timeout',
function($scope,websitesSvc,$timeout) {
$scope.searchString=null;
websitesSvc.getwebsites().then(function(websites){
$scope.websites = websites;
});
$timeout(function() {
var websites = new Bloodhound({
datumTokenizer: function(d) { return Bloodhound.tokenizers.whitespace(d.domain_name); },
queryTokenizer: Bloodhound.tokenizers.whitespace,
local:$scope.websites,
});
// initialize the bloodhound suggestion engine
websites.initialize();
$scope.numbersDataset = {
displayKey: 'domain_name',
source: websites.ttAdapter()
};
// Typeahead options object
$scope.exampleOptions = {
highlight: true
};
},1000);
}
]);
Adding delay so that the services are executed first and then the data fetched can be passed to typeahead for search suggestions.But I am getting following errors in console .
How should I change my code to debug this?

Resources