Chai Assertions .to.be.a.pony

At work, we use Chai Assertions to write unit and Protractor test assertions in a BDD style that read like English.

Examples

For example a passing test:

var someObject = {  
    'foo': 42,
    'bar': 84
};

var expected = {  
    'foo': 42,
    'bar': 84
};

expect(someObject).to.eql(expected);

// eql means deep equal and will compare all properties of the object

// √ Test Passes

And a failing test:

var foo = false;

expect(foo).to.be.true;

// X Test Fails

The Problem

I was recently refactoring a co-workers passing test to improve readability.

Before, the test looked like this:

expect(some.object.foo).to.equal('cat');  
expect(some.object.bar).to.equal('dog');  
expect(some.object.baz).to.equal.false;  
// ...10 more lines of this...

This test passed, but can you spot the mistake?

I refactored the multiple expects into an object comparison like I demonstrated earlier:

var expected = {  
    'foo': 'cat',
    'bar': 'dog',
    'baz': false
};

expect(some.object).to.include(expected);

// using include instead of eql because the object has other properties we don't want to make assertions on

The test started failing because some.object.baz was actually true. The previous implementation of the test tried to check for false with:

expect(some.object.baz).to.equal.false;  

This is not a valid assertion. It should have been written as:

expect(some.object.baz).to.equal(false);

// or

expect(some.object.baz).to.be.false;  

But why did the test pass? Can we just write anything we want:

.to.be.anything.we.want.kitty.cat

The Crazy

Getting to the point here, my co-workers original code had an improper assertion chain in it. Chai didn't recognize .to.equal.false but instead of failing the test or throwing an error of some sort, it just seemed to ignore it and move right along, giving us a false positive.

I'm not sure if we have Chai set up improperly or if there is some config we can tweak that would have alerted us that .to.equal.false is wrong, but I would expect it to error out and let us know we did something wrong.

.to.be.a.pony

Wrapping this post up now. The following test will pass:

var someObject = ...;

expect(someObject).to.be.a.pony;

// √ Test Passes

Ok. That's neat.

Show Comments