JESii JESii - 1 month ago 29
AngularJS Question

AngularJS / Karma testing: beforeEach not executed

I'm working on some TDD for AngularJS (another story altogether) and ran into a situation where my beforeEach calls are apparently not being executed. I reduced it down to the following example.

This works as evidenced by the fact that the console.log messages in beforeEach and it both appear:

describe('userApp', function(){
beforeEach( function(){
console.log("in beforeEach...");
});

it('should be able to log something', function(){
console.log("in it...");
});
});


This doesn't work, as evidenced by the fact that the console.log message in the beforeEach is NOT displayed and the it fails when attempting to $log.info and throws the error message:
TypeError: Cannot read property 'info' of undefined


describe('userApp', function(){
var $log;
beforeEach(module('userApp', function($provide) {
console.log("in beforeEach...");
// Output messages
$provide.value('$log', console);
}));
it('should be able to log something', function(){
console.log("in it...");
$log.info("Using $log for logging...");
});
});


I'm using Angular 1.3.15, karma 0.12.31, jasmine 2.3.4. Probably something obvious I'm overlooking...

EDIT: Michael Radionov's explanation is very helpful; however, I don't understand why this modified code still throws the same error.

describe('userApp', function(){
console.log("starting TEST3"); <=== this prints
var $log;
beforeEach(function() {
console.log("TEST3: in beforeEach..."); <=== this prints
module('userApp', function($provide, _$log_) {
$log = _$log_;
console.log("TEST3: in beforeEach/module..."); <=== never executed
// Output messages
$provide.value('$log', console);
$log.info("TEST3: calling $log in beforeEach...");
})
});
it('should be able to log something', function(){
console.log("TEST3: in it...");
$log.info("TEST3: Using $log for logging..."); <=== $log undefined err
});
});


Furthermore, it seems the code in "module('userApp'..." is never executed...?

Answer

The reason your log message console.log("in beforeEach..."); is not being displayed is because it is not actually inside beforeEach, it is inside an anonymous function passed to a module(..) as an argument which is considered to be a module by angular-mocks. This module will be executed only when injection happens and at the same time you'll receive a log message in beforeEach..., but there is no any injection in your test, so it never happens. beforeEach fires anyway, you just didn't put console.log in the right place; it will work:

beforeEach(function () {

  console.log("in beforeEach...");

  module('userApp', function($provide) {
    // Output messages
    $provide.value('$log', console);
  });

});

Also it seems that you forgot to inject mocked $log into you test suite, your $log variable never gets any value, so it stays undefined as the error states.

describe('userApp', function(){ 

  var $log;

  beforeEach(function () {
    console.log("in beforeEach...");

    module('userApp', function($provide) {
      // Output messages
      $provide.value('$log', console);
    });

    // getting an instance of mocked service to use in a test suite
    inject(function (_$log_) {
      $log = _$log_;
    });

  }); 

  it('should be able to log something', function(){ 
    console.log("in it...");
    $log.info("Using $log for logging...");
  }); 

});

See the plunker: http://plnkr.co/edit/EirNEthh4CXdBSDAeqOE?p=preview

Docs:

Comments