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

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.

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.

Related

Yet another 'Unknown provider' for an AngularJS service

I actually hate to be that guy, but I've been sitting with this
problem for some days now. I have these three files as a part of a
larger angularjs application. I can not get even this rudimentary test
to pass (or even work). I've been comparing files within the project,
I've read on-line (tried all those ways people have suggested). I have
even written the files from scratch a few times. I'm probably not able
to see my error anymore. I guess this is easier to spot (right away)
for a back-seat driver.
I'd be most appreciative for any help.
The output from gulp/karma
PhantomJS 2.1.1 (Linux 0.0.0) SiteDescriptionService the service should be defined FAILED
Error: [$injector:unpr] Unknown provider: SiteDescriptionServiceProvider <- SiteDescriptionService
http://errors.angularjs.org/1.5.8/$injector/unpr?p0=SiteDescriptionServiceProvider%20%3C-%20SiteDescriptionService (line 4511)
bower_components/angular/angular.js:4511:86
getService#bower_components/angular/angular.js:4664:46
bower_components/angular/angular.js:4516:48
getService#bower_components/angular/angular.js:4664:46
injectionArgs#bower_components/angular/angular.js:4688:68
invoke#bower_components/angular/angular.js:4710:31
workFn#bower_components/angular-mocks/angular-mocks.js:3085:26
loaded#http://localhost:8080/context.js:151:17
inject#bower_components/angular-mocks/angular-mocks.js:3051:28
app/service/sitedescriptor-service-test.js:10:19
app/service/sitedescriptor-service-test.js:4:13
global code#app/service/sitedescriptor-service-test.js:1:9
Expected undefined to be truthy.
app/service/sitedescriptor-service-test.js:17:32
loaded#http://localhost:8080/context.js:151:17
The module declaration
(function(){
'use strict';
angular.module('application.service', []);
})();
The service itself
(function () {
angular.module('application.service')
.service('SiteDescriptorService',
['$http', '$q', function ($http, $q) {
var lastRequestFailed = true,
promise,
items = [];
return {
name: 'SiteDescriptorService',
getItems: function () {
if (!promise || lastRequestFailed) {
promise = $http.get('site.json').then(
function (response) {
lastRequestFailed = false;
items = response.data;
return items;
}, function (response) { // error
lastRequestFailed = true;
return $q.reject(response);
});
}
return promise;
}
};
}]
);
})();
and the test
describe('SiteDescriptionService', function() {
'use strict';
describe('the service', function() {
var service, httpBackend;
beforeEach(module('application.service'));
beforeEach(inject(function(_SiteDescriptionService_, $httpBackend) {
service = _SiteDescriptionService_;
httpBackend = $httpBackend;
console.log(service);
}));
it('should be defined', function() {
expect(service).toBeTruthy();
});
});
});
Cheers
Mats
Looks like you just use incorrect name when injecting dependency, should be 'SiteDescriptorService' and not 'SiteDescriptionService'

jasmine karma unit test "Error: Unexpected request: GET /Content/json/3420_layer0.json"

