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

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

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

Как эта существующая часть работает? Ожидаемая функция возвращает объект, а затем просто выполняется поиск свойства объекта «кому». Это просто оценка собственности, не так ли? Единственное, что имело бы смысл для меня, это если бы свойство exists было методом получения.

Что делать?


person Larry Lawless    schedule 24.07.2015    source источник
comment
Это свойство геттера.   -  person Bergi    schedule 24.07.2015
comment
Да и не привык их часто использовать.   -  person Larry Lawless    schedule 24.07.2015
comment
Что ж, chai обнимает их. И вы не смотрели на should  -  person Bergi    schedule 24.07.2015
comment
Тот факт, что мы даже обсуждаем этот вопрос, означает, что в chai слишком много волшебства.   -  person William Entriken    schedule 28.07.2021


Ответы (2)


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.

Внутри 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'
    );
  });
person danillouz    schedule 24.07.2015
comment
Но как он останавливает выполнение кода, оставшегося после ожидаемого вызова, если тест не пройден? Например, если позже в it есть обратный вызов done(), он не выполняется... - person Cool Blue; 03.07.2016

Когда вы вызываете expect(foo), создается экземпляр нового объекта Assertion.

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

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

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

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

const assertion = new Assertion;
assertion.exists;

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

Подробнее о геттер-функциях можно прочитать здесь.

person Emil Sedgh    schedule 08.12.2016