Trying to navigate the complexities of testing an Angular app has left me feeling bewildered. It seems like there are conflicting recommendations that I'm trying to reconcile. Following John Papa's style guide, I've been using Sidewaffle templates extensively. However, I'm finding a clash between the suggested template and testability aspects.
The style guide advocates for an
activate()
method in your controller to handle the initialization logic. But the general testing guidelines discourage testing private methods. The challenge arises when trying to test the result of the activate() method, where the outcome is passed through
vm.avengers
variable. In his Pluralsight videos, John Papa uses common.activatecontroller() method with
$q.all()
to combine promises for easy function calls during controller activation phase. Consider a scenario where a function doesn't have a result that can be passed through vm, such as a post message to WebApi for user authentication and token setup. Here's an example:
In the following controller, the only business logic involves calling the func1() method within the activate() method, which in turn invokes OAuthenticationService.authenticate(). From a testing perspective, it's crucial to verify if the service was called or not. How can this be tested?
Here is a similar question where one suggestion involves using this keyword like so:
this.activate()
However, a comment highlights that this approach doesn't work with ControllerAs syntax, which is what I'm following.
Creating a mock for the service with spy on authenticate method reveals that it wasn't called, likely because the method is private.
Feeling stuck...
Appreciate any assistance!
Example
(function () {
'use strict';
angular
.module('app')
.controller('controller', controller);
controller.$inject = ['$location'];
function controller($location) {
/* jshint validthis:true */
var vm = this;
vm.title = 'controller';
activate();
function activate() {
func1();
}
function func1() {
OAuthAuthenticateService.authenticate(user).then(function() {
//setting up headers and other stuff, nothing will be part of $scope or vm;
});
}
}
})();
Original code:
(function () {
'use strict';
var controllerId = 'requestAuthorizationController';
angular
.module('myapp')
.controller(controllerId, requestAuthorizationController);
requestAuthorizationController.$inject = ['$rootScope',
'$scope',
'requestAuthorizationService'
'Restangular'];
function requestAuthorizationController($rootScope,
$scope,
requestAuthorizationService
Restangular) {
/* jshint validthis:true */
var vm = this;
//other business logic
activate();
function activate() {
requestAuthorization();
}
function requestAuthorization() {
vm.fired = undefined;
requestAuthorizationService.getDummy();
}
}
})();
Jasmine test:
'use strict';
describe('RequestAuthenticationController Specification', function () {
var RestangularProviderMock,
localStorageServiceProvider,
$httpProvider,
requestAuthorizationController,
requestAuthorizationServiceMock,
$rootScope;
//modules
beforeEach(function() {
angular.module('dilib.layout', []);
angular.module('http-auth-interceptor', []);
});
//providers
beforeEach(function () {
module('dilib', function(RestangularProvider, _localStorageServiceProvider_, _$httpProvider_, $provide) {
RestangularProviderMock = RestangularProvider;
localStorageServiceProvider = _localStorageServiceProvider_;
$httpProvider = _$httpProvider_;
$provide.service('requestAuthorizationService', function() {
this.getDummy = jasmine.createSpy('getDummy').and.callFake(function(num) {
});
});
});
});
//to crank up the providers
beforeEach(inject());
beforeEach(inject(function (_$rootScope_, _$controller_, _requestAuthorizationService_) {
$rootScope = _$rootScope_;
requestAuthorizationController = _$controller_;
requestAuthorizationServiceMock = _requestAuthorizationService_;
}));
describe('requestAuthorization function', function() {
it('RequestAuthorizationService.getDummy() is called', function() {
$rootScope.$digest();
expect(requestAuthorizationServiceMock.getDummy).toHaveBeenCalled();
});
});
});