chai 公开了一个use 方法来访问chai 导出,它是utils。
creating plugins时第三方可以使用此方法,但内部也可以使用它来加载它的界面。
这个方法的实现很简单:
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。加载此接口后,每当执行expect 时,都会实例化一个新的Assertion prototype,其中将包含所有功能:
// 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 获取该值,并使用Assertion prototype 上定义的assert 方法评估它是否不等于null。
Assertion.addProperty('exist', function () {
this.assert(
null != flag(this, 'object')
, 'expected #{this} to exist'
, 'expected #{this} to not exist'
);
});