$httpBackend is undefined although angular-mock is included - angularjs

This is my test. I get error that $httpBackend is undefined.
describe("Objects Service", function () {
var $httpBackend, $rootScope, scope, datacontext, config;
beforeEach(function () {
module('agApp');
});
beforeEach(inject(function ($rootScope, _$httpBackend_, _datacontext_, _config_) {
scope = $rootScope.$new();
datacontext = _datacontext_;
$httpBackend = _$httpBackend_;
config = _config_;
}));
it("should call right API adress to get all objects", function () {
$httpBackend.whenGET('/api/objects').respond(200);
datacontext.objects.getObjects(function (data) {
$httpBackend.flush();
});
});
afterEach(function () {
$httpBackend.verifyNoOutstandingExpectations();
$httpBackend.verifyNoOutstandingRequest();
});
});
3 specs, 1 failure
Spec List | Failures
Objects Service should call right API adress to get all objects
Error: [$injector:unpr] Unknown provider: configProvider <- config
http://errors.angularjs.org/1.3.9/$injector/unpr?p0=configProvider%20%3C-%20config
Error: [$injector:unpr] Unknown provider: configProvider <- config
http://errors.angularjs.org/1.3.9/$injector/unpr?p0=configProvider%20%3C-%20config
at http://localhost/WebRenter/Scripts/vendor/angular.js:64:20
at http://localhost/WebRenter/Scripts/vendor/angular.js:3995:21
at Object.getService [as get] (http://localhost/WebRenter/Scripts/vendor/angular.js:4142:53)
at http://localhost/WebRenter/Scripts/vendor/angular.js:4000:47
at getService (http://localhost/WebRenter/Scripts/vendor/angular.js:4142:53)
at Object.invoke (http://localhost/WebRenter/Scripts/vendor/angular.js:4174:13)
at Object.workFn (http://localhost/WebRenter/bower_components/angular-mocks/angular-mocks.js:2436:20)
at attemptSync (http://localhost/WebRenter/Scripts/jasmine/jasmine.js:1741:24)
at QueueRunner.run (http://localhost/WebRenter/Scripts/jasmine/jasmine.js:1729:9)
at QueueRunner.execute (http://localhost/WebRenter/Scripts/jasmine/jasmine.js:1714:10)
Error: Declaration Location
at window.inject.angular.mock.inject (http://localhost/WebRenter/bower_components/angular-mocks/angular-mocks.js:2407:25)
at Suite. (http://localhost/WebRenter/Test/objects/repository.objects.Spec.js:9:16)
at addSpecsToSuite (http://localhost/WebRenter/Scripts/jasmine/jasmine.js:725:25)
at Env.describe (http://localhost/WebRenter/Scripts/jasmine/jasmine.js:695:7)
at jasmineInterface.describe (http://localhost/WebRenter/Scripts/jasmine/jasmine.js:2969:18)
at http://localhost/WebRenter/Test/objects/repository.objects.Spec.js:4:1
TypeError: Cannot read property 'whenGET' of undefined
TypeError: Cannot read property 'whenGET' of undefined
at Object. (http://localhost/WebRenter/Test/objects/repository.objects.Spec.js:20:20)
at attemptSync (http://localhost/WebRenter/Scripts/jasmine/jasmine.js:1741:24)
at QueueRunner.run (http://localhost/WebRenter/Scripts/jasmine/jasmine.js:1729:9)
at QueueRunner.execute (http://localhost/WebRenter/Scripts/jasmine/jasmine.js:1714:10)
at Spec.Env.queueRunnerFactory (http://localhost/WebRenter/Scripts/jasmine/jasmine.js:608:35)
at Spec.execute (http://localhost/WebRenter/Scripts/jasmine/jasmine.js:346:10)
at Object.fn (http://localhost/WebRenter/Scripts/jasmine/jasmine.js:2059:43)
at attemptAsync (http://localhost/WebRenter/Scripts/jasmine/jasmine.js:1771:24)
at QueueRunner.run (http://localhost/WebRenter/Scripts/jasmine/jasmine.js:1726:9)
at QueueRunner.execute (http://localhost/WebRenter/Scripts/jasmine/jasmine.js:1714:10)
This is datacontext:
angular.module("agApp").factory("datacontext", ['$http', '$q', 'repositories', function ($http, $q, repositories) {
var RepoNames = ['objects', 'images', 'objectattributes', 'info', 'units', 'unitattributes']
var service = {
}
init();
return service;
function init() {
defineLazyLoadedRepos();
}
function defineLazyLoadedRepos() {
RepoNames.forEach(function (name) {/**/
Object.defineProperty(service, name, { //
configurable: true,
get: function () {///
var repo = repositories.getRepo(name); //samo prvi put a poslije može confugurable false
Object.defineProperty(service, name, {
value: repo,
configurable: false,
enumerable: true
});
return repo;
}///
});
//
}); /**/
}
} ]);
This is start of objects.repository file:
(function () {
var serviceId = 'repository.objects';
angular.module("agApp").factory(serviceId, ['$http', '$q', '$cacheFactory', 'repository.abstract', 'config', function ($http, $q, $cacheFactory, AbstractRepository, config) {
var entityName = 'objects';
var apiRootUrl = ROOT + "api/";
var cache = $cacheFactory("objectCache");
var cacheOn = config.cache.globalCache && config.cache.objectCache;
var _getObjects = function (object) {
var deferred = $q.defer();
$http.get(apiRootUrl + "objects").then(function (data, status, headers, config) {
deferred.resolve(data.data);
}, function (response) {
self._queryFailed(response);
deferred.reject();
});
return deferred.promise;
}
This is config:
(function () {
'use strict'
var agApp = angular.module('agApp');
var apiUrl = "api/";
//ROOT je definiran na layoutu
var viewsUrl = ROOT + 'App/Scripts/views';
var config = {
version: '0.0.1',
apiUrl: apiUrl,
viewsUrl: viewsUrl,
root:ROOT,
cache:{
globalCache:true,
objectCache:true,
objectAttrCache:true,
unitCache:true
}
};
agApp.value('config', config);
agApp.config(['$logProvider','$locationProvider', function ($logProvider,$locationProvider) {
$locationProvider.html5Mode({
enabled: true,
});
if ($logProvider.debugEnabled) {
$logProvider.debugEnabled(true);
}
} ]);
})();

Based on the information you've provided, first, look at the page that your first error message links to:
https://docs.angularjs.org/error/$injector/unpr?p0=configProvider%20%3C-%20config
It doesn't look like you're redefining your module or injecting a controller into a controller.
I think the most likely reason you're having this error (based on assuming there aren't other problems, and the fact that I had a similar problem) is that you either didn't include config in your karma.conf.js file, or if you did, you included it after your test. The order of files matters in Karma:
http://karma-runner.github.io/0.8/config/files.html
You've probably figured out your problem by now, but I had a similar one and would've appreciated an answer when looking for it.

Related

How to write test case for JSON getting form factory in AngularJS

I am trying to write the test cass for the factory which is returing a JSON response.
But I am getting the error:
Error: [$injector:unpr] http://errors.angularjs.org/1.4.1/$injector/unpr?p0=serviceProvider%20%3C-%20service
at Error (native)
Here is my code:
(function () {
angular.module('uspDeviceService',[]).factory('getDevice', GetDevice);
GetDevice.$inject = ['$http'];
function GetDevice($http) {
getDeviceList = function() {
return $http.get("static/test-json/devices/device-list.json");
}
return {
getDeviceList: getDeviceList
}
}
}());
Code for Test case:
describe('Get Product test', function() {
beforeEach(module('uspDeviceService'));
var service, httpBackend, getDevice ;
beforeEach(function () {
angular.mock.inject(function ($injector) {
//Injecting $http dependencies
httpBackend = $injector.get('$httpBackend');
service = $injector.get('service');
getDevice = $injector.get('getDevice');
})
});
console.log('Injection Dependencies is done');
describe('get Device List', function () {
it("should return a list of devices", inject(function () {
httpBackend.expectGET("static/test-json/devices/device-list.json").respond("Response found!");
httpBackend.flush();
}))
})
});
I am new to Angular Unit testing, can anyone please help me, where I am going wrong..
Two things that jump out at me:
Your angular.module declaration is defining a module, not getting the module. I would encourage you to split that up so that it's a fair bit more clear what your intent is.
angular.module('uspDeviceService', []);
angular.module('uspDeviceService').factory('getDevice', GetDevice);
It likely works as-is, but clarity is important.
What is...service? It's not defined anywhere in your code, and Angular can't find it either, hence the error message. You may be looking to get getDevice instead. Also, name your test variable with respect to what it actually is, so you don't confuse yourself.
// defined above
var getDevice;
// while injecting
getDevice = $injector.get('getDevice');
Supposing that you have an angularjs controller myController defined in myModule. The controller do some action when the api call is success and shows a flash message when api returns success = false. The your controller code would be something like
angular.module('myModule')
.controller( 'myController', function ( $scope,flashService, Api ) {
Api.get_list().$promise.then(function(data){
if(data.success) {
$scope.data = data.response
}
else{
flashService.createFlash(data.message, "danger");
}
});
});
Now to test both success = true and success = false we
describe('myController', function(){
var $rootScope, $httpBackend, controller, flashService;
var apilink = 'http://apilink';
beforeEach(module('myModule'));
beforeEach(inject(function(_$httpBackend_,_$rootScope_, _$controller_, _flashService_) {
$rootScope = _$rootScope_;
$httpBackend = _$httpBackend_;
flashService = _flashService_;
controller = _$controller_("myController", {$scope: $rootScope});
}));
it('init $scope.data when success = true', function(){
$httpBackend.whenGET(apilink)
.respond(
{
success: true,
response: {}
});
$httpBackend.flush();
expect($rootScope.data).toBeDefined();
});
it('show flash when api request failure', function(){
spyOn(flashService, 'createFlash');
$httpBackend.whenGET(apilink)
.respond(
{
success: false
});
$httpBackend.flush();
expect(flashService.createFlash).toHaveBeenCalled();
});
});
You are always going to mock the response because here we are testing the javascript code behaviour and we are not concerned with the Api. You can see when success the data is initialized and when success is false createFlash is called.
As far as test for factory is concerned you can do
describe('Get Product test', function() {
beforeEach(module('uspDeviceService'));
var service, httpBackend, getDevice ;
beforeEach(function () {
inject(function ($injector) {
httpBackend = $injector.get('$httpBackend');
service = $injector.get('service');
getDevice = $injector.get('getDevice');
});
});
describe('get Device List', function () {
it("should return a list of devices", inject(function () {
httpBackend.expectGET("static/test-json/devices/device- list.json").respond("Response found!");
var result = getDevice.getDeviceList();
httpBackend.flush();
expect(result).toEqual('Response found!');
}));
});
});

AngularJS controller unit test with Jasmine

I'm making a unit test for an angular controller with Jasmine but I can't get passed the error
"TypeError: Cannot read property 'running' of undefined".
The full error is posted at the bottom.
Here's the app definition...
var myApp= myApp|| angular.module('myApp', ['ngRoute', 'ngSanitize', 'ui.bootstrap']);
myApp.run(['$http', '$rootScope', 'properties', function($http, $rootScope, properties) {
//...
//Implementation of custom dependency
properties.get().then(function(response) {
$rootScope.propertiesLoaded = true;
myApp.properties = response;
});
//...
}]);
The controller..
myApp.controller('myController', function($scope, users) {
//...
});
The test.js
describe("Test Controllers", function () {
beforeEach(function () {
angular.module("myApp");
//Injection of mocked custom dependency into the myApp.run method
myApp.run(function ($provide) {
$provide.provider('properties', function () {
this.$get = function () {
return "Mock return"
};
});
});
});
describe("myController", function () {
var scope, usrs, createMainController, mockDependency;
beforeEach(function () {
mockDependency = {
current: {
get: function () {
return "Mock return";
}
}
};
angular.module(function ($provide) {
$provide.value('users', mockDependency);
},[]);
inject(function (_$injector_, _$controller_, _$rootScope_, users) {
scope = _$rootScope_.$new();
usrs = _$injector_.get("users");
_$controller_("myController", {
$scope: scope,
users: usrs
});
createMainController = function () {
return _$controller_("myController", {
$scope: scope,
users: usrs
});
};
});
});
describe("This simple test", function () {
it("should pass no matter what", function () {
expect(true).toBe(true);
});
});
});
});
Here's the whole error message...
TypeError: Cannot read property 'running' of undefined
at isSpecRunning (file:///C:/.../angular-mocks.js:1923:73)
at window.inject.angular.mock.inject (file:///C:/.../angular-mocks.js:2087:20)
Next line points to inject function
at Object.<anonymous> (file:///C:/.../mySpec.js:37:13)
at attemptSync (file:///C:/.../jasmine.js:1510:12)
at QueueRunner.run (file:///C:/.../jasmine.js:1498:9)
at QueueRunner.execute (file:///C:/.../jasmine.js:1485:10)
at Spec.Env.queueRunnerFactory (file:///C:/.../jasmine.js:518:35)
at Spec.execute (file:///C:/.../jasmine.js:306:10)
at Object.<anonymous> (file:///C:/.../jasmine.js:1708:37)
at attemptAsync (file:///C:/.../jasmine.js:1520:12)
Here is a related reference to the error that I found which suggests it is an existing problem with Jasmine. However, in this case the problem involved Mocha, which I'm not using.
https://github.com/angular/angular.js/issues/1467
I'm not sure if this will help you, but you could give this a shot, I've had that problem. I'm not very good with AngularJS so if this doesn't work I don't know what to tell you. In your angular-mocks.js find the function isSpecRunning and change it into this:
function isSpecRunning() {
//return currentSpec && (window.mocha || currentSpec.queue.running);
return !!currentSpec;
}
I read something about Jasmine 2.0 (not sure if that's what you're on) not behaving unless you have this line.
They have fixed this issue using the above logic in newer version of angular-mocks.js (v 1.3.15).

How do you mock $rootScope in an angularjs service?

Given i have a service like this.
angular.module('app')
.factory('Session', function Session($rootScope, $cookieStore) {
var user;
if (user = $cookieStore.get('user')) {
$rootScope.currentUser = user;
}
});
and a test
'use strict';
describe('Service: Session', function () {
var Session,
_rootScope,
_cookieStore;
beforeEach(module('app'));
beforeEach(module(function($provide, $injector) {
_rootScope = $injector.get('$rootScope').$new();
_cookieStore = {
get: angular.noop
};
$provide.value('$rootScope', _rootScope);
$provide.value('$cookieStore', _cookieStore);
}));
beforeEach(inject(function(_Session_) {
Session = _Session_;
}));
it('transfers the cookie under user into the currentUser', function() {
spyOn(_cookieStore, 'get').andReturn('user');
inject(function(_Session_) {
Session = _Session_;
});
expect(_rootScope.currentUser).toEqual('user');
});
});
I end up getting
Error: [$injector:unpr] Unknown provider: $rootScope
http://errors.angularjs.org/1.2.6/$injector/unpr?p0=%24rootScope
Can someone explain to me what concept I'm missing? I'm finding unit testing services to be exceedingly difficult.
The trick was to use $injector to explicitly instantiate the service at a specific moment in time. (Thanks for your help #caitp)
'use strict';
describe('Service: Session', function () {
var _cookieStore;
beforeEach(module('rallyApp'));
beforeEach(module(function($provide) {
_cookieStore = {
get: angular.noop
};
$provide.value('$cookieStore', _cookieStore);
}));
it('transfers the cookie under user into the currentUser', function() {
inject(function($rootScope, $injector) {
spyOn(_cookieStore, 'get').andReturn('caitp');
$injector.get('Session');
expect($rootScope.currentUser).toBe('caitp');
});
});
});

Unit testing the AngularJS $window service

I would like to unit test the following AngularJs service:
.factory('httpResponseInterceptor', ['$q', '$location', '$window', 'CONTEXT_PATH', function($q, $location, $window, contextPath){
return {
response : function (response) {
//Will only be called for HTTP up to 300
return response;
},
responseError: function (rejection) {
if(rejection.status === 405 || rejection.status === 401) {
$window.location.href = contextPath + '/signin';
}
return $q.reject(rejection);
}
};
}]);
I have tried with the following suite:
describe('Controllers', function () {
var $scope, ctrl;
beforeEach(module('curriculumModule'));
beforeEach(module('curriculumControllerModule'));
beforeEach(module('curriculumServiceModule'));
beforeEach(module(function($provide) {
$provide.constant('CONTEXT_PATH', 'bignibou'); // override contextPath here
}));
describe('CreateCurriculumCtrl', function () {
var mockBackend, location, _window;
beforeEach(inject(function ($rootScope, $controller, $httpBackend, $location, $window) {
mockBackend = $httpBackend;
location = $location;
_window = $window;
$scope = $rootScope.$new();
ctrl = $controller('CreateCurriculumCtrl', {
$scope: $scope
});
}));
it('should redirect to /signin if 401 or 405', function () {
mockBackend.whenGET('bignibou/utils/findLanguagesByLanguageStartingWith.json?language=fran').respond([{"description":"Français","id":46,"version":0}]);
mockBackend.whenPOST('bignibou/curriculum/new').respond(function(method, url, data, headers){
return [401];
});
$scope.saveCurriculum();
mockBackend.flush();
expect(_window.location.href).toEqual("/bignibou/signin");
});
});
});
However, it fails with the following error message:
PhantomJS 1.9.2 (Linux) Controllers CreateCurriculumCtrl should redirect to /signin if 401 or 405 FAILED
Expected 'http://localhost:9876/context.html' to equal '/bignibou/signin'.
PhantomJS 1.9.2 (Linux) ERROR
Some of your tests did a full page reload!
I am not sure what is going wrong and why. Can anyone please help?
I just want to ensure the $window.location.href is equal to '/bignibou/signin'.
edit 1:
I managed to get it to work as follows (thanks to "dskh"):
beforeEach(module('config', function($provide){
$provide.value('$window', {location:{href:'dummy'}});
}));
You can inject stub dependencies when you load in your module:
angular.mock.module('curriculumModule', function($provide){
$provide.value('$window', {location:{href:'dummy'}});
});
To get this to work for me I had to make a minor adjustment. It would error out and say:
TypeError: 'undefined' is not an object (evaluating '$window.navigator.userAgent')
So I added the navigator.userAgent object to get it to work for me.
$provide.value('$window', {
location:{
href:'dummy'
},
navigator:{
userAgent:{}
}
});
I faced the same problem, and went a step further in my solution. I didn't just want a mock, I wanted to replace $window.location.href with a Jasmine spy for the better ability to track changes made to it. So, I learned from apsiller's example for spying on getters/setters and after creating my mock, I was able to spy on the property I wanted.
First, here's a suite that shows how I mocked $window, with a test to demonstrate that the spy works as expected:
describe("The Thing", function() {
var $window;
beforeEach(function() {
module("app", function ($provide) {
$provide.value("$window", {
//this creates a copy that we can edit later
location: angular.extend({}, window.location)
});
});
inject(function (_$window_) {
$window = _$window_;
});
});
it("should track calls to $window.location.href", function() {
var hrefSpy = spyOnProperty($window.location, 'href', 'set');
console.log($window.location.href);
$window.location.href = "https://www.google.com/";
console.log($window.location.href);
expect(hrefSpy).toHaveBeenCalled();
expect(hrefSpy).toHaveBeenCalledWith("https://www.google.com/");
});
});
As you can see above, the spy is generated by calling the below function: (it works for both get and set)
function spyOnProperty(obj, propertyName, accessType) {
var desc = Object.getOwnPropertyDescriptor(obj, propertyName);
if (desc.hasOwnProperty("value")) {
//property is a value, not a getter/setter - convert it
var value = desc.value;
desc = {
get: function() { return value; },
set: function(input) { value = input; }
}
}
var spy = jasmine.createSpy(propertyName, desc[accessType]).and.callThrough();
desc[accessType] = spy;
Object.defineProperty(obj, propertyName, desc);
return spy;
}
Lastly, here's a fiddle demonstrating this in action. I've tested this against Angular 1.4, and Jasmine 2.3 and 2.4.

Angular injecting $service results in Unknown provider: $serviceProvider

Why when I run this in the karma runner:
describe('Service tests', function () {
var DataServiceMock
var httpBackend;
beforeEach(angular.mock.module('app'));
beforeEach(angular.mock.inject(function( $httpBackend, $service, DataService, $injector){
results in this error
Error: [$injector:unpr] Unknown provider: $serviceProvider <- $service
http://errors.angularjs.org/1.2.1/$injector/unpr?p0=%24serviceProvider%20%3C-%20%24service
at /home/site/angular/angular.js:78:12
Edit 2____________________
I'm trying to mock the DataService for the dataHandlerService
describe('Service', function () {
var DataServiceMock
var httpBackend;
var testUrl = "test/";
beforeEach(angular.mock.module('app'));
beforeEach(angular.mock.inject(function(){
module(function ($provide) {
$provide.value('DataService', DataServiceMock)
})
}));
it('should have', inject(function(DataService) {
expect('DataService').not.toBe(null);
}));
and this error:
Error: Injector already created, can not register a module!
at workFn (/home/me/root/angular/angular-mocks.js:1985:15)
There is no $service. If you want to mock your service then you should do it by using $provide:
beforeEach(function () {
DataServiceMock= {}
DataServiceMock.doSomething = function() {}
module(function ($provide) {
$provide.value('DataService', DataServiceMock)
})
})

Resources