Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is $log always silenced by angular-mocks?

$log service is recommended over console.log for AngularJS apps. One common use case for such logging is seeing debug print when running tests. The problem is, angular-mocks silences $log by default replacing it by a mock. Well, I do sometimes need to test my debug print, but I just need to see it much more often. The problem is, the default behavior insists on using dummy logging and I don't even see a proper way to revert back to real $log. I've made a jsfiddle example to illustrate it, try running it while looking at devtools console http://jsfiddle.net/ivan4th/EnvL9/

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

describe('myApp', function () {
    var element, rootScope;
    beforeEach(module('myApp'));
    it('does something', inject(function ($log) {
        $log.log("this message gets eaten by angular-mocks");
        console.log("this message is visible though");
    }));
});

The first message is skipped, while second is shown as expected. Why such strange behavior is used and is there any way to fix it besides not using $log?

like image 337
fionbio Avatar asked Mar 21 '23 09:03

fionbio


2 Answers

The mock $log service is designed to allow you to easily test and assert whether messages are logged or not, and ironically, to prevent log noise to the console when running tests.

If you don not like this behavior you can easily change it by doing:

$log.log = function(message){ console.log(message);};

Alternative you could output all previously logged messages to the console by doing:

console.log($log.log.logs)

You could add either method into a global before or after in your jasmine.

like image 174
Daniel Tabuenca Avatar answered Mar 23 '23 23:03

Daniel Tabuenca


Based on an idea from dtabuenc's answer, I've implemented workaround that dumps log outputs for Jasmine tests that fail, in the form of global afterEach():

afterEach(inject(function ($log) {
  // dump log output in case of test failure
  if (this.results().failedCount) {
    var out = [];
    angular.forEach(["log", "info", "warn", "error", "debug"], function (logLevel) {
      var logs = $log[logLevel].logs;
      if (!logs.length)
        return;
      out.push(["*** " + logLevel + " ***"]);
      out.push.apply(out, logs);
      out.push(["*** /" + logLevel + " ***"]);
    });
    if (out.length) {
      console.log("*** logs for: " + this.description + " ***");
      angular.forEach(out, function (items) { console.log.apply(console, items); });
    }
  }
  $log.reset();
}));

Unfortunately without replacing angular-mocks' $log implementation the order of messages with different log levels is lost, but I guess I'll be able to live with that. Silencing all log messages including Angular's own errors and warnings during tests still sound like bad design choice though.

like image 22
fionbio Avatar answered Mar 23 '23 23:03

fionbio