writing jasmine unit test for angular factory - javascript

I am trying to test an angular factory using jasmine and mocha however I keep getting undefined errors.
here is my factory:
(function() {
'use strict';
angular.module('app').factory('appFactory', appFactory);
appFactory.$inject = ['$http','$q'];
function appFactory($http,$q) {
return {
get: get
};
function get(someData) {
//....
}
}
})();
and here is my unit test using jasmine and mocha:
'use strict';
describe('Factory: appFactory', function() {
var http, appFactory;
var $rootScope, $scope;
beforeEach(function() {
angular.module('app');
});
beforeEach(inject(function($injector) {
$rootScope = $injector.get('$rootScope');
$scope = $rootScope.$new();
}));
beforeEach(inject(function() {
var $injector = angular.injector(['ngMock', 'ng', 'app']);
appFactory = $injector.get('appFactory');
}));
it('should be defined', inject( function() {
alert(appFactory);
}));
});
so my alert looks something like:
Object{get: function get(someData) {...}
how do I go about testing the functionality of my factory if this is returning an object?

Related

How to mock objects inside $scope or $window in AngularJs tests using Karma and Jasmine?

I am new to testing AngularJs controllers with Karma and Jasmine.
I'm trying to test this controller:
angular.module('app.dashboard.admin', [])
.controller('AdminCtrl', function (locale, $log, $scope, $window, $state) {
$scope.translation = $window.translation()[locale];
$scope.showAdminBoard = false;
$scope.initModel = {
disableProgress: false,
message: $scope.translation['admin_platform_init'],
error: ''
};
$scope.adminPrivileges = {};
$scope.onGetAdminPrivileges = function () {
return $scope.adinPrivileges;
}
Here's my test code:
'use strict';
describe('dashboard.admin module', function () {
beforeEach(function(){
module('app.dashboard.admin');
});
var auth, scope, ctrl, window;
beforeEach(inject(function ($controller, $rootScope, $window) {
auth = Auth;
scope = $rootScope.$new(); //get a childscope
window = {
translation: $window.translation
};
ctrl = $controller("AdminCtrl", {$scope: scope, $window: window});
}));
describe('Admin Controller', function () {
it('should inject controller', function () {
expect(ctrl).toBeDefined();
});
});
});
However, when I try to execute this test code I get this error:
TypeError: undefined is not an object (evaluating '$scope.translation['admin_platform_init']') (line 11)
views/dashboard.admin/admin.js:11:40
[native code]
instantiate#bower_components/angular/angular.js:4786:61
$controller#bower_components/angular/angular.js:10607:39
bower_components/angular-mocks/angular-mocks.js:2249:23
views/dashboard.admin/admin.spec.js:113:27
invoke#bower_components/angular/angular.js:4771:24
WorkFn#bower_components/angular-mocks/angular-mocks.js:3130:26
loaded#http://localhost:9876/context.js:151:17
inject#bower_components/angular-mocks/angular-mocks.js:3097:28
views/dashboard.admin/admin.spec.js:106:22
global code#views/dashboard.admin/admin.spec.js:3:9
Expected undefined to be defined.
views/dashboard.admin/admin.spec.js:118:37
loaded#http://localhost:9876/context.js:151:17
I have tried to mock the $window object and overriding angular's $window object, but I wasn't successful.
I have checked the dependencies in my karma.conf.js file and they're all there.
I have also checked these questions:
Karma-Jasmine: How to test $translate.use?
jasmine mock window object
but the proposed solutions didn't really help.
Thus, I'm trying to find a way to mock the $scope.translation['admin_platform_init'] object in order to be able to execute my tests.
Can someone please point me in the right direction?
Thank you.
try this instead of $window.translation
window = {
translation: function () {
return {
"admin_platform_init": "This is test message"
};
}
};
I managed to solve my problem by importing the 'app' module.
The test code after the fix looks like this:
'use strict';
describe('dashboard.admin module', function () {
beforeEach(function(){
module('app');
module('app.dashboard.admin');
});
var auth, scope, ctrl, window;
beforeEach(inject(function ($controller, $rootScope, $window) {
auth = Auth;
scope = $rootScope.$new(); //get a childscope
window = {
translation: $window.translation
};
ctrl = $controller("AdminCtrl", {$scope: scope, $window: window});
}));
describe('Admin Controller', function () {
it('should inject controller', function () {
expect(ctrl).toBeDefined();
});
});
});

karma test controller using toBeDefined failed

My test failed because it says my controller is not defined. So strange I think I did everything right.
describe('homeCtrl', function() {
var httpBackend, controller, scope;
beforeEach(module('App'));
beforeEach(inject(function($httpBackend, $controller) {
scope = {};
httpBackend = $httpBackend;
controller = $controller('homeCtrl', { $scope: scope });
}));
it('should exist', function() {
expect(controller).toBeDefined();
});
});
and I have my home.js which is the controller like this
var App = angular.module('App')
App.controller('homeCtrl', function($scope) {
})
The error is Expected undefined to be defined.
Your home.js should have dependencies injected in module, change it as,
var App = angular.module('App',[])
App.controller('homeCtrl', function($scope) {
})

Injecting dependencies into Angular services for testing

I'm trying to do some test driven development of an angular service I'm writing using Jasmine. However, I seem to have stumbled at the first hurdle, and I cannot get my $resource dependency to resolve.
The error I get is
Unknown provider: $resourceProvider <- $resource <- lookupService
My code is as follows
Module:
(function() {
'use strict';
angular
.module('common', ['ngSanitize', 'ngAnimate']);
})();
Service:
(function() {
'use strict';
angular
.module('common')
.service('lookupService', lookupService);
lookupService.$inject = ['$resource', 'api'];
function lookupService($resource, api) {
return {
getLookup: getLookup
};
function getLookup() {
return "something";
}
}
})();
Test:
describe('Service tests',
function () {
var lookupService, mockApi, $httpBackend;
//mocks
beforeEach(function () {
mockApi = { getUri: jasmine.createSpy() };
angular.mock.module('common',
function ($provide) {
$provide.value('api', mockApi);
});
});
//injects
beforeEach(function () {
inject(function ($injector) {
$httpBackend = $injector.get('$httpBackend');
lookupService = $injector.get('lookupService');
});
});
//tests
it('should be able to return something',
inject(function () {
expect(lookupService.getLookup()).toEqual("something");
}));
});//Service tests
The angular-resource.js file is included in my runner file. I'm not sure where I'm going wrong, any help would be appreciated.
Thanks
ngResource must be a dependency:
(function() {
'use strict';
angular
.module('common', ['ngSanitize', 'ngAnimate', 'ngResource']);
})();

AngularJS factory unit testing with dependencies

I am trying to test some AngularJS factories with Jasmine. It works fine for factories that don't have any dependencies. One of my factories uses Angular Material's $mdToast as dependency.
The factory:
(function() {
'use strict';
angular
.module('myModule')
.factory('ToastFactory', ToastFactory);
ToastFactory.$inject = ['$mdToast'];
function ToastFactory($mdToast) {
var service = {
showToast1: showToast1,
showToast2: showToast2
};
return service
function showToast1() {
return $mdToast.show($mdToast.build({
templateUrl: 'path'
}));
}
function showToast2() {
return $mdToast.show($mdToast.build({
templateUrl: 'path'
}));
}
}
})();
And here is one of the working tests for another factory without dependencies.
describe('myFactory', function() {
//Injector Service
var $injector;
//Set Module
beforeEach(function() {
angular.module('myModule');
});
//Inject injector service
beforeEach(inject(function() {
$injector = angular.injector(['myModule']);
}));
describe('SampleTest', function() {
it('should be true', function() {
//Arrange
var factory = $injector.get('myFactory');
//Act
var res = factory.testMethod();
//Assert
expect(res).toBe(true);
});
});
})
I know how to do it for controllers, but not for factories.

Invoking service method in Jasmine

Using Angular and Jasmine I would like to run the service method with some mockup data. Below is the code of my test which uses some working RoomsController trying to run test() method on the RoomsParamsSvc:
describe('Rooms Controller', function() {
var RoomsController,
scope,
location,
httpBackend,
RoomsParamsSvc;
beforeEach(module('rooms', function ($provide, $injector) {
RoomsParamsSvc = function () { //(1a)
return $injector.get('RoomsParamsSvc'); //(1b)
}; //(1c)
$provide.value('RoomsParamsSvc', RoomsParamsSvc); //(1d)
}));
beforeEach(inject(function($controller, $rootScope, $location, $httpBackend, _RoomsParamsSvc_) {
// Set a new global scope
scope = $rootScope.$new();
location = $location;
httpBackend = $httpBackend;
RoomsParamsSvc = _RoomsParamsSvc_;
RoomsController = $controller('RoomsController', {
$scope: scope,
$location: location,
RoomsParamsSvc: RoomsParamsSvc
});
}));
it('should have test as a function', function () {
var t = RoomsParamsSvc.test();
});
});
As far as I understand with the with injector I should be able to use that injected service. Without (1a-1d) I got an error:
Error: [$injector:unpr] Unknown provider: RoomsParamsSvcProvider <-
RoomsParamsSvc
However now it doesn't work, too. I got an error meaning that test() is not a function:
jasmine typeerror 'undefined' is not a function (evaluating 'RoomsParamsSvc.test()')
My service looks like that:
var roomsApp = angular.module('rooms', []);
roomsApp.factory('RoomsParamsSvc', function () {
var factory = {};
factory.test = function ()
{
return '';
}
return factory;
});
Do you have any suggestions?
Lines 1a-1d are not required, as the 'RoomsParamsSvc' is loaded within your 'room' module. But you make a reference to the RoomsController, which is undefined.
beforeEach(module('rooms'));
beforeEach(inject(function($controller, $rootScope, $location, $httpBackend, _RoomsParamsSvc_) {
// Set a new global scope
scope = $rootScope.$new();
location = $location;
httpBackend = $httpBackend;
RoomsParamsSvc = _RoomsParamsSvc_;
RoomsController = $controller(function() {}, {
$scope: scope,
$location: location,
RoomsParamsSvc: RoomsParamsSvc
});
console.log(RoomsParamsSvc);
}));
Plunker

Categories