Comparing objects with Chai

I use Karma, Mocha, and Chai for my unit testing of Oystr and I recently found myself needing to do a deep comparison of an output object and my expected value. I thought this would be as simple as using “expect(output).to.deep.equal(expected)” but for some reason it kept failing. As the object is pretty complex and large (multiple nested objects and arrays), I figured I would JSON.stringify both objects and do a quick WinMerge comparison to find what was wrong – but that showed they were both equal.

After a faffing about for another hour I finally found that it is to do with the fact that my object had methods declared upon it. This is the reason the JSON.stringify proved useless for finding the differences, because it ignores method declarations! For the kind of comparison I’m doing, I definitely want it to use “===” on properties that have a primitive typed value. But for methods, I would like it to ignore them.

Initially I thought that I would just modify my test so that I would create a test type that follows the exact same type structure. Thing is, I felt a sense of injustice. <rant>Why should I be forced to go back through a massive JSON object that, when properly formatted, is 700 lines long and make that fit?!?! Further to this, I was going to have to do it for quite a few of my expected output objects – what a waste of time!!! Additionally, one of the reasons I am even using Node.JS is because of it’s native understanding of JSON and here I am having to do stuff with a constructor and all!!!</rant> Also I’m a bit lazy, so I decided to write an extension for Chai that will do deep and strict comparisons of all primitives on an object but ignore methods.

“equalPropertiesOn” Chai Extension

You can find the source for the extension here https://github.com/chris-tomich/mymemorysucks/blob/master/ChaiObjectComparisonExtension/equalPropertiesOn.js . If I can be bothered at some stage, I’ll probably create an NPM package for it. It’s a pretty rough implementation at this stage (hence why I haven’t put it into NPM), but hopefully I’ll find the time to clean it up properly and create an NPM package. Unfortunately while I’m working full time on Oystr and then use my spare time to find consulting work + family + girl friend + Vainglory, I’m a little strapped for time to do something new.

To use the extension, just include it into your test unit project and then you can call it as so –

expect(output).to.equalPropertiesOn(expected);

What kind of objects can the extension compare successfully?

So let’s say you have an output object that is declared like so –

</pre>
<pre>function Dog(name) {
    this.name = name;
    this.enjoys = [];

    this.addActivity = function (activity) {
        this.enjoys.push(activity);
    };
}

function DogActivity(name, location) {
    this.name = name;
    this.location = location;
}

var fido = new Dog("Fido");
fido.addActivity(new DogActivity("running", "park"));
fido.addActivity(new DogActivity("chasing cats", "neighbourhood"));
fido.addActivity(new DogActivity("passing motion", "Dad's shoes"));</pre>
<pre>

you are able to successfully compare this against a object defined in JSON like so –

</pre>
<pre>var expectedFido = {
    name: "Fido",
    enjoys: [
        {
            name: "running",
            location: "park"
        },
        {
            name: "chasing cats",
            location: "neighbourhood"
        },
        {
            name: "passing motion",
            location: "Dad's shoes"
        }
    ]
};

expect(fido).to.equalPropertiesOn(expectedFido);</pre>
<pre>

If you were to compare these objects using Chai’s out-of-the-box deepEqual(), this would fail as the fido object has a method on it called “addActivity”. If you use the “equalPropertiesOn” extension, you can get pass this and just compare the properties.

Uncategorized

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s