2

So I am start to write unit test for an AngularJS application I wrote. This application is protected with a login page so that if the username in not logged in, any request to any page except the login page will redirect the login page. This logic is executed from the main modules .run() method since it only needs to run once, when the application starts, however is there a way to test code that is executed from within the main modules .run() method? I ahve the follow test code:

describe('Login Controller', function(){
    'use strict';

    var scope, controller, $httpBackend, $resource, callback;

    beforeEach(module('application'));

    beforeEach(inject(function($injector, $rootScope, $controller, $http, $location, authentication, session) {
        $httpBackend = $injector.get('$httpBackend');
        $httpBackend.expectGET('/api/v1/authentication').respond({status: 'success', data: null});
        $resource = $injector.get('$resource');
        callback = jasmine.createSpy();
        scope = $rootScope.$new();
        controller = new $controller('Login', {
            $scope: scope,
            $http: $http,
            $location: $location,
            authentication: authentication,
            session: session
        });
    }));

    afterEach(function() {
        $httpBackend.verifyrifyNoOutstandingExpectation();
        $httpBackend.verifyNoOutstandingRequest();
    });

    it('should verify all default values for controller', function() {
        expect(scope.username).toEqual('');
        expect(scope.password).toEqual('');
        expect(scope.displayApplicationLoad).toEqual(false);
        expect(angular.isFunction(scope.login)).toEqual(true);
        expect(angular.isFunction(scope.logout)).toEqual(true);
        expect(scope.loggedIn).toEqual(false);
        expect(scope.headerTemplate).toEqual('/templates/core/header.html');
        expect(scope.footerTemplate).toEqual('/templates/core/footer.html');
    });
});

The issue is that the code running inside the main modules .run() method is not taking into account the

$httpBackend.expectGET('/api/v1/authentication').respond({status: 'success', data: null});

line. Should I be placing this logic somewhere else so that I can unit test this code?

2 Answers 2

6

I would move all this code that you want to test into a service, which you inject into your run block. Then you can test this service independently. Also you can then set up modules for testing other stuff that relies on authentication more flexibly.

Sign up to request clarification or add additional context in comments.

2 Comments

could you please elaborate what you mean for "independently"? Should we create new modules ?
If you create a service that does all the work that you are doing in the run block then you can inject this service into either the run block for the application or into a unit test for testing. You don't need to create a new module.
0

I think I found a way to test a module's run method. It's a little hacky but it gets the job done. Here's my solution:

describe( 'my module', function() {

  var runBlocks;

  beforeEach( function() {
     var myModule = angular.module( 'modules.flow' );

     runBlocks = myModule._runBlocks;
     myModule._runBlocks = [];

     module( 'myModule' );
  } );

  afterEach( function() {
     angular.module( 'modules.flow' )._runBlocks = runBlocks;
  } );

  describe( 'when loaded', function() {

     beforeEach( inject( function( $injector ) {

        // Here you could e.g. configure $httpBackend

        for( var i = 0; i < runBlocks.length; ++i ) {
           $injector.invoke( runBlocks[i] );
        }
     } ) );

     // Tests ...

  } );

} );

First I make a copy of all run blocks defined for the module and delete the internal list of run blocks. Then it is possible to do the setup necessary for the run blocks to succeed and afterwards let the injector invoke the functions.

Nevertheless, if there is any chance to extract the code within the run blocks into appropriate services, you should prefer that way.

Update: Added missing afterEach method

Update 2: Fixed call to angular.module

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.