Подтвердить что ты не робот

Как работает функция ожидания chai?

Из chai api у вас есть такой код:

.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;

Как эта часть работает? Функция expect возвращает объект, тогда просто объект ищет объект "to". Это просто оценка собственности, правда? Единственное, что имеет смысл для меня, это то, что существующее свойство является методом getter.

Что происходит?

4b9b3361

Ответ 1

chai предоставляет метод use для доступа к экспорту chai и utils.

Этот метод может использоваться третьими лицами, когда создает плагины, но он также внутренне используется для загрузки интерфейса.

Реализация этого метода проста:

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

  return this;
};

Внутри он использует это для загрузки (среди прочего) первичной Assertion prototype и основной функции утверждения:

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

Одним из методов, который подвергается Assertion prototype, является метод addProperty, который позволяет добавлять свойства к указанному prototype.

Internally chai использует этот метод для добавления функциональности подтверждения ядра к Assertion prototype. Например, все языковые цепочки и помощники утверждения (exist, empty и т.д.) Добавляются таким образом.

Языковые цепочки:

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

Вся эта функциональность становится доступной, когда определенный интерфейс загружается внутри, например expect. Когда этот интерфейс загружен, новый Assertion prototype будет создаваться при каждом выполнении expect, который будет содержать все функциональные возможности:

// 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
  };
};

Как вы видите, метод expect принимает аргумент val (и необязательный аргумент message). Когда этот метод вызывается (например, expect(foo)), будет создан и возвращен новый Assertion prototype, отображающий все основные функциональные возможности (позволяя делать expect(foo).to.exist).

Assertion Constructor использует flag util для установки значения флага объекта, который сопоставляется с переданным аргументом val.

  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);
  }

Все exist, а затем, получает это значение через flag util и оценивает, не соответствует ли ему null, используя метод assert, определенный на Assertion prototype.

  Assertion.addProperty('exist', function () {
    this.assert(
        null != flag(this, 'object')
      , 'expected #{this} to exist'
      , 'expected #{this} to not exist'
    );
  });

Ответ 2

Когда вы вызываете expect(foo), создается новый объект Assertion.

to, have, with и подобные свойства ничего не делают, кроме как вернуть этот экземпляр Assertion. Они предназначены только для удобства чтения.

Однако в вашем примере существует, на самом деле что-то, что выполняет утверждение.

Свойство. Их свойства добавляются в Assertion: они определяются как функции getter, как вы можете здесь.

expect(foo).to.exist можно разбить на это:

const assertion = new Assertion;
assertion.exists;

assertion.exists добавляется к объекту утверждения с геттером. Это означает, что когда вы выполняете assertion.exists, чтобы оценить значение assertion.exists, выполняется функция, ранее предоставленная addProperty.

Вы можете узнать больше о функции getter.