How can I Unit Test Rest Angular Service and Controller? - angularjs

Rest-angular for Api Calling .
My Aim to Write a Unit test Case by calling Controller and Test all the Scope are assigned,the Code blocks of with REST API Response But not MOCK RESPONSE.
Rest Angular Service :-
(function () {
angular.module('movieApp').service('movieApiService', callMoviesApi);
function callMoviesApi(Restangular) {
this.getMyMovie= function (Id) {
return Restangular.one('movies/' + movieId).get().then(function(result){
return result.plain();
});
};
this.getMoviesList = function () {
return Restangular.all('movies').getList().then(function(result){
return result.plain();
});
};
}
}());
Where I am Injecting this Service to Controller as a Dependency
Controller Code Follows :-
angular.module('movieApp').controller('MoviesController', ['$scope','movieApiService',
function ($scope, MovieService) {
$scope.movie = $stateParams.movieId;
MovieService.getMovieDetails($scope.movie).then(function (result) {
$scope.movieDetails = result;
$scope.movieId = result._id;
$scope.movieName = result.displayName;
});
}
]);
I did tried to Write a Unit test for the Above Controller not Going good :-(
Test Code Follows:-
'use strict';
(function() {
describe('MoviesController', function() {
//Initialize global variables
var scope,stateParams={},
MoviesController;
// Load the main application module
beforeEach(module('movieApp'));
beforeEach(inject(function($controller, $rootScope,$stateParams) {
scope = $rootScope.$new();
stateParams.movieId='Baahubali';
HomeController = $controller('MoviesController', {
$scope: scope,
$stateParams:stateParams
});
}));
it('Should call movieApi and Assign Scopes', function() {
var Api="http://testsite.com/moives/thor";
var myScope=$httpBackend.expectGET(Api).passthrough();
expect(scope.movie).toBeDefined();
console.log('****'+scope.movie.displayName);
});
});
})();
Error is Raising :-
Error: Unexpected request: GET http://testsite.com/movies/undefined
Expected GET http://testsite.com/movies/undefined?
at $httpBackend (C:/wrokingdir2015/public/lib/angular-mocks/angular-mocks.js:1245)
at sendReq (C:/wrokingdir2015/public/lib/angular-mocks/public/lib/angular/angular.js:9695)
Could Any One help me to Write a Unit test case Which can Initialize controller and Assing Scopes like in real controller for testing .
Honestly iam New Guy for Unit testing .

I suggest Selenium with Cucumber for having the scenarios that you test in a nice and readable format
but for testing only a REST api you just need an implementation of javax.ws.rs.client.Client, I use org.glassfish.jersey.client.JerseyClient.
private final Client client = ClientBuilder.newClient();
e.g.
#When("^I want to retrieve all cells for the report with id \"([^\"]*)\".$")
public void accessCellReport(String id) {
response = client.target(URL).path(PathConstants.PATH_ID)
.resolveTemplate(PathConstants.PARAM_ID, reportId).request(MediaType.APPLICATION_JSON).get();
RestAssertions.assertResponseOk(response);
}

First of all i would use Restangulars one method as it supposed to be used.
Read more about it here: https://github.com/mgonto/restangular#creating-main-restangular-object
Restangular.one('movies', movieId);
In my service test i would do something like this to test that the correct endpoint has been called.
it('should call /movies/{movieId}', function() {
var spy = sinon.spy(Restangular, 'one');
var movieId = 1;
movieApiService.getMyMovie(movieId);
expect(spy).to.have.been.calledWith('movies', movieId);
});
Then I would make a sinon stub to mock the reponse from the service in another test for the controller.
it('should set my movies variabel after calling movie service', function() {
var mockResponse = [
{
id: 1,
title: 'Titanic'
},
{
id: 2,
title: 'American History X'
}
];
sinon.stub(movieApiService, 'getMyMovie')
.returns(
$q.when(
[
{
id: 1,
title: 'Titanic'
},
{
id: 2,
title: 'American History X'
}
]
);
);
expect($scope.movieList).to.equal(mockResponse);
});
And another test for checking that the controller catch function is called.
it('should call error handling if service rejects promise', function() {
sinon.stub(movieApiService, 'getMyMovie')
.returns(
$q.reject('an error occured when fetching movie');
);
});

I suggest using Selenium:
http://www.seleniumhq.org/.
Easy to write unit tests and can be automatized with jenkins build.

Related

How to write a karma-jasmine test for the values inside an object attached in a function for a controller written in john papa stye

This is how my controller looks like:
(function() {
'use strict';
angular.module('myApp', [])
.controller('vmCtrl', vmCtrl);
vmCtrl.$inject = ['$state', 'API', 'serviceConfig'];
function vmCtrl($state, API, serviceConfig) {
var vm = this;
vm.formValues = {};
vm.submitForm = function() {
vm.formValues = {
"name": vm.formValues.name,
"age": "18",
"schoolId": vm.formValues.schoolId,
"mobno": "21234"
};
var url = serviceConfig.BASE_URL + 'details';
API.post(url, vm.formValues)
.then(submitForm_success)
.catch(submitForm_error);
}
}
})();
the following specs in karma returned success on testing,
it('should define vmCtrl', function() {
expect(vmCtrl).toBeDefined();
});
it('should define submitForm', function() {
expect(vmCtrl.submitForm).toBeDefined();
});
Now is it possible to test the values inside the object formValues? Like if I need to test the age using .toEqual(18)
How should I write the spec for this case?
You need to invoke the method first and then check the value.
it('should define submitForm', function () {
vmCtrl.submitForm();
expect(vmCtrl.formValues.age).toEqual(18);
expect(vmCtrl.formValues.mobno).toEqual(21234);
});
Yes, javascript doesn't really have any notion of private variables. So you can write the following:
it('should initialize formValues.age', function () {
expect(vmCtrl.formValues.age).toEqual(18);
});
Just be aware, that for that test to pass, you would first need to call vmCtrl.submitForm() and in order for that to work, you would need to properly mock API.post()

Testing helpers functions with karma

In angular, I have this factory
function helperFunction(user){
// more code
return user;
}
angular.module('factories', [])
.factory('Users', function() {
var users = [];
return {
add: function(user) {
user = helperFunction(user);
users.push(user);
},
all: function(){
return users;
}
};
});
with karma, I can test the factory, similar to
describe('factories', function() {
beforeEach(module('factories'));
var users;
beforeEach(inject(function(_Users_) {
users = _Users_;
}));
it('test over add function', function(){
users.add({name:'name'});
// ...
});
});
});
how I can test the helperFunction ?
I'm not sure for what you are going to test because your "add" function doesn't return any value, so it can't be consumed by either a controller or another service.
Here are some resources that could be useful:
Testing service only
Testing service used by a controller
For your case, just include the helper function in your "Users" service or a "Helpers" service as you can't test a function that has no relate to any scope or service. But I suppose there is no need to test it here because the "add" functionality always means you just add something, and you want to test critical parts of your app.

