Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock angular $resource in jasmine tests

I am trying to test a controller which uses angular's $resource.

function PermissionsCtrl($scope, $resource, $cookies) {
  var Object = $resource('/v1/objects/:id');
  loadObjects();

  function loadObjects() {
    $scope.myAppObjects = new Array();

    var data = AppObject.get({find: '{"app_id": '+wtm.app_id+'}'},
      function(){
        if (data.results) {
          for(var i = 0; i< data.results.length; i++) {
            if(!data.results[i].is_deleted) {
              (function(i){
                $scope.objects(data.results[i]);
              }(i));
            }
          }
        }
      },
      function(error){console.log(error);});
  }

And here is the test code.

var apiServer = "...";
var app_id = 999
var mock_object_data = {...};


describe('apps permissionsCtrl', function(){
  var scope, ctrl, $httpBackend;

  // Create a matcher for comparing data 
  beforeEach( function() {
    this.addMatchers({
      toEqualData: function(expected) {
        return angular.equals(this.actual, expected);
      }
    });
  });

  // Create the controller with injected data/services
  beforeEach(inject(function(_$httpBackend_, $rootScope, $controller, $resource) {
    $httpBackend = _$httpBackend_;
    // cookie data to inject
    var cookies = new Array();
    cookies['id'] = '...'; // just needs to be declared


    $httpBackend.expectGET(apiServer+'/v1/app_objects?    find=%7B%22app_id%22:'+app_id+'+%7D&access_token=' + cookies['id'])
      .respond( mock_object_data );

    var $injector = angular.injector(['ng', 'ngResource']);
    var $resource = $injector.get('$resource');

    scope = $rootScope.$new();
    ctrl = $controller(PermissionsCtrl, {$scope: scope, $cookies: cookies, $resource: $resource});
  }));

  it('should put object data into $scope', function() {
    $httpBackend.flush();
    expect(scope.objects).toEqualData( mock_object_data );

}); });

When I run this I get

Error: Unknown provider: $resourceProvider <- $resource

at the line where I try to create my controller. I don't understand how to inject this into my controller and no matter what I try I get the same error. A couple things I've tried are

  • Declaring a an empty mock object and passing it through similar to my cookies variable. I figure this is probably a bad solution anyway since I actually want to use the service.
  • Mimicking the scope mock and passing it into my inject function and passing $resource.$new() to my controller.
  • Doing nothing and hoping that httpBackend would cover it since that's what ultimately gets called anyway. Vojta Jína made it sound like that would work but no dice.
  • Mild epithets. Satisfying but not very effective.
like image 827
akronymn Avatar asked Jan 09 '13 16:01

akronymn


People also ask

How does Jasmine define Angular spec?

We use the Jasmine-provided it function to define a spec. The first parameter of it is a text description of what the spec will be testing — in this case we have a defined component. The second parameter is a function that will run the test. We then use Jasmine's expect function to define our expectation.


2 Answers

After more reading and more experimenting it seems the right way to do this is to abstract the use of $resource out of the controller. In my case I wrote a service that relies on $resource and then inject that service into my controller. Meanwhile I test that service separately from my controller. Better practice all around.

My service declaration:

angular.module('apiModule', ['localResource', 'ngCookies'])
.factory('apiService', function($resource, $cookies) {

and in my unit tests I pass it through in a beforeEach setup function

beforeEach(module('apiModule'));
like image 173
akronymn Avatar answered Oct 09 '22 20:10

akronymn


Try to instantiate $resource with the following code:

var $injector = angular.injector(['ng', 'ngResource']);
var $resource = $injector.get('$resource');

Similar for other services, except when they are in other modules still. Then add that module to the array.

More info

like image 35
asgoth Avatar answered Oct 09 '22 19:10

asgoth