I followed this post (http://gonehybrid.com/how-to-write-automated-tests-for-your-ionic-app-part-2/) to create a simple unit test using Karma & Jasmine for a Ionic controller, but i keep getting undefined errors while the stated objects have been defined. I’m i missing something obvious? By the way, i’m able to run referenced tests from the blog above successfully which makes me think i’m missing something in mine.
Errors are as follows:
- TypeError: undefined is not an object (evaluating ‘authMock.login’) in /Users/projects/app/tests/unit-tests/login.controller.tests.js (line 65)
- TypeError: undefined is not an object (evaluating ‘deferredLogin.resolve’) in /Users/projects/app/tests/unit-tests/login.controller.tests.js (line 71)
- TypeError: undefined is not an object (evaluating ‘deferredLogin.reject’) in /Users/projects/app/tests/unit-tests/login.controller.tests.js (line 79)
Here’s the controller:
angular.module('app').controller('LoginCtrl', function($scope, $state, $ionicPopup, $auth) {
$scope.loginData = {};
$scope.user = {
email: '',
password: ''
};
$scope.doLogin = function(data) {
$auth.login(data).then(function(authenticated) {
$state.go('app.tabs.customer', {}, {reload: true});
}, function(err) {
var alertPopup = $ionicPopup.alert({
title: 'Login failed!',
template: 'Please check your credentials!'
});
});
};
});
Here’s the test:
describe('LoginCtrl', function() {
var controller,
deferredLogin,
$scope,
authMock,
stateMock,
ionicPopupMock;
// load the module for our app
beforeEach(angular.mock.module('app'));
// disable template caching
beforeEach(angular.mock.module(function($provide, $urlRouterProvider) {
$provide.value('$ionicTemplateCache', function(){} );
$urlRouterProvider.deferIntercept();
}));
// instantiate the controller and mocks for every test
beforeEach(angular.mock.inject(function($controller, $q, $rootScope) {
deferredLogin = $q.defer();
$scope = $rootScope.$new();
// mock dinnerService
authMock = {
login: jasmine.createSpy('login spy')
.and.returnValue(deferredLogin.promise)
};
// mock $state
stateMock = jasmine.createSpyObj('$state spy', ['go']);
// mock $ionicPopup
ionicPopupMock = jasmine.createSpyObj('$ionicPopup spy', ['alert']);
// instantiate LoginController
controller = $controller('LoginCtrl', {
'$scope': $scope,
'$state': stateMock,
'$ionicPopup': ionicPopupMock,
'$auth': authMock
});
}));
describe('#doLogin', function() {
// call doLogin on the controller for every test
beforeEach(inject(function(_$rootScope_) {
$rootScope = _$rootScope_;
var user = {
email: 'test@yahoo.com',
password: 'test'
};
$scope.doLogin(user);
}));
it('should call login on $auth Service', function() {
expect(authMock.login).toHaveBeenCalledWith(user);
});
describe('when the login is executed,', function() {
it('if successful, should change state to app.tabs.customer', function() {
deferredLogin.resolve();
$rootScope.$digest();
expect(stateMock.go).toHaveBeenCalledWith('app.tabs.customer');
});
it('if unsuccessful, should show a popup', function() {
deferredLogin.reject();
$rootScope.$digest();
expect(ionicPopupMock.alert).toHaveBeenCalled();
});
});
})
});
Here’s my Karma config:
files: [
'../www/lib/ionic/js/ionic.bundle.js',
'../www/lib/angular-mocks/angular-mocks.js',
'../www/js/*.js',
'../www/js/**/*.js',
'unit-tests/**/*.js'
],