I have a unit test test case created with mocha and chai's expect where I deeply compare an array of value objects to the parsed content of a JSON file.
My record object has about 20 properties, and currently only the price can cause a mismatch. On a diff, I only see five of them.
expect(records).to.deep.equal(expected);
"data": {
- "price": 3578
+ "price": 3438
"not_important": "foo"
"also_not_important": "bar"
}
"data": {
- "price": 1828
+ "price": 1698
"not_important": "foo"
"also_not_important": "bar"
}
This is useful default in most cases, yet in this one it obfuscates which specific data object is breaking the assertions, as I only see redundant data here.
Assume there is a important
property in the data object that would make it quite clear what expectation is breaking the test. Therefore, I would like to be able to either configure what properties are shown or to display the entire object in the diff.
How can I configure mocha's diff display?
Here is a contrived meta-syntactic example showcasing the problem:
import {expect} from "chai";
describe(("diff problem"), () => {
it("should show case that the diff is not shown properly", () => {
const actual = {
a: 1,
troiz: 0,
bar: 0,
baz: 2,
poit: 3,
narf: 4,
fizzbuzz: 117,
fizz: 5,
buzz: 4,
waldo: 115,
mos: 85465,
important: "THIS IS IMPORTANT",
};
const expected = {
...actual,
a: 0,
};
return expect(actual).to.deep.equal(expected);
});
});
The output of that testcase will be:
2) SourceParser diff problem should show entire diff on error of one property:
AssertionError: expected { Object (a, troiz, ...) } to deeply equal { Object (a, troiz, ...) }
+ expected - actual
{
- "a": 1
+ "a": 0
"bar": 0
"baz": 2
"buzz": 4
"fizz": 5
Yet it would be helpful to see: important: "THIS IS IMPORTANT"
as well.
Here is the modified example for the array case:
describe(("diff problem with an array"), () => {
it("should show case that the diff is not shown properly for deep equal of arrays", () => {
const anEntity = {
a: 1,
troiz: 0,
bar: 0,
baz: 2,
poit: 3,
narf: 4,
fizzbuzz: 117,
fizz: 5,
buzz: 4,
waldo: 115,
mos: 85465,
important: "IMPORTANT", // assume that each item has a unique important property, which is why it's helpful for it to be shown
};
const offendingItem = {
...anEntity,
a: 0,
};
const actual = [
anEntity,
offendingItem,
anEntity,
];
const expected = [
anEntity,
anEntity,
anEntity,
];
return expect(actual).to.deep.equal(expected);
});
The output will be:
AssertionError: expected [ Array(3) ] to deeply equal [ Array(3) ]
+ expected - actual
"troiz": 0
"waldo": 115
}
{
- "a": 0
+ "a": 1
"bar": 0
"baz": 2
"buzz": 4
"fizz": 5
and it won't get better with Louis' answer modifying chai as it only dumps the entire actual array first and then shows the non-helpful diff:
AssertionError: expected [ { a: 1,
troiz: 0,
bar: 0,
baz: 2,
poit: 3,
narf: 4,
fizzbuzz: 117,
fizz: 5,
buzz: 4,
waldo: 115,
mos: 85465,
important: 'IMPORTANT' },
{ a: 0,
troiz: 0,
bar: 0,
baz: 2,
poit: 3,
narf: 4,
fizzbuzz: 117,
fizz: 5,
buzz: 4,
waldo: 115,
mos: 85465,
important: 'IMPORTANT' },
{ a: 1,
troiz: 0,
bar: 0,
baz: 2,
poit: 3,
narf: 4,
fizzbuzz: 117,
fizz: 5,
buzz: 4,
waldo: 115,
mos: 85465,
important: 'IMPORTANT' } ] to deeply equal [ { a: 1,
troiz: 0,
bar: 0,
baz: 2,
poit: 3,
narf: 4,
fizzbuzz: 117,
fizz: 5,
buzz: 4,
waldo: 115,
mos: 85465,
important: 'IMPORTANT' },
{ a: 1,
troiz: 0,
bar: 0,
baz: 2,
poit: 3,
narf: 4,
fizzbuzz: 117,
fizz: 5,
buzz: 4,
waldo: 115,
mos: 85465,
important: 'IMPORTANT' },
{ a: 1,
troiz: 0,
bar: 0,
baz: 2,
poit: 3,
narf: 4,
fizzbuzz: 117,
fizz: 5,
buzz: 4,
waldo: 115,
mos: 85465,
important: 'IMPORTANT' } ]
+ expected - actual
"troiz": 0
"waldo": 115
}
{
- "a": 0
+ "a": 1
"bar": 0
"baz": 2
"buzz": 4
"fizz": 5
As far as I know, there's no built-in way to get Chai or Mocha to produce diffs that would add to the context provided by the diff some fields that are not responsible for the test failure. And I'm not aware of any extension that would exactly what you are looking for. So I only know of workarounds.
If you set truncateThreshold
configuration setting to a larger value, or to 0
if you don't want any truncation, the failure message that appears before the diff will show whole objects. So if I add this to your code:
chai.config.truncateThreshold = 0; // 0 means "don't truncate, ever".
(The configuration options are covered on this documentation page.)
Then the error I get is:
AssertionError: expected { a: 1,
troiz: 0,
bar: 0,
baz: 2,
poit: 3,
narf: 4,
fizzbuzz: 117,
fizz: 5,
buzz: 4,
waldo: 115,
mos: 85465,
important: 'THIS IS IMPORTANT' } to deeply equal { a: 0,
troiz: 0,
bar: 0,
baz: 2,
poit: 3,
narf: 4,
fizzbuzz: 117,
fizz: 5,
buzz: 4,
waldo: 115,
mos: 85465,
important: 'THIS IS IMPORTANT' }
+ expected - actual
{
- "a": 1
+ "a": 0
"bar": 0
"baz": 2
"buzz": 4
"fizz": 5
Moreover, a way to get custom information in the error message is to set a custom message with the assertion, for instance:
expect(actual).to.deep.equal(
expected,
`failed equality test on object with important field set to: ${actual.important}`)
The custom message can be as verbose or terse as you need it to be.
If there is only one field that matters to you for differentiating objects, a custom message may be sufficient to get the information you need to track the problem.
For arrays of objects, you could perform a comparison by iterating through the actual
and expected
arrays and comparing each member. It would then essentially work like described above. For sure, this has disadvantages: if items 1 and 10 are different, for instance, you'll get a report only for item 1 because the test will end with that comparison failure. When you fix this problem and run the test again, you'll get a report for item 10. Whether or not in practice this is a major problem depends the kind of data you are testing.
One thing I've done in cases where the default diff algorithm was not doing what I wanted was to import a diffing library that I configured to my liking, and then use the library to perform diffs between objects that I cared about and combine the results into a final report that is then checked with an assertion.
Again, I'm not aware of a library that would do specifically what you are looking for. However, I could imagine iterating through the actual
and expected
arrays to produce one diff report per pair and then combining them into a larger report that contains identifying information.
You can add --inline-diffs
to the mocha command, which will show the entire object with line numbers and inline diffs:
mocha --inline-diffs YourSpec.js
The documentation is a bit misleading: https://mochajs.org/#diffs
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