I am trying to test a rootscope http request in my case
I have something like
mainCont file
$rootScope.testLoad = $http.get('/api/testapi/product');
TestCont file
$rootScope.testLoad.success(function(product){
console.log(product)
})
Test file
describe('test', function () {
var $httpBackend, $rootScope, scope, mainCont, testCont;
beforeEach(module('myApp'));
beforeEach(inject(function (_$controller_, _$httpBackend_, _$rootScope_) {
scope = _$rootScope_.$new();
$rootScope = _$rootScope_;
$httpBackend = _$httpBackend_;
testCont = _$controller_('testCont', {
$scope: scope
});
mainContr = _$controller_('mainCont', {
$scope: scope
});
}));
describe('test http request', function() {
it('should check if the api is called', function() {
$httpBackend.expectGET('/api/testapi/product').respond(200);
//I am not sure how to test the call in testCont file.
})
})
});
I am not sure how to test the call in the testCont because when I run the test,
I got an error saying
TypeError: 'undefined' is not an object (evaluating '$rootScope.testLoad.success')
Can anyone help me to fix this issue? Thanks a lot!
You've defined testLoad as a function, so you need to call it by adding parentheses. Change your code to
$rootScope.testLoad().success(function(product){
console.log(product)
})
Related
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();
});
});
});
I want to unit test my controller. I started with basic test assertions of expect API. But I am facing challenge in mocking scope methods inside a conditional check. I am getting an undefined error since it is not available under scope, only the global logout() method is available.
I tried mocking the localStorageService using spyOn as true to satisfy the condition, but that's still of no help. Any solution will be of great help to get me kickstarted.
Controller:
angular.module('app').controller('sampleCtrl',
function($scope, $state, $http, $rootScope, localStorageService) {
if (!(localStorageService.get('isAuthenticated'))) {
$state.go('home');
}
if (localStorageService.get('isAuthenticated') === true) {
//http post calls made here to perform certain operation on page load
$scope.someMethod = function(){
//do something
}
}
$scope.logOut = function() {
localStorageService.set('property', '');
localStorageService.set('isAuthenticated', false);
$state.go('home');
};
});
Karma:
'use strict';
describe('Controller: sampleCtrl', function() {
/** to load the controller's module */
beforeEach(module('app'));
var sampleCtrl,scope,httpBackend,deferred,rootScope;
beforeEach(inject(function ($controller,_$rootScope_,$httpBackend,$q) {
var store = {};
scope= _$rootScope_.$new(); // creates a new child scope of $rootScope for each test case
rootScope = _$rootScope_;
localStorageService = _localStorageService_;
httpBackend = $httpBackend;
httpBackend.whenGET(/\.html$/).respond('');
spyOn(localStorageService, 'set').and.callFake(function (key,val) {
store[key]=val;
});
spyOn(localStorageService, 'get').and.callFake(function(key) {
return store[key];
});
sampleCtrl = $controller('sampleCtrl',{
_$rootScope_:rootScope,
$scope:scope,
$httpBackend:httpBackend,
_localStorageService_:localStorageService
// add mocks here
});
localStorageService.set('isAuthenticated',true);
}));
/**ensures $httpBackend doesn’t have any outstanding expectations or requests after each test*/
afterEach(function() {
httpBackend.verifyNoOutstandingExpectation();
httpBackend.verifyNoOutstandingRequest();
});
it('sampleCtrl to be defined:',function(){
httpBackend.flush();
expect(sampleCtrl).toBeDefined();
});
// failing test case - scope.someMethod not available in scope
it('is to ensure only authenticated user can access the state methods',function(){
localStorageService.get('isAuthenticated');
httpBackend.flush();
expect(scope.someMethod).toBeDefined();
});
});
I've managed to get it work.
The problem was that localStorageService did not have isAuthenticated set to true on starting the controller. Place setting it to true before calling the controller.
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
I am trying to write units test for my app and I have the following issue
In my controller, I have something like
$scope.test1 = function() {
productFactory.getName()
.then(function(products){
$scope.result = products;
})
}
productFactory
angular.module('myApp').factory('productFactory', function($http) {
var factoryObj = {};
factoryObj.getName = function() {
return http.get(url)
}
return factoryObj
})
In my unit test file
describe('test here', function () {
var testCtrl, scope, httpBackend, mockFactory;
beforeEach(module('myApp', function($provide){
$provide.value('productFactory', mockFactory);
}));
// Initialize the controller and a mock scope
beforeEach(inject(function (_$controller_, _$rootScope_, _$httpBackend_, _productFactory_) {
scope = _$rootScope_.$new();
httpBackend = _$httpBackend_;
mockFactory = _productFactory_;
testCtrl = _$controller_('testCtrl', {
$scope: scope
});
it('should get product name', function() {
scope.test1();
//I am not sure how to test the results
});
}));
When I run karma test, it gives me
TypeError: 'undefined' is not an object (evaluating 'productFactory.getName()')
I am not sure how to test the http result and fix the error. Can anyone help me about it? Thanks a lot!
First of all, you don't need to worry about using $provide:
beforeEach(module('myApp'));
1. Without $httpBackend (mock out the service completely)
Then, productFactory will be passed into your controller, but you want to spyOn the getName():
// Initialize the controller and a mock scope
beforeEach(inject(function (_$controller_, _$rootScope_, _$httpBackend_, _productFactory_) {
scope = _$rootScope_.$new();
httpBackend = _$httpBackend_;
mockFactory = _productFactory_;
// add spy for the method, wrap with $q.when so it returns a promise
spyOn(mockFactory, 'getName').and.returnValue($q.when('Pizza!'));
testCtrl = _$controller_('testCtrl', {
$scope: scope,
productFactory: mockFactory // pass in here
});
Then, you've got to cause a $digest cycle, so that the promise will call through:
it('should get product name', function() {
scope.test1();
// hit the $digest
scope.$apply();
// expectation
expect(scope.result).toBe('Pizza!')
});
2. With $httpBackend
// Initialize the controller and a mock scope
beforeEach(inject(function (_$controller_, _$rootScope_, _$httpBackend_) {
scope = _$rootScope_.$new();
httpBackend = _$httpBackend_;
// set up httpBackent
httpBackend.when('GET', '/products')
.respond([{ name: 'Pizza!'}, {name: 'Sandwich'}]);
testCtrl = _$controller_('testCtrl', {
$scope: scope
});
We don't need to mock the factory in this case at all. Then, we just need to flush $httpBackend when we want the http call to return:
it('should get product name', function() {
scope.test1();
// hit the $digest with flush
httpBackend.flush();
// expectation
expect(scope.result.length).toBe(2)
});
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 ...