From chai's api you've got code like this:
.exist
Asserts that the target is neither null nor undefined.
var foo = 'hi'
, bar = null
, baz;
expect(foo).to.exist;
expect(bar).to.not.exist;
expect(baz).to.not.exist;
How does that exist part work? The expect function returns an object, then there's simply a property lookup on the "to" object. That's simply a property evaluation though isn't it? The only thing that would make sense to me is if the exist property is a getter method.
What's the go?
When you call
expect(foo)
, a new Assertion object is instantiated.to, have, with, and similar properties do nothing but to return that Assertion instance. They are only for readability.
However, in your example, exists, is actually something that runs an assertion.
Its a property. They way properties are added to Assertion is that they are defined as getter functions as you can see here.
expect(foo).to.exist
could be broken down to this:assertion.exists
is added to the assertion object with a getter. That means when you execute assertion.exists, to evaluate the value of assertion.exists, a function that was earlier provided toaddProperty
is executed.You can read more about getter functions.
chai exposes an
use
method to access thechai
export and it'sutils
.This method can be used by third parties when creating plugins, but it's also used internally to load it's interface.
The implementation of this method is simple:
Internally it uses this to load (among other) the primary
Assertion prototype
and the core assertion functionality:One of the methods that are exposed by the
Assertion prototype
is theaddProperty
method which allows you to add properties to saidprototype
.Internally
chai
uses this method to add the core assertion functionality to theAssertion prototype
. For instance, all language chains and assertion helpers (exist
,empty
, etc) are added this way.Language chains:
All this functionality becomes available when a specific interface gets loaded internally, for instance
expect
. When this interface is loaded, a newAssertion prototype
will be instantiated wheneverexpect
gets executed, which will contain all functionality:As you can see the
expect
method accepts aval
argument (and an optionalmessage
argument). When this method is called (for instanceexpect(foo)
) a newAssertion prototype
will be instantiated and returned, exposing all core functionality (allowing you to doexpect(foo).to.exist
).The
Assertion Constructor
uses theflag
util
to set a flag value on the Object that maps to the passed inval
argument.All
exist
then does, is get this value through theflag
util
and evaluates if it not equals tonull
, using theassert
method defined on theAssertion prototype
.