Zachary Jacobi Zachary Jacobi - 4 months ago 21
Javascript Question

Testing a service that requires $resource using $httpBackend in Angular.JS

I've looked at several answers on SO, and have read through the official docs. From what I've seen, this should be working.

In my service, I have:

var RESTServices = angular.module('RESTServices', []);

RESTServices.service('restCall', ['$resource', function($resource){
return {
servList: function(args, scope){
// Lists servers from the API method
$resource('http://localhost:1000/apiv1/servers')
.get(args).$promise.then(function (result) {
scope.servers = result.server_list;
}, function(error){
errorHandler(scope, error)
})
}, ... etc.,
};
}]);


I am trying to run the test:

describe('Services that require API calls', function() {
var restCall,
$httpBackend;
beforeEach(function () {
module('RESTServices');

inject(function (_$httpBackend_, _restCall_) {
restCall = _restCall_;
$httpBackend = _$httpBackend_;
});
});
it('Should supply a list of servers', function () {
//var serverList = ['Thufir Hawat', 'Duncan Idaho'];
//$httpBackend.expectGET('http://localhost:1000/apiv1/servers')
// .respond({server_list: serverList});
// Would continue writing if $resource could inject...
});
});


However I receive the following message when I do:

Chrome 31.0.1650 (Windows Vista) Services that require API calls Should supply a list of servers FAILED
Error: [$injector:unpr] Unknown provider: $resourceProvider <- $resource <- restCall
http://errors.angularjs.org/1.2.11/$injector/unpr?p0=%24resourceProvider%20%3C-%20%24resource%20%3C-%20restCall
at E:/workspace/JSUI/app/lib/angular/angular.js:78:12
at E:/workspace/JSUI/app/lib/angular/angular.js:3543:19
at Object.getService [as get] (E:/workspace/JSUI/app/lib/angular/angular.js:3670:39)
at E:/workspace/JSUI/app/lib/angular/angular.js:3548:45
at getService (E:/workspace/JSUI/app/lib/angular/angular.js:3670:39)
at invoke (E:/workspace/JSUI/app/lib/angular/angular.js:3697:13)
at Object.instantiate (E:/workspace/JSUI/app/lib/angular/angular.js:3718:23)
at Object.<anonymous> (E:/workspace/JSUI/app/lib/angular/angular.js:3586:24)
at Object.invoke (E:/workspace/JSUI/app/lib/angular/angular.js:3707:17)
at E:/workspace/JSUI/app/lib/angular/angular.js:3549:37
Error: Declaration Location
at window.inject.angular.mock.inject (E:/workspace/JSUI/app/lib/angular/angular-mocks.js:2134:25)
at null.<anonymous> (E:/workspace/JSUI/test/unit/servicesSpec.js:133:9)
Chrome 31.0.1650 (Windows Vista): Executed 30 of 30 (1 FAILED) (0.497 secs / 0.14 secs)


Everything I've read tells me this should be working, so what am I missing? It IS possible to use $httpBackend to mock $resource, correct? Posts from the google group (including this one seem to suggest that it should work without a problem.

Answer

After trying many things, and doing some more research, it seems to be that the module that includes the declaration of 'ngResource' needs to be included in the test for it to work. For example, I declared 'ngResource' in app.js in the module myApp, so once I include this, the tests work.

in app.js:

var myApp = angular.module('myApp', [
  'ngRoute',
  'ngCookies',
  'ngResource',
  'myControllers',
  'myDirectives',
  'myServices',
  'RESTServices'
]);

in the spec:

describe('Testing Services that require API calls', function() {

    var restCall,
        $httpBackend,
        $resource,
        scope;

    beforeEach(function () {

        module('myApp'); //this line fixed it
        module('RESTServices');

        inject(function (_$httpBackend_, _restCall_, _$resource_) {
            $httpBackend = _$httpBackend_;
            $resource = _$resource_;
            restCall = _restCall_;
        });

        scope = {};

    });

    describe('servList', function() {
        it('Should supply a list of servers', function () {
            var serverList = ['Thufir Hawat', 'Duncan Idaho'];
            $httpBackend.expectGET('http://localhost:1000/apiv1/servers')
                .respond({server_list: serverList});
            restCall.servList({}, scope);
            $httpBackend.flush();
            expect(arraysEqual(scope.servers, serverList)).toBeTruthy();
        });
    });
});

ETA: Someone else chimed in that they fixed this problem for themselves by adding module('ngResource'); where I added module('RESTServices');. I'm willing to bet that the important thing is having a ngResource imported into your tests, either directly or indirectly.

Comments