How to access Angular $log debug messages from within Karma

How to access Angular $log debug messages from within Karma
Photo by Sigmund / Unsplash

Angular has a convenient $log service that allows you to log debug messages to the console:

$log.debug('Some debug message');

The cool thing about debug messages is that you can easily turn logging on/off in one place using the $logProvider:

(function (angular) {

  angular
    .module('app')
    .config(setDebugMode);

  /**
   * Turn on/off debug mode
   */
  function setDebugMode($logProvider) {
    $logProvider.debugEnabled(true);
  }

  // Inject dependencies;
  setDebugMode.$inject = ['$logProvider'];
  
})(angular);

This allows you to leave all $log.debug statements in your code and just disable debug logging on your production environment and rest assured that nothing is actually logged to the console.

The problem with Karma

When running unit tests with Karma however, you will find that your debug logs don't appear in Karma's log output:

...
PhantomJS 1.9.8 (Mac OS X): Executed 29 of 54 SUCCESS (0 secs / 0.004 secs)
PhantomJS 1.9.8 (Mac OS X): Executed 30 of 54 SUCCESS (0 secs / 0.004 secs)
...

Enabling the debug log level in your karma config:

// level of logging, possible values:
// config.LOG_DISABLE
// config.LOG_ERROR
// config.LOG_WARN
// config.LOG_INFO
// config.LOG_DEBUG
logLevel: config.LOG_DEBUG

does NOT make the $log.debug() calls magically appear in your Karma log output, as this setting only affects Karma internally, not your Angular $logProvider.

The solution

The reason your messages don't appear in the Karma log is because angular-mocks.js contains a customized $logProvider that catches all messages in an array instead of logging them to the console.

To grab the output from this mock $log service within your unit tests, you can:

var $log;

// Inject the $log service
beforeEach(inject(function(_$log_){
  $log = _$log_;
}));
  
// Log debug messages in Karma
afterEach(function(){
  console.log($log.debug.logs);
});

which will output the debug logs to your Karma log:

...
PhantomJS 1.9.8 (Mac OS X): Executed 29 of 54 SUCCESS (0 secs / 0.004 secs)
LOG: [[''], ['Debug message'], ['']]
PhantomJS 1.9.8 (Mac OS X): Executed 30 of 54 SUCCESS (0 secs / 0.004 secs)
...

In fact you can access any level of log messages like this:

afterEach(function(){

  // Messages logged using $log.log()
  console.log($log.log.logs);
  
  // Messages logged using $log.info()  
  console.log($log.info.logs);
  
  // Messages logged using $log.warn()
  console.log($log.warn.logs);
  
  // Messages logged using $log.error()
  console.log($log.error.logs);
  
  // Messages logged using $log.debug()
  console.log($log.debug.logs);
});

allowing you to conveniently access the output of your $log service when running unit tests.

To keep your Karma logs clean I wouldn't recommend logging the messages by default, but it can be a real life saver if you want to quickly enable debug logging in your unit tests to troubleshoot an issue.

So if you ever need to inspect the logs, you now know how to get ahold of them!

Happy logging!