But this property is defined as undefined…
After all these years, JavaScript still occasionally trips me up. Today, I built a test that was failing mysteriously. I use Chai to write my assertions, and that particular test was failing to agree that the array I had constructed was deeply equal to its theoretical value. WebStorm’s test tooling has a diff visualization for deep object or array equality, and this was showing the arrays as equal:
It’s only after some deep dive debugging into Chai’s code that I spotted the difference between the two objects. One of the array items on the left of the comparison had one additional property defined, but with the value undefined. Yes, JavaScript lets you define a property as undefined, and there is a difference with never defining it, or setting it to null. Saying the a property is undefined is not the same as saying that it is defined as undefined. This is so much fun.
Try it is you don’t believe me… This will fail:
var foo = {a: 42};
foo.bar = foo.baz;
expect(foo).to.deep.equal({a: 42});
But this will pass:
expect(foo).to.deep.equal({a: 42, bar: undefined});
It’s kind of obvious written this way, because foo is being built right under your nose, but in a real test, this will typically happen deep in the tested code, so you won’t suspect it so easily. Also, with such a simple object, Chai itself will be helpful and tell you:
AssertionError: expected { a: 42, bar: undefined } to deeply equal { a: 42 }
Unfortunately, with bigger objects, it will be a lot less obvious and tell you something vague like:
AssertionError: expected [ Array(5) ] to deeply equal [ Array(5) ]
But well, that’s JavaScript for you, and the way you can tell them apart is by testing “hasOwnProperty”. The real issue here is that WebStorm fails to show a property set to undefined. This object visualization should enumerate the object using “getOwnProperties” and display what’s defined as undefined.
So next time you see two objects that look exactly the same, but don’t test as equal, look for properties defined as undefined.
Also, avoid setting properties to values that may be undefined. This is almost always a mistake. The semantically right value in those cases is almost always null. Or don’t set the property at all. Here’s how to fix the above code to make everything nicely explicit:
foo.bar = foo.baz || null;
If I had done that, the difference would have been obvious, because WebStorm’s tooling *does* show null values in the diff.