how to unit test an angular.js service call using jasmine.js - json

It is a bit difficult for me to figure out the examples since I am a beginner could someone please help.
This is my code simple anjular.js service call
var app = angular.module('myApp', []);
var mycontroller = app.controller('Myctrl', function($scope, $http) {
$http.get("service.json")/*the json that i pass*/
.success(function(response) {$scope.names = response.records;});
});
I want to test this code using jasmine. What is the procedure and the code to do it.

You can use httpBackend mock service that will help to test your service.
Example-
describe('Myctrl', function() {
var $httpBackend, scope, createController, authRequestHandler;
// Set up the module
beforeEach(module('MyApp'));
beforeEach(inject(function($injector) {
// Set up the mock http service responses
$httpBackend = $injector.get('$httpBackend');
// backend definition common for all tests
authRequestHandler = $httpBackend.when('GET', 'service.json')
.respond(true);
// Get hold of a scope (i.e. the root scope)
$rootScope = $injector.get('$rootScope');
// The $controller service is used to create instances of controllers
var $controller = $injector.get('$controller');
createController = function() {
return $controller('MyController', {'$scope' : scope});
};
})
);
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it('should fetch authentication token', function() {
$httpBackend.expectGET('service.json');
var controller = createController();
expect(scope.names).toBe(true);
$httpBackend.flush();
});
});

Related

Node.js HTTPS Request for Quandl API

