I'm currently using the Karma test runner for my Angular project, with the jasmine testing framework. It's working great, but I have one issue: When an object comparison fails, the resulting print into the console is really hard to read, and gets harder the more properties these objects have. Example:
Expected spy spy to have been called with [ { currentCareMoment : { ID : 5, Description : 'Late namiddag (16-20)', StartHour : 16, EndHour : 20 }, previousCareMoment : { ID : 4, Description : 'Namiddag (14-16)', StartHour : 14, EndHour : 16 } } ] but actual calls were [ { currentCareMoment : { ID : 6, Description : 'Avond (20-24)', StartHour : 20, EndHour : 24 }, previousCareMoment : { ID : 5, Description : 'Late namiddag (16-20)', StartHour : 16, EndHour : 20 } } ].
Is there anyway to set up Jasmine (as I think Karma has nothing to do with it) to print objects prettier? Just some line breaks and indentation would already be a huge help. Example:
Expected spy spy to have been called with [ {
currentCareMoment : {
ID : 5,
Description : 'Late namiddag (16-20)',
StartHour : 16,
EndHour : 20
},
previousCareMoment : {
ID : 4,
Description : 'Namiddag (14-16)',
StartHour : 14,
EndHour : 16
}
} ] but actual calls were [ {
currentCareMoment : {
ID : 6,
Description : 'Avond (20-24)',
StartHour : 20,
EndHour : 24
},
previousCareMoment : {
ID : 5,
Description : 'Late namiddag (16-20)',
StartHour : 16,
EndHour : 20
}
} ].
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.
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
}
});
});
});
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)
:
Figuring out how to make this work with jasmine spies is left as an exercise for the reader.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With