How does the chai expect function work?

后端 未结 2 1045
别跟我提以往
别跟我提以往 2020-12-17 16:35

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         


        
相关标签:
2条回答
  • 2020-12-17 17:20

    chai exposes an use method to access the chai export and it's utils.

    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:

    exports.use = function (fn) {
      if (!~used.indexOf(fn)) {
        fn(this, util);
        used.push(fn);
      }
    
      return this;
    };
    

    Internally it uses this to load (among other) the primary Assertion prototype and the core assertion functionality:

    var assertion = require('./chai/assertion'); // primary Assertion prototype
    exports.use(assertion); // load it
    
    var core = require('./chai/core/assertions'); // core assertion functionality
    exports.use(core); // load it
    

    One of the methods that are exposed by the Assertion prototype is the addProperty method which allows you to add properties to said prototype.

    Internally chai uses this method to add the core assertion functionality to the Assertion prototype. For instance, all language chains and assertion helpers (exist, empty, etc) are added this way.

    Language chains:

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

    All this functionality becomes available when a specific interface gets loaded internally, for instance expect. When this interface is loaded, a new Assertion prototype will be instantiated whenever expect gets executed, which will contain all functionality:

    // load expect interface
    var expect = require('./chai/interface/expect'); // expect interface
    exports.use(expect); // load it
    
    // expect interface
    module.exports = function (chai, util) {
      chai.expect = function (val, message) {
        return new chai.Assertion(val, message); // return new Assertion Object with all functionality
      };
    };
    

    As you can see the expect method accepts a val argument (and an optional message argument). When this method is called (for instance expect(foo)) a new Assertion prototype will be instantiated and returned, exposing all core functionality (allowing you to do expect(foo).to.exist).

    The Assertion Constructor uses the flag util to set a flag value on the Object that maps to the passed in val argument.

      function Assertion (obj, msg, stack) {
        flag(this, 'ssfi', stack || arguments.callee);
        flag(this, 'object', obj); // the 'object' flag maps to the passed in val
        flag(this, 'message', msg);
      }
    

    All exist then does, is get this value through the flag util and evaluates if it not equals to null, using the assert method defined on the Assertion prototype.

      Assertion.addProperty('exist', function () {
        this.assert(
            null != flag(this, 'object')
          , 'expected #{this} to exist'
          , 'expected #{this} to not exist'
        );
      });
    
    0 讨论(0)
  • 2020-12-17 17:21

    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:

    const assertion = new Assertion;
    assertion.exists;
    

    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 to addProperty is executed.

    You can read more about getter functions.

    0 讨论(0)
提交回复
热议问题