AngularJS testing with firebase/mockfirebase in a service

I've been trying to write some unit tests for my services which use AngularFire to communicate with Firebase inside an Angular website.
I'm new to AngularJS and so I feel like I'm missing something obvious but couldn't find any great examples online (at least not that spoke to my limited knowledge).
I found some limited docs on MockFirebase https://github.com/katowulf/mockfirebase/tree/master/tutorials and that showed how to pretty much mock out the data so I did that.
For further examples of mockfirebase I looked at the angular fire's unit tests https://github.com/firebase/angularfire/tree/master/tests/unit but that didn't seem to show me the right way.
Here is my service --
app.service('Subscription', function ($firebase, FIREBASE_URL, $q) {
var ref;
var Subcription = {
ref: function () {
if (!ref) ref = new Firebase(FIREBASE_URL + "/subscriptions");
return ref;
},
validateSubscription: function(userId){
var defer = $q.defer();
$firebase(Subcription.ref().child(userId))
.$asObject()
.$loaded()
.then(function (subscription) {
defer.resolve(subscription.valid === true);
});
return defer.promise;
},
recordSubscription: function(userId){
return Subcription.ref().$set(userId, {valid: true});
}
};
return Subcription;
});
Here is the spec file --
describe('Service: subscription', function () {
// load the service's module
beforeEach(module('clientApp'));
// instantiate service
var subscription;
var scope;
beforeEach(inject(function (_Subscription_, $rootScope) {
MockFirebase.override();
subscription = _Subscription_;
scope = $rootScope.$new();
}));
it('allows access when the user id is in the subscription list', function () {
subscription.ref().push({'fakeUser': {valid: true}});
subscription.ref().flush();
var handler = jasmine.createSpy('success');
subscription.validateSubscription('fakeUser').then(handler);
scope.$digest();
expect(handler).toHaveBeenCalledWith(true);
});
});
It seems like the problem is that the promise never gets resolved inside of $asobject.$loaded because that angularfire part isn't happening.
I get the following as a result of the test: 'Expected spy success to have been called with [ true ] but it was never called.'

