Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I test a .run in AngularJS?

myApp.run([
  '$rootScope', 'userService', function($rootScope, userService) {
    return userService.isAuthenticated().then(function(response) {
      if (response.data.authenticated) {
        return $rootScope.$broadcast('login', response.data);
      } else {
        return userService.logout();
      }
    });
  }
]);

That's my code that I have in an init.js file. How can I unit test this?

like image 564
Shamoon Avatar asked May 14 '14 18:05

Shamoon


People also ask

Is AngularJS code unit testable?

AngularJS is written with testability in mind, but it still requires that you do the right thing. We tried to make the right thing easy, but if you ignore these guidelines you may end up with an untestable application.


2 Answers

Unit testing a run(..) block is as simple as loading your module(..) in jasmine.

All of the code below is available in this plunker.

Consider the following very simple app.js:

var _idx = 1;
window.log = function(s) {
  console.log('(' + _idx++ + ') ' + s);
};

var app = angular.module('myapp', []);

app.run(function($rootScope) {
  log('run block');
  $rootScope.valueSetInRun = 666;

});

app.controller('MainCtrl', function($scope) {
  log('MainCtrl block');
});

Note that the markup is irrelevant in this app.

Now consider the following test:

describe('myapp', function() {

  beforeEach(module('myapp'));

  beforeEach(inject(function($rootScope) {
    log('beforeEach');
  }));

  it('should allow me to test the run() block', inject(function ($rootScope) {
    log('it block');
    expect( $rootScope.valueSetInRun ).toBe(666);
  }));
});

Here is the console output:

(1) run block 
(2) MainCtrl block 
(3) run block 
(4) beforeEach 
(5) it block 

Note that the test passes

Some important observations

  • The first two console outputs, (1) and (2) are logged during normal app execution
  • Log messages (3) to (5) are outputted while the test is running.

Given the above, we can conclude the following:

  1. In the unit test, the module 'myapp' was instantiated
  2. In the unit test, MainCtrl wasn't instantiated
  3. In the unit test, the run block was executed
  4. When running a unit test, the beforeEach...run block is executed first, then beforeEach and finally the it block.
  5. The second beforeEach is not useful for unit testing a run block (note that you can put a beforeEach block before beforeEach(module('myapp'));, however if you try creating an injector in that block your test will fail)

And finally, we can conclude that the code above is how you can test a run block. As to your particular test, armed with this knowledge, it will be possible to construct a unit test using dependency injection mocking and Jasmine's toHaveBeenCalled() assertion.

like image 112
Gil Birman Avatar answered Nov 02 '22 08:11

Gil Birman


One easy method would be to store an 'authentication' object in $rootScope. In your unit test, expect that value to be empty or undefined, then populate the object in your service, and re-test against the value or length of that object.

like image 42
Steve Avatar answered Nov 02 '22 10:11

Steve