Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock a Service containing a resource in AngularJS

I have a service which contains a resource factory like this:

serviceModule.factory('ProjectResource', ['$resource', function($resource){
    return $resource('/projects/:id.json', {}, {
        'query': {method: 'GET', isArray: true}}
    );
}]);

In a form, which resides in a controller, I inject the serviceModule, and I create a new instance of the resource object:

  $scope.project = new ProjectResource({name: 'Enter a name'})

I have some issues with mocking it. I have tried creating a mock object like this, and injecting it in the controller:

 mockProjectResource = {
            query: function(){
                deferred = $q.defer();
                deferred.resolve({id: 1, :name:'test'});
                return deferred.promise;
            }
        };

No matter the unit test, I get the error:

TypeError: undefined is not a function

Which points to the initialization of the Project Resource object ($scope.project = new ProjectResource({name: 'Enter a name'})).

Are there any good way to mock the new ProjectResource(...)?

like image 225
Dofs Avatar asked Jun 24 '14 08:06

Dofs


1 Answers

Another way to mock a resource based service is like this:

// the name of an object should start with a capital letter
// in the case where we create a function object (as opposed to
// a literal object).
MockProjectResource = function(){};

// we add the "query" method to the "prototype" property
MockProjectResource.prototype.query = function(){
  deferred = $q.defer();
  deferred.resolve({id: 1, :name:'test'});
  return deferred.promise;
};

Mocking the query function like above works in the case where the controller expects the promise to be returned as a result of the call, e.g.:

var projectController = angular.module('projectController', []);
projectController.controller('ProjectController', ['$scope', 'ProjectResource',
  function($scope, ProjectResource) {

    var promise = ProjectResource.query();
    promise.then(function(data) {
        console.log(data);
      },
      function(err){
        console.log(err);
      });

}]);

However, if the controller expects the result to be sent in a callback, like this:

      ProjectResource.query(function(data) {
          console.log(data);
        },
        function(err){
          console.log(err);
        });

then, the service needs to be mocked like this:

MockProjectResource.prototype.query = function(success, error){
  var deferred = q.defer();
  var promise = deferred.promise;
  promise.then(success, error);
  deferred.resolve({id: 1, :name:'test'});
};    

For a full example, see my answer to a similar question:

How do you mock an angularjs $resource factory

like image 65
claudius Avatar answered Sep 28 '22 17:09

claudius