Karma/Jasmine: Pretty printing object comparison

Since the time that the other answers here were added, a pretty-printing option became available in karma-jasmine-diff-reporter. I would suggest trying it -- it's very configurable and is working nicely for me in combination with other common test reporters.

A minimal configuration looks like:

    reporters: ['jasmine-diff'],

    jasmineDiffReporter: {
        multiline: true,
        pretty: true
    },

My answer is based on jasmine 2.0.1.

Method 1 is documented in the jasmine docs. So it is probably recommended.
Method 2 however is much simpler.

Method 1: Using a custom matcher

My initial though was to create a custom matcher as described here. So I copied the toHaveBeenCalledWith matcher from the jasmine source code and modified it so it would pretty print:

var matchers = {
  toBeCalledWith: function (util, customEqualityTesters) {
    return {
      compare: function() {
        var args = Array.prototype.slice.call(arguments, 0),
          actual = args[0],
          expectedArgs = args.slice(1),
          result = { pass: false };

        if (!jasmine.isSpy(actual)) {
          throw new Error('Expected a spy, but got ' + jasmine.JSON.stringify(actual, undefined, 2) + '.');
        }

        if (!actual.calls.any()) {
          result.message = function() {
            return 'Expected spy ' + actual.and.identity() + ' to have been called with ' + JSON.stringify(expectedArgs, undefined, 2) + ' but it was never called.';
          };
          return result;
        }

        if (util.contains(actual.calls.allArgs(), expectedArgs, customEqualityTesters)) {
          result.pass = true;
          result.message = function() {
            return 'Expected spy ' + actual.and.identity() + ' not to have been called with ' + JSON.stringify(expectedArgs, undefined, 2) + ' but it was.';
          };
        } else {
          result.message = function() {
            return 'Expected spy ' + actual.and.identity() + ' to have been called with ' + JSON.stringify(expectedArgs, undefined, 2) + ' but actual calls were ' + JSON.stringify(actual.calls.allArgs(), undefined, 2) + '.';
          };
        }

        return result;
      }
    };
  }
};

The test case would then use our new matcher instead:

describe('Test', function() {

  beforeEach(function() {
    jasmine.addMatchers(matchers);
  });

  it('should print pretty', function() {
    var spy = jasmine.createSpy('spy');
    spy({
      currentCareMoment: {
      ID: 5,
      Description: 'Late namiddag (16-20)',
      StartHour: 16,
      EndHour: 20
    },
    previousCareMoment: {
      ID: 4,
      Description: 'Namiddag (14-16)',
      StartHour: 14,
      EndHour: 16
    }});

    expect(spy).toBeCalledWith({
      currentCareMoment: {
        ID: 6,
        Description: 'Avond (20-24)',
        StartHour: 20,
        EndHour: 24
      },
      previousCareMoment: {
        ID: 5,
        Description: 'Late namiddag (16-20)',
        StartHour: 16,
        EndHour: 20
      }
    });
  });
});

Method 2: Override jasmine.pp

However, during implementing this I noticed jasmine uses the function jasmine.pp for pretty printing. So I figured I could just override this by adding the following on top of my test file:

jasmine.pp = function(obj) {
  return JSON.stringify(obj, undefined, 2);
};

I found that overriding jasmine.pp caused my spec reporters to no longer color-code actual vs. expected diffs.

My solution was to add the below snippet to it's own file, load it into karma.conf, then add the custom matcher (using underscore for asserting deep equality) to the config of the reporter that produces color-coded diffs in the console (karma-jasmine-diff-reporter)

//This will run before all of our specs because it's outside of a describe block
beforeEach(function() {
  var objectMatcher = {
    toEqualObject: function(util, customEqualityTesters) {
      return {
        compare: function(actual, expected) {
          var result = {};
          result.pass = _.isEqual(actual, expected);
          if (result.pass) {
            result.message = "Expected \n" + JSON.stringify(actual, null, 2) + "\n not to equal \n" + JSON.stringify(expected, null, 2) + "\n";
          } else {
            result.message = "Expected \n" + JSON.stringify(actual, null, 2) + "\n to equal \n" + JSON.stringify(expected, null, 2) + "";
          }
          return result;
        }
      };
    }
  };
  jasmine.addMatchers(objectMatcher);
});

Now I can get output like this in the console, by calling expect(foo).toEqualObject(bar):

Pretty console output

Figuring out how to make this work with jasmine spies is left as an exercise for the reader.