The dangers of deep equal assertions in Chai.js
Deep equal assertions are faster to implement but usually come with a dangerous lack of attention
Has anyone in your team ever said something like this? “It was covered by unit tests, but we were comparing it against the wrong value!”
Most of the times I’ve heard that, there was a deep equal assertion involved. Deep equal assertions in Chai.js are extremely simple and fast to implement — why write assertions property by property when I can just do a deep comparison of an object that I can easily copy-paste in my tests? — but by doing so, developers miss the chance to ask themselves: is the value of this property what it really should be?
Consider a person
object that results from a transformation function with some business logic inside it. Let’s imagine that the property isActive
is determined by some internal checks in that function.
Often, a developer will just debug or console.log
the contents of the person
object and happily throw them into a deep.equal
comparison, like this:
“My unit test is passing, all is good!”
Unfortunately, the developer did not spend any time to really think about every single one of the properties in the object. It turns out isActive
should have been true
, and by the time someone in the team realizes the mistake, the damage will already be done.
Note to self, and to you all: don’t be lazy. Take some extra time to really, really think about every assertion:
When does Chai.js perform deep equal comparisons?
There are two ways in which Chai.js will do such comparisons:
expect(o1).to.eql(o2)
: asserts that o1 is deeply equal to o2 using their own deep equality algorithm. Has the aliaseqls
.expect(o1).to.deep.equal(o2)
: same as before, with one very important difference. This causes deep equality comparisons to also be used for any other assertions that follow in the chain.
Invest in good unit tests, you will sleep better at night!