How to do unit testing using jasmine on that factory? - angularjs

I try to make a unit test on that code that consists of factory that take behavior Name and contracts an http request in a closure ?
var app = angular.module("behaviour",[]);
var behaviour = app.factory('Behaviours',['http',function(http){
var BehavioursJson = $http.get('data.json');
return {
getBehaviour : function(behaviourName) {
if (BehavioursJson[behaviourName]) {
var behaviour = BehavioursJson[behaviourName];
return function (behaviourData, callback) {
var keys = Object.allKeys(behaviourData);
var headers = {};
var data = {};
var url = behaviour.path;
// some process to fill headers and data objects
$http({
method: behaviour.method,
url: url,
data: data,
headers: headers
}).then(function successCallback(response) {
callback(response,null);
},function errorCallback(error) {
callback(null,error);
});
}
};
return null;
}
}
}]);
Note: using jasmine

Related

Fetch params from URL using app controller

How to pass the multiple parameters to a function using this code? I am able to pass only Username as single parameter but MarkDate is not passing to URL.
var app = angular.module("myModule", ['angularUtils.directives.dirPagination']);
//This Gets all the Pre Clients
app.controller("GetAttendance", function ($scope, $http) {
window.params = function () {
var params = {};
var param_array = window.location.href.split('?')[1].split('&');
for (var i in param_array) {
x = param_array[i].split('=');
params[x[0]] = x[1];
}
return params;
} ();
$http({
url: "../assets/services/MasterWebService.asmx/spGetAttendanceByUsernameDate",
method: "GET",
**params: { Username: window.params.Username , MarkDate : params.Markdate}**
}).then(function (response) {
console.log(response.data);
$scope.GetAttendanceData = response.data;
$scope.TotalOrders = response.data.length;
});
Your "MarkDate" param is not getting its value from the window.params object as you do with "Username". This should work:
$http({
url: "../assets/services/MasterWebService.asmx/spGetAttendanceByUsernameDate",
method: "GET",
**params: { Username: window.params.Username , MarkDate : window.params.Markdate}**
}).then(function (response) {
console.log(response.data);
$scope.GetAttendanceData = response.data;
$scope.TotalOrders = response.data.length;
});

angular $http.put() works but $http({method: 'PUT'}) does not

I am trying to consolidate all my services which make api calls to the Rails back end into one. Here's what it looks like:
angular.module('feeSuitesApp')
.factory('FeeSuitesSvc', [
'$http',
function ($http) {
var TransformInstance, Result;
TransformInstance = function(FeeObj, obj){
return new FeeObj(obj);
};
Result = function(feeSuiteObj){
var servicePlural = feeSuiteObj.service + 's';
return $http({
method: feeSuiteObj.method,
url: feeSuiteObj.url,
params: feeSuiteObj.params,
transformResponse: function(data){
var w = angular.fromJson(data);
angular.forEach(w[servicePlural], function(obj, idx){
w[servicePlural][idx] = TransformInstance(feeSuiteObj.feeObj, obj);
});
return w;
}
})
}
return {
promise: Result,
};
}]);
POST and GET work fine, but PUT gives me a RangeError: Maximum call stack size exceeded
FeeRule looks like this:
angular.module('feeSuitesApp')
.factory('FeeRule', function(){
//constructor
var FeeRule = function(obj){
this.id = obj.id || null;
this.name = obj.name || '';
this.fee_suite_id = obj.fee_suite_id || null;
this.fee_parameter_id = obj.fee_parameter_id || null;
this.multiplier = obj.multiplier || 1;
this.addend = obj.addend || 0;
};
return FeeRule;
});
however, if I make the following call everything works perfectly:
var url = '/api/v3/fee_rules/' + feeRule.id;
$http.put(url, { fee_rule: feeRule});
but if I use my service like this I get the stack overflow error:
var feeSuiteObj = {
url: '/api/v3/fee_rules/' + feeRule.id,
service: 'fee_rule',
method: 'PUT',
params: {
fee_rule: feeRule
},
feeObj: FeeRule
};
FeeSuitesSvc.promise(feeSuiteObj).then(function(success){
$state.go('root');
},function(error){
console.log(error);
});
see https://docs.angularjs.org/api/ng/service/$http#usage, there is no service nor feeObj config properties, also params is used to append serialized data to GET requests (not PUT). So try this:
var feeSuiteObj = {
url: '/api/v3/fee_rules/' + feeRule.id,
method: 'PUT',
data: {
fee_rule: feeRule
}
};
if you need to pass service or feeObj, you can do it within data object:
data: {
fee_rule: feeRule,
service: 'fee_rule',
feeObj: FeeRule
}

angular then catch success error from services

I'm afraid I may have gone down the rabbit hole of recursive promises.
I have a service that handles my api. (It's got an extra layer of promise so that I could switch back to a local json if the api went offline. (Not sure how necessary it is anymore) - mayte I should eliminate it for simplicity).
Then I've got the promised async call in my controller.
This all works great as long as I get the data I expect, but it doesn't handle errors very well. When I get 400's and 500's, it doesn't send the error message to the user via toastr.
Sadly, this is not a fully-compliant RESTful api. The 400 error I get back is simply
{"Message":"No packages found"}
I don't really get how to get this to behave as it should, and replace success/error with then/catch (as per Angular best practice).
Here is a typical service call:
var _getPackagesPage = function (options) {
var pageSize = options.data.pageSize;
var page = options.data.page -1;
return $q (function(resolve, reject) {
switch (dataSource) {
case 'api'://staging - live api data
return $http({
method: 'get',
url: serviceBase + 'api/Packages?pageSize=' + pageSize + '&page=' + page
}).then(function(results) {
resolve(results);
});
break;
default: // dev - local json
$.getJSON('Content/data/Packages.json', function (json) {
var pageSize = options.data.pageSize;
var page = options.data.page;
var newjson = json.splice(page*pageSize,pageSize);
resolve(newjson);
});
}
});
};
and a typical call in a controller:
(options is the data object handed back to my data grid (Kendo))
vm.getPackages = function(options) {
return packagesService.getPackagesPage (options)
.then(function(results) {
options.success(results.data.Items);
})
.catch(function(error) {
options.error(error);
toastr.error(error.Message);
});
};
How can I clean this up?
[ UPDATE ] Attempted fix per Answer 1, below
Service:
var _getOrdersPage = function (options) {
var deff = $q.defer();
var pageSize = options.data.pageSize;
var page = options.data.page -1;
return $http({
method: 'get',
url: serviceBase + 'api/Packages?pageSize=' + pageSize + '&page=' + page
})
.then(
function(results) {
deff.resolve(results);
},
function(ex){
deff.reject(ex);
});
return deff.promise;
};
Controller:
vm.getOrders = function (options) {
return ordersService.getOrdersPage (options)
.then(function(results) {
console.log("results!");
console.log(results);
})
.catch(function(error) {
console.log("error!");
console.log(error);
});
};
results in:
GET http://< myURL >/api/Packages?pageSize=20&page=0 400 (Bad Request)
results!
undefined
I'm removing the switch case for brevity.
var _getPackagesPage = function (options) {
var pageSize = options.data.pageSize;
var page = options.data.page -1;
var deff = $q.defer();
$http({
method: 'get',
url: serviceBase + 'api/Packages?pageSize=' + pageSize + '&page=' + page
}).then(
function(results) {
deff.resolve(results);
},
function(ex){
deff.reject(ex);
});
return deff.promise;
};
Controller
vm.getOrders = function (options) {
return ordersService.getOrdersPage (options)
.then(
function(results) {
console.log("results!");
console.log(results);
},
function(error) {
console.log("error!");
console.log(error);
});
};
If you dont have any logic inside your service, then you could return the $http itself as $http inturn is a promise:
var _getPackagesPage = function (options) {
var pageSize = options.data.pageSize;
var page = options.data.page -1;
return $http({
method: 'get',
url: serviceBase + 'api/Packages?pageSize=' + pageSize + '&page=' + page
});
};
You have too many returns in your service. The second one is not called.
You don't need to create a promise manually since $http returns apromise.
You're not returning data from your service.
var _getOrdersPage = function(options) {
var pageSize = options.data.pageSize;
var page = options.data.page -1;
return $http({
method: 'get',
url: serviceBase + 'api/Packages?pageSize=' + pageSize + '&page=' + page
})
.then(
function(results) {
return results;
},
function(ex){
return ex;
});
}
Your controller is fine, you can use catch() or pass an error callback.
Example:
function myService($http) {
this.getData = function(url) {
return $http.get(url).
then(function(response) {
return response.data;
}, function(error) {
return error;
});
}
};
function MyController(myService) {
var vm = this;
vm.result = [];
vm.apiUrl = "https://randomuser.me/api/";
myService.getData(vm.apiUrl).then(function (data) {
vm.result = data;
},
function(error) {
console.log(error);
});
};
angular.module('myApp', []);
angular
.module('myApp')
.service('myService', myService)
.controller('MyController', MyController);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyController as ctrl">
{{ ctrl.result }}
</div>
</div>

Angular JS. Refresh a list after promise completes

I have a model that I am using to hold my data in angular:
var FuelProcessingModel = function (carrierService) {
this.myArray = [];
};
That model has an array of MyObjects that I get from the DB:
var MyObject = function () {
//stuff
}
I update this using a REST call:
$scope.add = function () {
var myObject = new MyObject();
$scope.model.MyObjects.push(myObject);
service.add(myObject);
};
Which I use a service to hit the Server:
this.add = function (myObject) {
$http({
method: "POST",
url: "theServer",
data: myObject
});
}
The REST service just adds to the database, It doesn't return anything.
I need to reload the data from the database after the update is finished, so that my records now have all newly associated ID's and pertinent data.
I cannot just do:
window.location.reload();
The user starts by selecting a value from a drop down list to decide which list of data they start off seeing. I cannot / do not want to pass the value to it, mainly because it is in its own partial view, with its own controller, because it is used on many pages.
I tried doing:
$scope.add = function () {
//same as above
//this
service.get().then(function(result) { $scope.model.myArray = result.data; });
};
Obviously the problem here is the promise isn't complete before the DOM reloads the page. So the user saw themself add an item to the array and it vanished.
Do I want to load the page after the promise is complete? (How would I do that?)
should I return the updated data from the REST service and reset the current value? (seems like the same promise issue)
Is there a better practice that I do not know about?
UPDATE
For Bergi:
this.get = function (key) {
return $http({
method: "GET",
url: "theServer" + key
})
.success(function (data) {
return data;
});
}
I think you want to chain your two promises:
$scope.add = function () {
var myObject = new MyObject();
$scope.model.MyObjects.push(myObject);
return service.add(myObject).then(function() {
return service.get();
}).then(function(result) {
$scope.model.myArray = result.data;
});
};
and
this.add = function(myObject) {
return $http({
// ^^^^^^ return a promise here
method: "POST",
url: "theServer",
data: myObject
});
};
You can wrap your service call in a deferred promise, and on return success re-init your data from the controller..
$scope.add = function () {
var myObject = new MyObject();
$scope.model.MyObjects.push(myObject);
service.add(myObject).then(function (response) {
// here's where you'd do whatever you want to refresh your model
}),
function (err) {console.log(err);};
};
And the service:
this.add = function (myObject) {
var deferred = $q.defer();
$http({
method: "POST",
url: "theServer",
data: myObject,
success: function (response) {
deferred.resolve(err);
},
error: function (err) {
deferred.reject(err);
}
});
return deferred.promise;
}

AngularJS - transformRequest is not getting called on $resource

I am adding a pair of actions to an AngularJS resource, but when I invoke the action, my transformRequest function is not getting called:
var _resource = $resource('api/NewItem/:id',
{ id: '#id' },
{
create: {
method: 'POST',
transformRequest: function (data, headersGetter) {
var result = JSON.stringify(data.productIntro);
return result;
}
},
update: {
method: 'PUT',
transformRequest: function (data, headersGetter) {
var result = JSON.stringify(data.productIntro);
return result;
}
}
});
If I add the function globally on the app, it works:
var newItemApp = angular.module('newItemApp', ['ngResource'])
.config(function ($httpProvider) {
$httpProvider.defaults.transformRequest = function(data)
{
if (data === undefined) {
return data;
}
var result = JSON.stringify(data.productIntro);
return result;
};
});
What I need to do is remove the root element from any POST or PUT action because the default model binding in Web Api does not bind a json object when that object has a named root.
transformRequest is supported since AngularJS 1.1.2. If you use early version, you need to add it to $httpProvider.

Resources