How does the expect().to.be.true work in Chai?

wangzi6147 picture wangzi6147 · Jun 26, 2017 · Viewed 14k times · Source
expect(true).to.be.true;

In this code, all the 'to', 'be', 'true' seems to be an attribute of the object response from 'expect(true)'.

How can these attributes work so that they can raise an exception?

Answer

CodinCat picture CodinCat · Jun 26, 2017

You can check the source code:

[ 'to', 'be', 'been'
  , 'is', 'and', 'has', 'have'
  , 'with', 'that', 'which', 'at'
  , 'of', 'same', 'but', 'does' ].forEach(function (chain) {
    Assertion.addProperty(chain);
});

and there is a addProperty in utils:
https://github.com/chaijs/chai/blob/master/lib/chai/utils/addProperty.js

With this you can chain the properties infinitely like: .to.be.to.to.to.be.equal()

Let's create a simpler demonstration:

Assume that you have an assert object, with the .true() method

const assert = {
  'true': function (v) {
    return !!v
  }
}

and you want to be able to chain .to infinitely. Simply Use the defineProperty to define our getter:

Object.defineProperty(assert, 'to', {
  get() {
    return assert
  }
})

so now you can

assert.to.to.to.to.true(false)

working code: https://codepen.io/CodinCat/pen/LLzBEX?editors=0012


I've added another more complex example here: https://codepen.io/CodinCat/pen/dRVjXL?editors=0012

In this example you can see that there is some behaviors in the .true property.

We store the value from expect() in the internal __expectObj and the __value property, and then verify it in the getter of .true. So you can

expect(false).to.to.to.to.true