I am using IBM Bluemix to make a web service for a school project.
My project needs to request JSON data from two APIs, for use in the project.
The first one is a http.request, which I executed just fine. For the second one, however, I need a https.request - and that is where the trouble comes from.
I don't know how to get a JSON through a https request. I've been trying to adapt the code for the http one, but my efforts have rendered useless.
How can I request a JSON via https?
Here is my .jsfile:
// Hello.
//
// This is JSHint, a tool that helps to detect errors and potential
// problems in your JavaScript code.
//
// To start, simply enter some JavaScript anywhere on this page. Your
// report will appear on the right side.
//
// Additionally, you can toggle specific options in the Configure
// menu.
function main() {
return 'Hello, World!';
}
main();/*eslint-env node*/
//------------------------------------------------------------------------------
// node.js starter application for Bluemix
//------------------------------------------------------------------------------
// HTTP request - duas alternativas
var http = require('http');
var request = require('request');
//HTTPS request
var https = require('https');
var https = require('https');
var fs = require('fs');
// cfenv provides access to your Cloud Foundry environment
// for more info, see: https://www.npmjs.com/package/cfenv
var cfenv = require('cfenv');
//chama o express, que abre o servidor
var express = require('express');
// create a new express server
var app = express();
// serve the files out of ./public as our main files
app.use(express.static(__dirname + '/public'));
// get the app environment from Cloud Foundry
var appEnv = cfenv.getAppEnv();
// start server on the specified port and binding host
app.listen(appEnv.port, '0.0.0.0', function() {
// print a message when the server starts listening
console.log("server starting on " + appEnv.url);
});
app.get('/home1', function (req,res) {
http.get('http://developers.agenciaideias.com.br/cotacoes/json', function (res2) {
var body = '';
res2.on('data', function (chunk) {
body += chunk;
});
res2.on('end', function () {
var json = JSON.parse(body);
var CotacaoDolar = json["dolar"]["cotacao"];
var VariacaoDolar = json["dolar"]["variacao"];
var CotacaoEuro = json["euro"]["cotacao"];
var VariacaoEuro = json["euro"]["variacao"];
var Atualizacao = json["atualizacao"];
obj=req.query;
DolarUsuario=obj['dolar'];
RealUsuario=Number(obj['dolar'])*CotacaoDolar;
EuroUsuario=obj['euro'];
RealUsuario2=Number(obj['euro'])*CotacaoEuro;
Oi=1*VariacaoDolar;
Oi2=1*VariacaoEuro;
if (VariacaoDolar<0) {
recomend= "Recomenda-se, portanto, comprar dólares.";
}
else if (VariacaoDolar=0){
recomend="";
}
else {
recomend="Recomenda-se, portanto, vender dólares.";
}
if (VariacaoEuro<0) {
recomend2= "Recomenda-se, portanto, comprar euros.";
}
else if (VariacaoEuro=0){
recomend2="";
}
else {
recomend2="Recomenda-se,portanto, vender euros.";
}
res.render('cotacao_response.jade', {
'CotacaoDolar':CotacaoDolar,
'VariacaoDolar':VariacaoDolar,
'Atualizacao':Atualizacao,
'RealUsuario':RealUsuario,
'DolarUsuario':DolarUsuario,
'CotacaoEuro':CotacaoEuro,
'VariacaoEuro':VariacaoEuro,
'RealUsuario2':RealUsuario2,
'recomend':recomend,
'recomend2':recomend2,
'Oi':Oi,
'Oi2':Oi2
});
app.get('/home2', function (req,res) {
https.get('https://www.quandl.com/api/v3/datasets/BCB/432.json?api_key=YOUR_API_KEY', function (res3) {
var body = '';
res3.on('data', function (chunk) {
body += chunk;
});
res3.on('end', function () {
var x=json.dataset.data[0][1];
console.log("My JSON is "+x); });
});
});
});
});
});
Your https.get should work as set up. There were a few other issues with your code that caused it to break, which I'm outlining below with explanations:
1. Potentially incorrect nesting of the /home2 route
Your declaration of the /home2 route was inside the declaration of your /home1 route. It is likely that you meant it to be outside. I've fixed this (and also fixed some indentation) in the code below.
2. json is undefined in the /home2 route's https.get callback
The variable json is not defined before use in the https.get callback function. You will need a line similar to the one you have in the http.get callback: var json = JSON.parse(body);.
Here's the fixed code for the routes
app.get('/home1', function (req,res) {
http.get('http://developers.agenciaideias.com.br/cotacoes/json', function (res2) {
var body = '';
res2.on('data', function (chunk) {
body += chunk;
});
res2.on('end', function () {
var json = JSON.parse(body);
var CotacaoDolar = json["dolar"]["cotacao"];
var VariacaoDolar = json["dolar"]["variacao"];
var CotacaoEuro = json["euro"]["cotacao"];
var VariacaoEuro = json["euro"]["variacao"];
var Atualizacao = json["atualizacao"];
obj=req.query;
DolarUsuario=obj['dolar'];
RealUsuario=Number(obj['dolar'])*CotacaoDolar;
EuroUsuario=obj['euro'];
RealUsuario2=Number(obj['euro'])*CotacaoEuro;
Oi=1*VariacaoDolar;
Oi2=1*VariacaoEuro;
if (VariacaoDolar<0) {
recomend= "Recomenda-se, portanto, comprar dólares.";
}
else if (VariacaoDolar=0){
recomend="";
}
else {
recomend="Recomenda-se, portanto, vender dólares.";
}
if (VariacaoEuro<0) {
recomend2= "Recomenda-se, portanto, comprar euros.";
}
else if (VariacaoEuro=0){
recomend2="";
}
else {
recomend2="Recomenda-se,portanto, vender euros.";
}
res.render('cotacao_response.jade', {
'CotacaoDolar':CotacaoDolar,
'VariacaoDolar':VariacaoDolar,
'Atualizacao':Atualizacao,
'RealUsuario':RealUsuario,
'DolarUsuario':DolarUsuario,
'CotacaoEuro':CotacaoEuro,
'VariacaoEuro':VariacaoEuro,
'RealUsuario2':RealUsuario2,
'recomend':recomend,
'recomend2':recomend2,
'Oi':Oi,
'Oi2':Oi2
});
});
});
});
app.get('/home2', function (req,res) {
https.get('https://www.quandl.com/api/v3/datasets/BCB/432.json?api_key=YOUR_API_KEY', function (res3) {
var body = '';
res3.on('data', function (chunk) {
body += chunk;
});
res3.on('end', function () {
var json = JSON.parse(body);
var x=json.dataset.data[0][1];
console.log("My JSON is "+x);
res.send('done https: JSON result: '+x);
});
});
});
Final note
You added your API key in the https URL. I would recommend changing the key, if sensitive information is involved.
The HTTPS server and client API is almost identical to the HTTP API.In fact, the client API is the same, and the HTTPS server only differs in that it needs a certificate file.
Starting the server
To start the HTTPS server, you need to read the private key and certificate. Note that readFileSync is used in this case, since blocking to read the certificates when the server starts is acceptable:
// HTTPS
var https = require('https');
// read in the private key and certificate
var pk = fs.readFileSync('./privatekey.pem');
var pc = fs.readFileSync('./certificate.pem');
var opts = { key: pk, cert: pc };
// create the secure server
var serv = https.createServer(opts, function(req, res) {
console.log(req);
res.end();
});
// listen on port 443
serv.listen(443, '0.0.0.0');
Note that on Linux, you may need to run the server with higher privileges to bind to port 443. Other than needing to read a private key and certificate, the HTTPS server works like the HTTP server.