Writing a simple test case.
describe('Services', function () {
describe('API', function () {
var $httpBackend, $rootScope, createController, requestHandler;
var jsonLayer0 = "/Content/json/3420_layer0.json";
// Set up the module
beforeEach(module('anbud'));
beforeEach(inject(function ($injector) {
// Set up the mock http service responses
$httpBackend = $injector.get('$httpBackend');
$httpBackend.whenGET(jsonLayer0).respond(200, '');
$rootScope = $injector.get('$rootScope');
// The $controller service is used to create instances of controllers
var $controller = $injector.get('$controller');
createController = function () {
return $controller('anbudTreeController', { '$scope': $rootScope });
};
}));
afterEach(function () {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it('should fetch first layer', function () {
$httpBackend.expectGET(jsonLayer0);
var controller = createController();
$rootScope.getFirstLayer();
$httpBackend.flush();
});
I get:
Error: Unexpected request: GET /Content/json/3420_layer0.json
But, I do have:
var jsonLayer0 = "/Content/json/3420_layer0.json";
$httpBackend.whenGET(jsonLayer0).respond(200, '');
So, not sure what the problem is...
Full stack trace:
Error: Unexpected request: GET test
No more request expected
at $httpBackend (C:/git/angularjs/NSview/NSviewer/Scripts/angular-mocks.js:1244:9)
at $httpBackend (C:/git/angularjs/NSview/NSviewer/Scripts/angular-mocks.js:1237:11)
at sendReq (C:/git/angularjs/NSview/NSviewer/Scripts/angular.js:10515:9)
at serverRequest (C:/git/angularjs/NSview/NSviewer/Scripts/angular.js:10222:16)
at processQueue (C:/git/angularjs/NSview/NSviewer/Scripts/angular.js:14745:28)
at C:/git/angularjs/NSview/NSviewer/Scripts/angular.js:14761:27
at Scope.$eval (C:/git/angularjs/NSview/NSviewer/Scripts/angular.js:15989:28)
at Scope.$digest (C:/git/angularjs/NSview/NSviewer/Scripts/angular.js:15800:31)
at Function.$httpBackend.flush (C:/git/angularjs/NSview/NSviewer/Scripts/angular-mocks.js:1543:38)
at Object.<anonymous> (C:/git/angularjs/NSview/NSviewer/app/tests/testServiceAPI.js:54:26)
Error: [$rootScope:inprog] $digest already in progress
http://errors.angularjs.org/1.4.7/$rootScope/inprog?p0=%24digest
at C:/git/angularjs/NSview/NSviewer/Scripts/angular.js:68:12
at beginPhase (C:/git/angularjs/NSview/NSviewer/Scripts/angular.js:16346:15)
at Scope.$digest (C:/git/angularjs/NSview/NSviewer/Scripts/angular.js:15780:9)
at Function.$httpBackend.verifyNoOutstandingExpectation (C:/git/angularjs/NSview/NSviewer/Scripts/angular-mocks.js:1575:38)
EDIT:
Added:
$httpBackend.expectGET(jsonLayer0);
Added:
Full stack trace
It is required to tell $httpBackend to expect a GET request.
Try the following code
it('should fetch first layer', function () {
$httpBackend.expectGET(jsonLayer0);
var controller = createController();
$rootScope.getFirstLayer();
$httpBackend.flush();
});

Karma jasmine and angular controller using 'Controller as' syntax (this instead of $scope)

I'm trying to set up karma to make some unit tests but I can't manage to make it work on a basic example :
This is the controller file :
angular.module('balrogApp.requests', [
/* Dependancies */
])
// Routes configuration
.config(['$routeProvider', function($routeProvider) {
/* $routeProvider configuration */
}])
.controller('requestsController', function(Requests, Users, Projects, RequestsComments, CostEstimations,
Regions, growl, $route, $rootScope, $scope, $location) {
this.test = 'test42';
/* ... */
});
This is the test file :
describe('requestsController', function() {
beforeEach(module('balrogApp.requests'));
var ctrl;
beforeEach(inject(function($controller) {
ctrl = $controller('requestsController');
}));
it('should have test = "test42"', function(){
expect(ctrl.test).toBe("test42");
});
});
But this error is thrown :
Chrome 43.0.2357 (Windows 7 0.0.0) requestsController should have test
= "test42" FAILED
Error: [$injector:unpr] Unknown provider: $scopeProvider <- $scope <- requestsController
http://errors.angularjs.org/1.4.7/$injector/unpr?p0=%24scopeProvider%20%3C-%20%24scope%20%3C-%20requestsController
at C:/Users/aazor102115/Desktop/Dev/Balrog/bower_components/angular/angular.js:68:12
at C:/Users/aazor102115/Desktop/Dev/Balrog/bower_components/angular/angular.js:4289:19
at Object.getService [as get] (C:/Users/aazor102115/Desktop/Dev/Balrog/bower_components/angular/angular.js:4437:39)
at C:/Users/aazor102115/Desktop/Dev/Balrog/bower_components/angular/angular.js:4294:45
at getService (C:/Users/aazor102115/Desktop/Dev/Balrog/bower_components/angular/angular.js:4437:39)
at invoke (C:/Users/aazor102115/Desktop/Dev/Balrog/bower_components/angular/angular.js:4469:13)
at Object.instantiate (C:/Users/aazor102115/Desktop/Dev/Balrog/bower_components/angular/angular.js:4486:27)
at C:/Users/aazor102115/Desktop/Dev/Balrog/bower_components/angular/angular.js:9151:28
at C:/Users/aazor102115/Desktop/Dev/Balrog/bower_components/angular-mocks/angular-mocks.js:1882:12
at Object. (C:/Users/aazor102115/Desktop/Dev/Balrog/tests/requests.js:6:12)
Error: Declaration Location
at window.inject.angular.mock.inject (C:/Users/aazor102115/Desktop/Dev/Balrog/bower_components/angular-mocks/angular-mocks.js:2409:25)
at Suite. (C:/Users/aazor102115/Desktop/Dev/Balrog/tests/requests.js:5:14)
at C:/Users/aazor102115/Desktop/Dev/Balrog/tests/requests.js:1:1
TypeError: Cannot read property 'test' of undefined
at Object. (C:/Users/aazor102115/Desktop/Dev/Balrog/tests/requests.js:10:16)
Chrome 43.0.2357 (Windows 7 0.0.0): Executed 1 of 1 (1 FAILED) ERROR
(0.108 secs / 0.087 secs)
The $scope (on which your controller depends on) is a so-called "local", i.e. it is specific to the instance of the controller and does not live in the dependency injection container. You have to provide it yourself, e.g. as:
beforeEach(inject(function($rootScope, $controller) {
ctrl = $controller('requestsController', { $scope: $rootScope.$new() });
}));
Since you are creating a new scope, it would be good to destroy it after the test:
var scope;
beforeEach(inject(function($rootScope, $controller) {
scope = $rootScope.$new();
ctrl = $controller('requestsController', { $scope: scope });
}));
afterEach(function() {
scope.$destroy();
});

Service will not inject into controller

I've made a handful of Angular applications in the past, but have never really made use of modules. I'm creating an Ionic app right now (which uses Angular) and for some reason I cannot get my services to inject into the controllers.
controllers.js
angular.module('myapp.controllers', [])
.controller('StreamCtrl', ['$scope', 'StreamService',
function($scope, StreamService) {
$scope.playlists = [1,2,3,4];
}]);
services.js
angular.module('myapp.services', [])
.factory('StreamService', ['$scope', function($scope) {
var self = {
'fetching' : false,
'streamItems' : []
};
return self;
]);
app.js
angular.module('myapp', ['ionic',
'myapp.services',
'myapp.controllers',
'ngCordova',
'LocalStorageModule'])
// And lots of other code that isn't needed for this question.
So when I try and load the StreamCtrl I end up getting the following error:
Error: [$injector:unpr] Unknown provider: $scopeProvider <- $scope <-StreamService
http://errors.angularjs.org/1.3.6/$injector/unpr?p0=<ion-nav-view name="menuContent" class="view-container" nav-view-transition="ios">copeProvider%20%3C-%20%24scope%20%3C-%20StreamService
at REGEX_STRING_REGEXP (http://localhost:8100/lib/ionic/js/ionic.bundle.js:7888:12)
at http://localhost:8100/lib/ionic/js/ionic.bundle.js:11806:19
at Object.getService [as get] (http://localhost:8100/lib/ionic/js/ionic.bundle.js:11953:39)
at http://localhost:8100/lib/ionic/js/ionic.bundle.js:11811:45
at getService (http://localhost:8100/lib/ionic/js/ionic.bundle.js:11953:39)
at Object.invoke (http://localhost:8100/lib/ionic/js/ionic.bundle.js:11985:13)
at Object.enforcedReturnValue [as $get] (http://localhost:8100/lib/ionic/js/ionic.bundle.js:11847:37)
at Object.invoke (http://localhost:8100/lib/ionic/js/ionic.bundle.js:11994:17)
at http://localhost:8100/lib/ionic/js/ionic.bundle.js:11812:37
at getService (http://localhost:8100/lib/ionic/js/ionic.bundle.js:11953:39)
See this working fiddle ,
You are treating service as if it was a controller, never inject a $scope into service, its not there
var myApp = angular.module('myApp',['myapp.services','myapp.controllers']);
angular.module('myapp.controllers', [])
.controller('StreamCtrl', ['$scope', 'StreamService',
function($scope, StreamService) {
$scope.playlists = [1,2,3,4];
}]);
angular.module('myapp.services', []).factory('StreamService', function() {
var self = {
'fetching' : false,
'streamItems' : []
};
return self;}
);
Your error clearly says there is problem inside StreamService factory.
You could never inject $scope inside factory. Removing $scope dependency will solve your issue.
Factory basically used to expose singleton methods, common and sharable data. Usually we write any service call or method which can be accessible by any module who inject it using its dependancy.
Factory
angular.module('myapp.services', [])
.factory('StreamService', [function() {
var self = {
'fetching': false,
'streamItems': []
};
return self;
}]);
Working fiddle.
Hope this could help you. Thanks.

Weird error when testing angular controller with $httpBackend

I've been trying to fix it for hours. Unfortunately with negative effect so please help me.
In my application I want to test my $http requests. I'm doing it by using $httpBackend.
Here is my controller code:
angular.module('app').controller('testController',function($scope,$http){
$http.get('/test/users').success(function(data){
console.log('wtf');
});
})
My unit test code:
describe('testController tests', function(){
var $httpBackend, $scope, createController;
beforeEach(module('app'));
beforeEach(inject(function($injector, ngTableParams, notifier,identity, $sessionStorage, $location){
$httpBackend = $injector.get('$httpBackend');
$httpBackend.whenGET('/test/users').respond({test: 'test'});
$rootScope = $injector.get('$rootScope');
$scope = $rootScope.$new();
var $controller = $injector.get('$controller');
createController = function(){
return $controller('testControler', { '$scope': $scope, '$http': $httpBackend });
};
}));
it('should fetch users ', function() {
$httpBackend.expectGET('/test/users');
var controller = createController();
$httpBackend.flush();
});
});
It's not working. I always have the following error:
TypeError: Object function $httpBackend(method, url, data, callback, headers, timeout, withCredentials) {
var xhr = new MockXhr(),
expectation = expectations[0],
wasExpected = false;
function prettyPrint(data) {
return (angula...<omitted>... } has no method 'get'
at new <anonymous> (http://localhost:9876/base/public/app/controllers/testController.js:256:11)
at invoke (http://localhost:9876/base/public/libraries/angular/angular.js:3805:17)
at Object.instantiate (http://localhost:9876/base/public/libraries/angular/angular.js:3816:23)
at $get (http://localhost:9876/base/public/libraries/angular/angular.js:6922:28)
at createController (http://localhost:9876/base/test/unit/testControllerSpec.js:70:18)
at null.<anonymous> (http://localhost:9876/base/test/unit/testControllerSpec.js:89:26)
at jasmine.Block.execute (http://localhost:9876/base/node_modules/karma-jasmine/lib/jasmine.js:1145:17)
at jasmine.Queue.next_ (http://localhost:9876/base/node_modules/karma-jasmine/lib/jasmine.js:2177:31)
at http://localhost:9876/base/node_modules/karma-jasmine/lib/jasmine.js:2167:18
Any ideas what does it mean and how to fix it?
I've found error in my code. $httpBackend shouldn't be injected into controller.
I think the problem is you need to add the dependencies to your module creation:
angular.module('app', []).controller ...
instead of
angular.module('app').controller ...

Categories