Test Case File
describe('homeController', function() {
beforeEach(module('moduleInjectionApp'));
var $controller;
var $rootScope;
beforeEach(inject(function(_$controller_, _$rootScope_) {
$controller = _$controller_('homeController', {'$scope': scope});
$rootScope = _$rootScope_;
}));
describe('$scope.ID', function() {
it('Check the scope object', function() {
var $scope = {};
expect($scope.ID).toEqual(5);
});
});
});
Controller File
angular.module('moduleInjectionApp').controller('homeController', homeController)
homeController.$inject = ["$scope", "$rootScope", "$location"];
function homeController($scope, $rootScope, $location) {
console.log("entered homeController")
$scope.ID = 5;
$rootScope.loginObj = JSON.parse(localStorage.getItem('login_data'));
}
Error
Error: Expected undefined to equal 5.
at <Jasmine>
at UserContext.<anonymous> (WebContent/test/home/homeSpec.js:14:31)
at <Jasmine>
Chrome 75.0.3770 (Windows 10.0.0): Executed 1 of 1 (1 FAILED) (0.036 secs / 0.012 secs)
TOTAL: 1 FAILED, 0 SUCCESS
Try
describe('homeController', function() {
beforeEach(module('moduleInjectionApp'));
var $controller;
beforeEach(inject(function(_$controller_){
$controller = _$controller_;
}));
describe('$scope.ID', function() {
it('Check the scope object', function() {
var $scope = {};
var controller = $controller('homeController', { $scope: $scope });
expect($scope.ID).toEqual(5);
});
});
});
When you declare var $scope = {};, you will always get $scope.ID as undefined. You need to do
var $scope = { ID: 5}
Anyways, in unit test, you dont create some values and then expect assertions on it. You validate the values which are already defined or have been modified. Here you were trying to declare and then putting expect (which will always pass)
Related
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);
});
});
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');
}));
I am writing my first Angular test, in Jasmine, and I cannot seem to get a promise to digest in a mock service.
Here is my controller (which is being tested) and the resource it uses:
'use strict';
angular.module('myApp.login', [
'ngCookies',
'ngResource'
])
/*Controllers*/
.controller('login', ['$scope', '$rootScope', '$cookies', 'LoginService', function ($scope, $rootScope, $cookies, LoginService) {
$scope.user = {};
$scope.user.username = "";
$scope.user.password = "";
var loginError = function () {
console.log("failure logging in")
};
var loginSuccess = function (result) {
$cookies.put('authToken', result.token);
$rootScope.loggedIn = true;
};
$scope.login = function () {
var credentials = {username: $scope.user.username, password: $scope.user.password};
var tokenPromise = LoginService.authenticate(credentials);
console.log(tokenPromise);
tokenPromise.$promise.then(loginSuccess, loginError);
}
}])
/*Resources*/
.factory('LoginService', ['$resource', 'apiUrl', function ($resource, apiUrl) {
return $resource(
apiUrl + 'auth/token/',
{},
{
authenticate: {
method: "POST"
}
}
)
}]);
Below is the current version of the test.
describe('myApp.login', function () {
var createController, scope, deferred, LoginService;
var successToken = {'token': 'tokenGoesHere'}
beforeEach(inject(function($rootScope, $controller, $injector, $q, $timeout) {
var cookies = $injector.get('$cookies');
scope = $rootScope.$new();
LoginService = { authenticate: function(user) {
deferred = $q.defer();
$timeout(function(){
deferred.resolve(successToken);
$rootScope.$apply();
$rootScope.$digest();
}, 1000);
$timeout.flush();
return deferred.promise;
}};
return $controller('login', {
'$scope': scope,
'$cookies': cookies,
'LoginService': LoginService
});
};
}));
it('Should set cookie with returned JWT', function() {
var controller = new createController();
scope.user.username = 'username';
scope.user.password = 'password';
scope.login();
});
});
I've tried a $timeout, setTimeout, spyOn, and a few others, but nothing I try returns the promise in the state that the controller expects, and I end up getting the following stacktrace:
PhantomJS 1.9.8 (Linux 0.0.0) myApp.login Should set cookie with returned JWT FAILED
TypeError: 'undefined' is not an object (evaluating 'tokenPromise.$promise.then')
at /home/anton/git/persist-ng/app/login/login.js:53
at /home/anton/git/persist-ng/app/login/login_test.js:42
PhantomJS 1.9.8 (Linux 0.0.0): Executed 1 of 1 (1 FAILED) ERROR (0.041 secs / 0.007 secs)
Any help is appreciated, even if the issue actually lives in the code itself, not the test.
THE SITUATION:
In my Ionic app I am testing the correct opening of a modal.
I have made several attempts, but i am getting the following error:
TypeError: Cannot read property 'then' of undefined
THE FUNCTION:
$scope.open_register_modal = function()
{
$ionicModal.fromTemplateUrl('templates/project_register.html', {
scope: $scope
}).then(function(modal) {
$scope.modal_register = modal;
$scope.modal_register.show();
});
};
THE TEST:
describe('App tests', function() {
beforeEach(module('my_app.controllers'));
beforeEach(inject(function(_$controller_, _$rootScope_)
{
$controller = _$controller_;
$rootScope = _$rootScope_;
$scope = _$rootScope_.$new();
$ionicModal =
{
fromTemplateUrl: jasmine.createSpy('$ionicModal.fromTemplateUrl'),
then : function(modal){} // <--- attempt
};
var controller = $controller('MainCtrl', { $scope: $scope, $rootScope: $rootScope, $ionicModal: $ionicModal });
}));
describe('Modal tests', function()
{
it('should open register modal', function()
{
$scope.open_register_modal();
expect($ionicModal).toHaveBeenCalled();
});
});
});
ATTEMPTS:
These are some of the attempts to initialize $ionicModal:
1.
$ionicModal =
{
fromTemplateUrl: jasmine.createSpy('$ionicModal.fromTemplateUrl'),
then : function(modal){}
};
2.
$ionicModal =
{
fromTemplateUrl: jasmine.createSpy('$ionicModal.fromTemplateUrl'),
then: jasmine.createSpy('$ionicModal.then')
};
3.
$ionicModal =
{
fromTemplateUrl: jasmine.createSpy('$ionicModal.fromTemplateUrl'),
then: jasmine.createSpy('$ionicModal.fromTemplateUrl.then')
};
4.
$ionicModal = jasmine.createSpyObj('$ionicModal', ['show', 'close','fromTemplateUrl']);
But they all give the same error:
TypeError: Cannot read property 'then' of undefined
THE QUESTION:
How can i pass the .then method inside the test?
How can i properly test ionicModal?
I don't know anything about ionic, but I think your mistake is expecting that the method then is part of it. The code
$ionicModal.fromTemplateUrl('templates/project_register.html', {
scope: $scope
}).then(function(modal) {
$scope.modal_register = modal;
$scope.modal_register.show();
});
can be refactor to:
var temp=$ionicModal.fromTemplateUrl(
'templates/project_register.html',
{scope: $scope});
temp.then(function(modal) {
$scope.modal_register = modal;
$scope.modal_register.show();
});
so the method then is part of the object returned by the call to fromTemplateUrl
A solution could be something like:
function fakeTemplate() {
return { then:function(){}}
}
$ionicModal = {
fromTemplateUrl: jasmine.createSpy('$ionicModal.fromTemplateUrl').and.callFake(fakeTemplate)
};
i try to test an angular controller but he returns a promise and i cant really resolve it...what's wrong with my code?
the Angular Controller:
kpi.AboutController = function ($scope, Version) {
function loadVersion() {
//$scope.version = Version.getVersion();
$scope.version = '1.1.0';
}
loadVersion();
};
and the jasmine test:
describe('dashboard: AboutController', function() {
beforeEach(module('dashboard'));
var $controller;
beforeEach(inject(function(_$controller_){
// The injector unwraps the underscores (_) from around the parameter names when matching
$controller = _$controller_;
}));
it('testing the version number', function() {
var $scope = {};
var controller = $controller('AboutController', { $scope: $scope });
var version = 0;
console.log($scope.version);
expect($scope.version).toContain("1.");
});
});
this is working, but when i change the line $scope.version = '1.1.0'; to $scope.version = Version.getVersion(); i receive a promise and i can not rly check it....i tried to resolve it with "then()" function via $scope.version.then(...)but that did not work...what to do?
edit:
the following error occures:
Expected e({ $promise: Object({ $$state: Object({ status: 0 }) }), $resolved: false }) to contain '1.'.
at Object.<anonymous>
and the Service:
kpi.VersionFactory = function ($resource, appConfig) {
var Version = $resource(thePath, {}, {
"getVersion": {
method: "GET",
url: thePath,
isArray: false
}
});
return Version;
};
you need to pass a callback into your test case .
kpi.AboutKPIController = function ($scope, Version) {
$scope.loadVersion= function () {
Version.getVersion().then(function(res){
$scope.version = res.data;
})
}
$scope.loadVersion();
};
describe('dashboard: AboutKPIController', function() {
beforeEach(module('dashboard'));
var $controller;
beforeEach(inject(function(_$controller_){
// The injector unwraps the underscores (_) from around the parameter names when matching
$controller = _$controller_;
}));
it('testing the version number', function(done) {
var $scope = {};
var controller = $controller('AboutKPIController', { $scope: $scope });
var version = 0;
console.log($scope.version);
$scope.loadVersion().then(function(res)){
//can test here
expect($scope.version).toContain("1.");
done();
});
});
});
I expect Version.getVersion(); returns a promise. Your controller implemnentation should look like
function loadVersion() {
Version.getVersion().then(function(version) {
$scope.version = version;
});
}
In your test code use $scope.$apply to resolve promises before you perform except.
beforeEach(inject(function(_$controller_, _$rootScope_){
$controller = _$controller_;
$rootScope = _$rootScope_;
}));
it('testing the version number', function() {
var $scope = $rootScope.$new();
var controller = $controller('AboutKPIController', { $scope: $scope });
controller.loadVersion();
$scope.$apply();
expect($scope.version).toContain("1.");
});