AngularJS: Loading single objects from json

I'm trying to list some posts from a json file then after click one, load the single post, but when I click it the data is not loaded.
I'm using the function below to handle the data
$scope.currentPost = $filter('filter')($scope.posts, {id: $routeParams.id})
Here is my Plnkr: http://plnkr.co/edit/brWn6r4UvLnNY5gcFF2X?p=preview
Updated Plnkr: http://plnkr.co/edit/3P2k60aPyuatjTx9raJU?p=preview
app.controller('MainCtrl', function($scope, $http, $route, $routeParams, $filter) {
$scope.name = 'Test';
$scope.getData = function(){
$http.get('posts.json')
.then(function(res){
$scope.posts = res.data.posts;
$scope.currentPost = $filter('filter')($scope.posts, {id: $routeParams.id});
$scope.currentPost = $scope.currentPost[0]; // $filter apparently returns an array...
});
};
// setInterval($scope.getData, 1000); // DO WE REALLY NEED IT?
$scope.getData();
});
Alternative solution using _ (underscore) findWhere method:
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
app.controller('MainCtrl', function($scope, $http, $route, $routeParams, $filter) {
$scope.name = 'Test';
$scope.getData = function(){
$http.get('posts.json')
.then(function(res){
$scope.posts = res.data.posts;
// id: integer
// $routeParams.id: string
// when comparing integer to string _.findWhere was failing
// always good practice to pass radix to parseInt: http://davidwalsh.name/parseint-radix
$scope.currentPost = _.findWhere($scope.posts, {id: parseInt($routeParams.id, 10)});
});
};
// setInterval($scope.getData, 1000); // DO WE REALLY NEED IT?
$scope.getData();
});
Plnkr: http://plnkr.co/edit/N7UeaOuoNIoQgzQfrkY3?p=preview
In my code I usually use _ but now I've learnt something new - I can use $filter too!

How to load a JSON data Object from other domain (no callback function) with AngularJS

Is it possible to load JSON data without callback function in AngularJS? If I manually download the json file and change the url to 'phones/phones.json'. In jQuery it is possible http://www.sitepoint.com/jsonp-examples/
var phonecatApp = angular.module('phonecatApp', []);
phonecatApp.controller('PhoneListCtrl', ['$scope', '$http',
function ($scope, $http) {
$http.get('https://raw.githubusercontent.com/angular/angular-phonecat/master/app/phones/phones.json').success(function(data) {
$scope.phones = data.splice(0, 5);
});
$scope.orderProp = 'age';
}]);
SOLVED: Thanks! I changed "raw.githubusercontent.com/angular/angular-phonecat/master/app/phones/phones.json" to "rawgit.com/angular/angular-phonecat/master/app/phones/phones.json"
See https://rawgit.com/faq
It was server side problem as Words Like Jared said.
The problem is not with your client but with your server.
http://plnkr.co/edit/a7K79KTae3CPPZx7XMfH?p=preview
var phonecatApp = angular.module('phonecatApp', []);
phonecatApp.controller('PhoneListCtrl', ['$scope', '$http',
function ($scope, $http) {
$http.get('https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS').success(function(data) {
$scope.phones = data;
});
$scope.orderProp = 'age';
}]);
That's virtually the same code pointed to a different URL and it works.
I think you need the HTTP request's response to contain the "Access-Control-Allow-Origin" header with a value of say "*" to access the content from another site. How to do that will vary depending on your server technology.