accessing atributes of a service in angularjs

I created a service to share some data between two controllers. The thing is that this controllers set and get some data from this service. But I don't know why when I try to get data, all this variables are not set.
My code is this one:
var appModule = angular.module('app', ['mgcrea.ngStrap'])
// custom service to share/collect data between controllers
// this objects are populated by the controllers
.service('sharedProperties', function () {
this.searchPattern = {
basicFilters: {},
advanceFilters: {}
};
});
// controller for main section
appModule.controller('parentController', function ($scope, $aside, sharedProperties) {
$scope.basicFilters = {
category: 'undef',
masterbrand: {value:'undef', text: 'Any'},
page: 1,
perPage:10,
q:''
};
// populate object in service
$scope.updatePatternSearch = function(newValue, oldValue, scope) {
sharedProperties.searchPattern.basicFilters = 'HI!, I have a value!';
};
$scope.$watch('basicFilters', 'updatePatternSearch', true);
// get variables from service
$scope.search = function() {
// ** PROBLEM **
// firebug says that is:basicFilters: {},
// advanceFilters: {}
// empties????, why??
console.log(sharedProperties.searchPattern);
}
}
});
There are lots of typos and erros in your plnkr code.
I have forked and updated it. It's working fine.
Have a look at this - http://plnkr.co/edit/BVFjufOQFFlhB2gTqIeB?p=preview

Unreadable data from $resource in angular.js

I have a very strange problem with an angular app we are building. Whenever i load some data from a resource defined like below (simplest example I could build) I get some data back wich I can use for databinding (eg. ng-repeat='message in messages' or as {{message.id}}) however I can never read it from javascript by accessing it as an array or object (depending on wether i used get({id:myId}) or query()).
Iterating over it only gives me keys like $get, $query, $save, etc... but no actual data.
app.factory('Message', ['$resource', function($resource) {
return $resource('MY_URL/messages/:id', {id: '#id'});
}]);
app.service('messageService', ['$rootScope', 'Message', function($rootScope, Message) {
var messages = Message.query();
var selectedMessage = null;
var service = {};
service.get = function(id) {
// Problem A (see below for details)
if (arguments.length === 1) return Message.get({id: id});
else return messages;
};
var MenuCtrl = function($scope, Project, messageService, otherService) {
$scope.projects = Project.query();
$scope.messages = messageService.get();
// Problem B (details below)
};
At Problem A i want to be able to return a single element form a collection that has already been fetched, however i need some way to handle calls that happen before the data is ready.
At problem B i would like to process some of the fetched data and pass the result to "otherService" however i need a way to delay this until the data is ready.
I have only seen this issue come up in unit testing, and the way to get around it is by "flushing" the mock $httpBackend.
According to the API docs:
The $httpBackend used in production, always responds to requests with responses asynchronously. If we preserved this behavior in unit testing, we'd have to create async unit tests, which are hard to write, follow and maintain. At the same time the testing mock, can't respond synchronously because that would change the execution of the code under test. For this reason the mock $httpBackend has a flush() method, which allows the test to explicitly flush pending requests and thus preserving the async api of the backend, while allowing the test to execute synchronously.
Here's an example with some context:
// define a resource within a service
angular.module('app.services', ['ngResource'])
.factory('Message', function ($resource) {
var url = ...
, params = ...
, actions = ...;
return $resource(url, params, actions);
}
// Query the resource in a controller
function MessagesCtrl ($scope, $routeParams, Message) {
$scope.messages = Message.query();
}
// unit test with a mocked backend
describe('MessagesCtrl', function() {
var scope, ctrl, $httpBackend, messages;
beforeEach(inject(function (_$httpBackend_, $rootScope, $controller) {
$httpBackend = _$httpBackend_;
scope = $rootScope.$new();
messages = [
{
id: '1',
text: 'foo',
}, {
id: '2',
text: 'foo',
}
]
$httpBackend.expectGET('/api/messages').respond(messages);
ctrl = $controller('MessagesCtrl', {$scope: scope});
}));
it('should get a list of messages', function () {
// THE NEXT LINE WILL SOLVE THE PROBLEM
$httpBackend.flush();
expect(scope.message).toEqualData(message);
});
});

Resources