AngularJS set scope variables in Karma test - javascript

I'm trying to set up Karma unit tests and in my test I want to set a scope variable so I can run the test. I get the error Cannot set property 'expandedSeries' of undefined.
Below is my code. What am I doing wrong?
describe('FormController', function () {
beforeEach(module('userFormApp'));
var $controller;
var $rootScope;
beforeEach(inject(function (_$controller_, _$rootScope_) {
$controller = _$controller_;
$rootScope = _$rootScope_;
}));
describe('$scope.getImageSrc', function () {
var $scope, controller;
beforeEach(function () {
$scope = $rootScope.$new();
controller = $controller('FormController', { $scope: $scope});
});
$scope.expandedSeries = 1;
it('sets variables ', function () {
expect($scope).toBeDefined();
expect($scope.expandedSeries).toBeDefined();
expect($scope.expandedSeries).toEqual(1);
});
});

Instantiate the variable in before each so that the test cases can get it when they start.
describe('$scope.getImageSrc', function () {
var $scope, controller;
beforeEach(function () {
$scope = $rootScope.$new();
controller = $controller('FormController', { $scope: $scope});
$scope.expandedSeries = 1;
});
it('sets variables ', function () {
expect($scope).toBeDefined();
expect($scope.expandedSeries).toBeDefined();
expect($scope.expandedSeries).toEqual(1);
});
});

Related

scope method in AngularJS directive is not a function, when unit testing

I have this Mocha test:
'use strict';
///////////////////////////////////
describe('all admin page directives', function () {
let scope, $compile, element, tmp;
beforeEach(module('app'));
beforeEach(module('templates'));
afterEach(function () {
scope.$destroy();
});
describe('category', function () {
beforeEach(inject(function ($injector) {
$compile = $injector.get('$compile');
var $rootScope = $injector.get('$rootScope');
scope = $rootScope.$new();
scope.rightSidebarData = {};
$compile('<create-category right-sidebar-data="rightSidebarData"></create-category>')(scope);
return scope.$digest();
}));
it('should do something', function () {
scope.updateModel(); // <<<<<< ERROR HERE
});
});
});
here is my directive:
/* globals angular */
angular.module('app').directive('createCategory',
['UserService', 'AssignmentService', 'NotificationService', 'USER', 'UserInfoService', 'AlertService', '$window',
function (UserService, AssignmentService, NotificationService, USER, UserInfoService, AlertService, $window) {
return {
scope: {
rightSidebarData: '=',
},
restrict: 'EA',
templateUrl: "pages/admin/views/templates/category/create-category.html",
link: function ($scope, el, attrs) {
$scope.rightSidebarData.setOrReset = function () {
$scope.setOrReset();
};
},
controller: function ($scope, FUNCTIONAL_TEAM_ENUM, CATEGORY_ENUM, CategoryService) {
const rsd = $scope.rsd = $scope.rightSidebarData;
$scope.setOrReset = function () {...};
$scope.updateModel = function () {...};
$scope.saveModel = function () {...};
},
};
}
]);
I am getting this error:
TypeError: scope.updateModel is not a function
Does anyone know what I need to do in my test to fix this?
Also, how do I know if I need to use $rootScope.$new() or if I should be passing the parent controller's scope?
I had to add another preprocessor in my karma config file:
preprocessors: {
'./public/pages/**/views/**/*.html':['ng-html2js'], // this
},
and then using the following, it worked:
'use strict';
describe('all admin page directives', function () {
let scope, el, tmp, isoScope;
beforeEach(module('app'));
beforeEach(module('ngMockE2E'));
beforeEach(module('templates'));
afterEach(function () {
scope.$destroy();
});
describe('category', function () {
beforeEach(inject(function ($injector) {
const $compile = $injector.get('$compile');
const $rootScope = $injector.get('$rootScope');
const $templateCache = $injector.get('$templateCache');
console.log('create category template =>', $templateCache.get('pages/admin/views/templates/category/create-category.html'));
scope = $rootScope.$new();
scope.rightSidebarData = {};
scope.rightSidebarData.model = {};
let element = angular.element(`<create-category right-sidebar-data="rightSidebarData"></create-category>`);
el = $compile(element)(scope);
$rootScope.$digest();
scope.$digest();
el.isolateScope().setOrReset();
}));
it('should do something', function () {
el.isolateScope().updateModel();
});
});
});

Unittest of AngularJS Controller with Jasmine and Karma "Cannot read property 'then' of undefined

I am trying to unit-test an angularjs controller and get this error message when running Karma:
Cannot read property 'then' of undefined
What am I doing wrong?
Sorry, it's my first time testing something.
Controller:
angular
.module('my')
.controller('MyCtrl', MyController);
MyController.$inject = ['$scope', 'myFactory'];
function MyController($scope,myFactory) {
$scope.thingy = {};
//[..]
function getThingys() {
myFactory.getThingys(function () {}).then(function (data) {
//SUCCESS
$scope.thingy = data;
});
}
}
Test:
var scope;
var controller;
var mockedMyFactory;
beforeEach(module('my'));
beforeEach(module('my', function ($provide) {
mockedMyFactory = {
getThingys: jasmine.createSpy()
};
$provide.value('myFactory', mockedMyFactory);
}));
beforeEach(inject(function ($controller, $rootScope, myFactory) {
scope = $rootScope.$new();
controller = $controller('MyCtrl', {
$scope: scope, myFactory
});
}));
describe('this', function () {
it('is a dummy spec', function () {
expect(2 + 2).toEqual(4);
});
});
To mock the service:
var $httpBackend;
var myFactory;
beforeEach(angular.mock.inject(function ($injector) {
// Set up the mock http service responses
$httpBackend = $injector.get('$httpBackend');
// backend definition common for all tests
myFactory= $injector.get('myFactory');
$httpBackend.when('GET', 'url for call').respond({mock data});
}
afterEach(function () {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});

Ionic unit test in controller, spyOn not passing

It's a very simple test.. and it's not passing.. If someone can throw some light into this :)
This is the controller code (part of it) that needs to be tested
AppCtrl
$scope.requestAuthorization = function() { requestAuthorization(); };
if ($stateParams.requestAuthorization === true) {
console.log('$stateParams.requestAuthorization');
$scope.requestAuthorization();
}
function requestAuthorization() {
console.log('requestAuthorization()');
// more code here..
}
Test
describe('AppCtrl', function() {
var AppCtrl, $rootScope, $scope, $stateParams;
beforeEach(module('myapp'));
// disable ionic cache to avoid GET errors
beforeEach(module(function($provide, $urlRouterProvider) {
$provide.value('$ionicTemplateCache', function() {});
$urlRouterProvider.deferIntercept();
}));
beforeEach(inject(function($controller, _$rootScope_, _$injector_, _$stateParams_) {
$rootScope = _$rootScope_;
$scope = $rootScope.$new();
$stateParams = _$stateParams_;
AppCtrl = $controller('AppCtrl',{
$scope: $scope
});
spyOn($scope, 'requestAuthorization');
$stateParams.requestAuthorization = true;
}));
it('$stateParams.requestAuthorization should be defined', function() {
expect($stateParams.requestAuthorization).toBeDefined();
});
it('$scope.requestAuthorization should be defined', function() {
expect($scope.requestAuthorization).toBeDefined();
});
// this test is not passing..
it('should call requestAuthorization', function() {
expect($scope.requestAuthorization).toHaveBeenCalled();
});
});
The function is actually being called, I can see the console.log in the console, but it's not passing.
Easy tests, all passing.. except the last one..
Thanks for your time :)
NOTE: There is a $stateParams.requestAuthorization, and a $scope.requestAuthorization. First one is boolean, the other a function, the function is not passing.
In your beforeEach block, define the $stateParams before instanciate the Controller.
beforeEach(inject(function($controller, _$rootScope_, _$injector_, _$stateParams_) {
$rootScope = _$rootScope_;
$scope = $rootScope.$new();
$stateParams = _$stateParams_;
$stateParams.requestAuthorization = true;
AppCtrl = $controller('AppCtrl',{
$scope: $scope,
$stateParams: $stateParams
});
spyOn($scope, 'requestAuthorization');
}));

Jasmine controller testing, expected spy to have been called

I have a method defined in AngularJS controller which is called on initialization. I want to test it using Jasmine ("jasmine-core": "^2.3.4", "karma": "^0.12.37"). I follow some tutorials on the Internet and StackOverflow questions, but I cannot find the right answer. Please take a look at this code:
Controller usersAddUserController:
(function () {
'use strict';
angular.module('app.users.addUser')
.controller('usersAddUserController', ['$scope', 'usersAddUserService', function ($scope, usersAddUserService) {
usersAddUserService.getCountryPhoneCodes().then(function (phoneCodes) {
$scope.phoneCodes = phoneCodes;
});
}]);
}());
Jasmine test:
(function () {
'use strict';
describe('usersAddUserControllerUnitTest', function () {
var scope, deferred, objectUnderTest, mockedAddUserService;
beforeEach(module('app'));
beforeEach(inject(function ($rootScope, $q, $controller) {
scope = $rootScope.$new();
function emptyPromise() {
deferred = $q.defer();
return deferred.promise;
}
mockedAddUserService = {
getCountryPhoneCodes: emptyPromise
};
objectUnderTest = $controller('usersAddUserController', {
$scope: scope,
usersAddUserService: mockedAddUserService
});
}));
it('should call getCountryPhoneCodes method on init', function () {
//when
spyOn(mockedAddUserService, 'getCountryPhoneCodes').and.callThrough();
deferred.resolve();
scope.$root.$digest();
//then
expect(mockedAddUserService.getCountryPhoneCodes).toHaveBeenCalled();
});
});
}());
After running the tests, the error message is:
PhantomJS 1.9.8 (Windows 7 0.0.0) usersAddUserControllerUnitTest should call getCountryPhoneCodes method on init FAILED
Expected spy getCountryPhoneCodes to have been called.
I obviously missing something, but I cannot figure out what it is. Any help will be appreciated.
You are spying on the mock after it has been passed into the instantiated controller.
Try this:
describe('usersAddUserControllerUnitTest', function () {
var scope, deferred, objectUnderTest, mockedAddUserService, $controller;
beforeEach(module('app'));
beforeEach(inject(function ($rootScope, $q, _$controller_) {
scope = $rootScope.$new();
function emptyPromise() {
deferred = $q.defer();
return deferred.promise;
}
mockedAddUserService = {
getCountryPhoneCodes: emptyPromise
};
$controller = _$controller_;
}));
function makeController() {
objectUnderTest = $controller('usersAddUserController', {
$scope: scope,
usersAddUserService: mockedAddUserService
});
}
it('should call getCountryPhoneCodes method on init', function () {
//when
spyOn(mockedAddUserService, 'getCountryPhoneCodes').and.callThrough();
makeController();
deferred.resolve();
scope.$root.$digest();
//then
expect(mockedAddUserService.getCountryPhoneCodes).toHaveBeenCalled();
});
});
EDIT Thanks #juunas for noticing the bug in my solution
You can provide the mock like this:
mockedAddUserService = {
getCountryPhoneCodes: emptyPromise
};
beforeEach(function () {
module(function ($provide) {
$provide.value('usersAddUserService', mockedAddUserService);
});
});
EDIT:
The code should look (as i cannot test it) like this:
(function () {
'use strict';
describe('usersAddUserControllerUnitTest', function () {
beforeEach(module('app'));
var emptyPromise = function() {
var deferred = $q.defer();
return deferred.promise;
}
var mockedAddUserService = {
getCountryPhoneCodes: emptyPromise
};
beforeEach(function () {
module(function ($provide) {
$provide.value('usersAddUserService', mockedAddUserService);
});
});
var scope;
beforeEach(inject(function ($rootScope, $q, $controller) {
scope = $rootScope.$new();
$controller('usersAddUserController', {
$scope: scope
});
}));
it('should call getCountryPhoneCodes method on init', function () {
spyOn(mockedAddUserService, 'getCountryPhoneCodes').and.callThrough();
scope.$root.$digest();
expect(mockedAddUserService.getCountryPhoneCodes).toHaveBeenCalled();
});
});
}());

How to test scope values after service call http.get

I am trying to write a unit test to test that tests a factory that performs a http.get and then tests the scope bindings.
The factory is called within my controller.
Here's a plunker showing my http.get: http://plnkr.co/edit/VqUSeTiEj3MP37tAXKad?p=preview
Ctrl:
app.controller('MainCtrl', function($scope, $http, factoryGetJSONFile) {
$scope.name = 'World';
factoryGetJSONFile.getMyData(function(data) {
$scope.Addresses = data.Addresses.AddressList;
$scope.People = data.Names.People;
$scope.Country = data.Country;
});
});
Test:
describe('with httpBackend', function () {
var app;
beforeEach(function () {
app = angular.mock.module('plunker')
});
describe('MyCtrl', function () {
var scope, ctrl, theService, httpMock;
beforeEach(inject(function ($controller, $rootScope, factoryGetJSONFile, $httpBackend) {
httpMock = $httpBackend;
scope = $rootScope.$new();
ctrl = $controller('MyCtrl', {
$scope: scope,
factoryGetJSONFile: factoryGetJSONFile,
$httpBackend: httpMock
});
}));
it("should make a GET call to data.json", function () {
console.log("********** SERVICE ***********");
httpMock.expectGET("data.json?").respond(data);
console.log(data.Addresses);
console.log(data.Names);
console.log(data.Country);
//expect(factoryGetJSONFile.getMyData()).toBeDefined();
httpMock.flush();
});
})
});
The test for the http.get seems ok, but when i try logging the reponse (data), an error occurs.
UPDATE:
When i try to log the call via:
console.log(httpMock.expectGET("data.json?").respond(data));
Undefined is displayed.

Categories

Resources