AngularJS : get back data from a json array with an id

I have a json file where i am stocking informations from all the people in my database. I actually use it to display first name, last name in a web page and i want to add the possibility to display the details of every person.
To do so i'm using the id of the person like this :
.when('/people/:id', {templateUrl: 'partials/people-detail.html'})
It works pretty well, i have a page generated for every person, which is nice. But now I would like to get the information of the person back.
The easiest way would have been to have a json file for every person, but i don't particularly like the idea of having so much file.
So my actual idea is to iterate through the people.json file to find the good one and using it but it's not working.
Here's my controller :
var PeopleController = angular.module ('PeopleController', []);
PeopleController.controller('PeopleDetailCtrl', ['$scope', '$routeParams', '$http',
function($scope, $routeParams, $http) {
$scope.search = function() {
var url = 'data/people.json';
$http.get(url).success(httpSuccess).error(function() {
alert('Unable to get back informations :( ');
});
}
httpSuccess = function(response) {
$scope.persons = response;
}
function getById(arr, id) {
for (var d = 0, len = arr.length; d < len; d += 1) {
if (arr[d].id === id) {
return arr[d];
}
}
}
$scope.search();
$scope.person = getById($scope.persons,$routeParams.id);
}]);
Well, maybe my solution is bad since it doesn't work, but i didn't find another way to do so.
Now i'm all yours :)
Thanks for reading.
The problem is that your $scope.search method contains $http.get() which is asynchronous.
What that means is your next line (the one that sets $scope.person) executes before the json file has been read. As such, $scope.persons is empty at the time it is executed.
You can take advantage of the fact that $http.get() returns a chainable promise here.
So if you change your search() function to return that promise, you can then use then() to populate person when everything has been successful:
$scope.search = function() {
var url = 'data/people.json';
return $http.get(url).success(httpSuccess).error(function() {
alert('Unable to get back informations :( ');
});
}
(note the return statement).
Then change the person population to take advantage of this:
$scope.search().then(function(){
$scope.person = getById($scope.persons,$routeParams.id);
});
I hope getting a person is a whole different event like on click. You can try grep:
$scope.person = function(_id) {
return $.grep($scope.persons, function(item){
return item.id == _id
})[0];
}
Assuming you have all persons available otherwise this logic has to move inside the part of the success callback for the http call.
I used ECMAScript 5 filter to get person by id and moved your search by id to success method since we are dealing with ajax call.
Example:
app.controller('PeopleDetailCtrl', ['$scope', '$routeParams', '$http',
function($scope, $routeParams, $http) {
$scope.search = function() {
var url = 'data.json';
$http.get(url).success(httpSuccess).error(function() {
alert('Unable to get back informations :( ');
});
}
httpSuccess = function(response) {
$scope.persons = angular.fromJson(response);
$scope.person = $scope.persons.filter(function(item){
return item.id==routeParams.id //check for undefined;
});
}
$scope.search();
}]);
Live Example: http://plnkr.co/edit/jPT6aC5UqLdHGJ1Clfkg?p=preview

Update fields with user position using a service

I would like to update some fields when I receive a geoposition for a give user.
Until know I have the following code:
http://jsfiddle.net/VSph2/10/
Firstly, I get a Error: Unknown provider: positionProvider <- position (only on jsfiddle). I do not get this error on my real site.
The problem is that when I get the position I update the position object in the service but it does not update in the HTML view.
Any suggestions?
Try this. Fiddle
var test = angular.module('myApp', []);
var services = angular.module('myApp.services', []);
services.factory('position', ['$http', function ($http) { ...
should be
var test = angular.module('myApp', []);
test.factory('position', ['$http', function ($http) { ...
You should update the controller code as this, to use a callback function and $apply to apply the value set to the scope.
position.getPosition(function (p) {
$scope.$apply(function () {
$scope.position.latitude = p.coords.latitude;
$scope.position.longitude = p.coords.longitude;
$scope.position.accuracy = p.coords.accuracy;
});
});