映月读书网 > Vue2实践揭秘 > 附录A Chai断言参考 >

附录A Chai断言参考

not

对之后的断言取反:

    expect(foo).to.not.equal(\'bar\')
    expect(goodFn).to.not.throw(Error)
    expect({ foo: \'baz\' }).to.have.property(\'foo\').and.not.equal(\'bar\')  
deep

设置deep标记,然后使用equal和property断言。该标记可以让其后的断言不是比较对象本身,而是递归比较对象的键值对:

    expect(foo).to.deep.equal({ bar: \'baz\' })
    expect({foo: {bar: { baz: \'quux\' }}})
      .to.have.deep.property(\'foo.bar.baz\', \'quux\')  

deep.property中的特殊符号可以使用双反斜杠进行转义(第一个反斜杠是在字符串参数中对第二个反斜杠进行转义,第二个反斜杠用于在property中进行转义):

    var deepCss = {\'.link\': { \'[target]\': 42 }}
    expect(deepCss).to.have.deep.property(\'\\.link.\\[target\\]\', 42)  
any

在keys断言之前使用any标记(与all相反):

    expect(foo).to.have.any.keys(\'bar\', \'baz\')  
all

在keys断言之前使用all标记(与any相反):

    expect(foo).to.have.all.keys(\'bar\', \'baz\')  
a(type)/an(type)

● type:String,被测试的值的类型。

a和an断言即可作为语言链又可作为断言使用:

    

// 类型断言
    expect(\'test\').to.be.a(\'string\');
    expect({ foo: \'bar\' }).to.be.an(\'object\');
    expect(null).to.be.a(\'null\');
    expect(undefined).to.be.an(\'undefined\');
    expect(new Error).to.be.an(\'error\');
    expect(new Promise).to.be.a(\'promise\');
    expect(new Float32Array).to.be.a(\'float32array\');
    expect(Symbol).to.be.a(\'symbol\');

    // es6 overrides
    expect({[Symbol.toStringTag]:=>\'foo\'}).to.be.a(\'foo\');

    // language chain
    expect(foo).to.be.an.instanceof(Foo);
    ** include(value) / contains(value) **  

● value:Object/String/Number。

include和contains既可作为属性类断言前缀语言链又可作为作为判断数组、字符串是否包含某值的断言使用。当作为语言链使用时,常用于key断言之前:

    expect([1, 2, 3]).to.include(2)
    expect(\'foobar\').to.include(\'bar\')
    expect({ foo: \'bar\', hello: \'universe\' }).to.include.keys(\'foo\')  
ok

断言目标为真值:

    expect(\'everything\').to.be.ok
    expect(1).to.be.ok
    expect(false).to.not.be.ok
    expect(null).to.not.be.ok  
true

断言目标为true,注意,这里与ok的区别是不进行类型转换,只有为true才能通过断言:

    expect(true).to.be.true
    expect(1)to.not.be.true  
false

断言目标为false:

    expect(false).to.be.false
    

expect(0).to.not.be.false  
null

断言目标为null:

    expect(null).to.be.null
    expect(undefined).to.not.be.null  
undefined

断言目标为undefined:

    expect(undefine).to.be.undefined
    expect(null).to.not.be.undefined  
NaN

断言目标为非数字NaN:

    expect(\'foo\').to.be.null
    expect(4)to.not.be.null  
exist

断言目标存在,既非null也非undefined:

    var foo = \'hi\',
      bar = null,
      baz

    expect(foo).to.exist
    expect(bar).to.not.exist
    expect(baz).to.not.exist  
empty

断言目标的长度为0。对于数组和字符串,它检查length属性,对于对象,它检查可枚举属性的数量:

    expect().to.be.empty
    expect(\'\').to.be.empty
    expect({}).to.be.empty  
arguments

断言目标是一个参数对象arguments:

    function test  {
      expect(arguments).to.be.arguments
    

}  
equal(value)

● value:Mixed

断言目标严格等于(===)value。另外,如果设置了deep标记,则断言目标深度等于value:

    expect(\'hello\').to.equal(\'hello\')
    expect(42).to.equal(42)
    expect(1).to.not.equal(true)
    expect({foo: \'bar\'}).to.not.equal({foo: \'bar\'})
    expect({foo: \'bar\'}).to.deep.equal({ foo: \'bar\' })  
eql(value)

● value:Mixed

断言目标深度等于value,相当于deep.equal(value)的简写:

    expect({foo: \'bar\'}).to.eql({ foo: \'bar\' })
    expect([1, 2, 3]).to.eql([1, 2, 3])  
above(value)

● value:Number

断言目标大于(超过)value:

    expect(10).to.be.above(5)  

也可接在length后来断言一个最小的长度。相比直接提供长度的好处是提供了更详细的错误消息:

    expect(\'foo\').to.have.length.above(2)
    expect([1, 2, 3]).to.have.length.above(2)  
least(value)

● value:Number

断言目标不小于(大于或等于)value:

    expect(10).to.be.at.least(10)  

也可接在length后来断言一个最小的长度。相比直接提供长度的好处是提供了更详细的错误消息:

    expect(\'foo\').to.have.length.of.at.least(3)
    expect([1, 2, 3]).to.have.length.of.at.least(3) 
below(value)

● value:Number

断言目标小于value:

    expect(5).to.be.below(10)  

也可接在length后来断言一个最大的长度。相比直接提供长度的好处是提供了更详细的错误消息:

    expect(\'foo\').to.have.length.below(4)
    expect([1, 2, 3]).to.have.length.below(4)  
most(value)

● value:String

断言目标不大于(小于或等于)value:

    expect(5).to.be.at.most(5)  

也可接在length后来断言一个最大的长度。相比直接提供长度的好处是提供了更详细的错误消息:

    expect(\'foo\').to.have.length.of.at.most(4)
    expect([1, 2, 3]).to.have.length.of.at.most(3)  
within(start, finish)

● start:Number,下限;

● finish:Number,上限。

断言目标在某个区间内:

    expect(7).to.be.within(5,10)  

也可接在length后来断言一个长度区间。相比直接提供长度的好处是提供了更详细的错误消息:

    expect(\'foo\').to.have.length.within(2, 4)
    expect([1, 2, 3]).to.have.length.within(2, 4)  
instanceof(constructor)

● constructor:Constructor,构造函数。

断言目标是构造函数constructor的一个实例:

    var Tea = function (name) { this.name = name },
      Chai = new Tea(\'chai\')
    

expect(Chai).to.be.an.instanceof(Tea)
    expect([1, 2, 3]).to.be.an.instanceof(Array)  
property(name, [value])

● name:String,属性名;

● value:Mixed,可选,属性值。

断言目标是否拥有名为name的属性,如果提供了value则该属性值还需要严格等于(===)value。如果设置了deep标记,则可以使用点“.”和中括号“”来指向对象和数组中的深层属性:

    // 简单引用
    var obj = { foo: \'bar\' }
    expect(obj).to.have.property(\'foo\')
    expect(pbj).to.have.property(\'foo\', \'bar\')

    // 深层引用
    var deepObj = {
      green: { tea: \'matcha\' },
      teas: [\'Chai\', \'matcha\', { tea: \'konacha\' }]
    }

    expect(deepObj).to.have.deep.property(\'green.tea\', \'matcha\')
    expect(deepObj).to.have.deep.property(\'teas[1]\', \'matcha\')
    expect(deepObj).to.have.deep.property(\'teas[2].tea\', \'konacha\')  

如果目标是一个数组,还可以直接使用一个或多个数组下标作为name来在嵌套数组中断言deep.property:

    var arr = [
      [ \'chai\', \'matcha\', \'konacha\' ],
      [ { tea: \'chai\' },
        { tea: \'matcha\' },
        { tea: \'konacha\' }
      ]
    ]

    expect(arr).to.have.deep.property(\'[0][1]\', \'matcha\')
    expect(arr).to.have.deep.property(\'[1][2].tea\', \'konacha\')  

此外,property把断言的主语(subject)从原来的对象变为当前属性的值,使得可以在其后进一步衔接其他链式断言(来针对这个属性值进行测试):

    expect(obj).to.have.property(\'foo\')
      

.that.is.a(\'string\')
    expect(deepObj).to.have.property(\'green\')
      .that.is.an(\'object\')
      .that.deep.equals({ tea: \'matcha\' })
    expect(deepObj).to.have.property(\'teas\')
      .that.is.an(\'array\')
      .with.deep.property(\'[2]\')
        .that.deep.equals({ tea: \'konacha\' })  

只有当设置了deep标记的时候,在property name中的点(.)和中括号()才必须使用双反斜杠进行转义(为什么是双反斜杠,在前文有提及),当没有设置deep标记的时候,是不能进行转义的。

    // 简单指向
    var css = { \'.link[target]\': 42 }
    expect(css).to.have.property(\'.link[target]\', 42)

    // 深度指向
    var deepCss = { \'link\': { \'[target]\': 42 } }
    expect(deepCss).to.have.deep.property(\'\\.link\\.[target]\', 42)  
ownProperty(name)

● name:String,属性名。

断言目标拥有名为name的自有属性:

    expect(\'test\').to.have.ownProperty(\'length\')  
ownPropertyDescription(name[, descriptor])

● name:String,属性名;

● descriptor:Object,描述对象,可选。

断言目标的某个自有属性存在描述符对象,如果给定了descroptor描述符对象,则该属性的描述符对象必须与其相匹配:

    expect(\'test\').to.have.ownPropertyDescriptor(\'length\')
    expect(\'test\').to.have.ownPropertyDescriptor(\'length\', {
      enumerable: false,
      configrable: false,
      writeable: false,
      value: 4
    })

    expect(\'test\').not.to.have.ownPropertyDescriptor(\'length\', {
      enumerable: false,
        

configurable: false,
        writeable: false,
        value: 3
    })

    // 将断言的主语改为了属性描述符对象
    expect(\'test\').to.have.ownPropertyDescriptor(\'length\')
      .to.have.property(\'enumerable\', false)

    expect(\'test\').to.have.ownPropertyDescriptor(\'length\')
      .to.have.keys(\'value\')  
length

设置.have.length标记作为比较length属性值的前缀:

    expect(\'foo\').to.have.length.above(2)
    expect([1, 2, 3]).to.have.length.within(2, 4)  
lengthOf(value)`
    -value:Number。  

断言目标的length属性为期望的值:

    expect([1, 2, 3]).to.have.lengthOf(3)
    expect(\'foobar\').to.have.lengthOf(6)  
match(regexp)

● regexp:RegExp,正则表达式。

断言目标匹配到一个正则表达式:

    expect(\'foobar\').to.match(/^foo/)  
string(string)

● string:String,字符串。

断言目标字符串包含另一个字符串:

    expect(\'foobar\').to.have.string(\'bar\')  
keys(key1, [key2], [...])

● key:String | Array | Object属性名。

断言目标包含传入的属性名。与any、all、contains或者have前缀结合使用会影响测试结果:

● 当与any结合使用时,无论是使用have还是使用contains前缀,目标必须至少存在一个传入的属性名才能通过测试。注意,any或者all应当至少使用一个,否则默认为all。

● 当结合all和contains使用时,目标对象必须至少拥有全部传入的属性名,但是它也可以拥有其他属性名。

● 当结合all和have使用时,目标对象必须且仅能拥有全部传入的属性名:

    // 结合any使用
    expect({ foo: 1, bar: 2, baz: 3 }).to.have.any.keys(\'foo\', \'bar\')
    expect({ foo: 1, bar: 2, baz: 3 }).to.contains.any.keys(\'foo\', \'bar\')

    // 结合all使用
    expect({ foo: 1, bar: 2, baz: 3 }).to.have.all.keys(\'foo\', \'bar\', \'baz\')
    expect({ foo: 1, bar: 2, baz: 3 }).to.contains.all.keys(\'foo\', \'bar\')

    // 传入string
    expect({ foo: 1, bar: 2, baz: 3 }).to.have.any.keys(\'foo\')
    // 传入Array
    expect({ foo: 1, bar: 2, baz: 3 }).to.have.all.keys([\'foo\', \'bar\', \'baz\'])
    // 传入Object
    expect({ foo: 1, bar: 2, baz: 3 }).to.have.any.keys({ bar: 2, foo: 1 })  
throw(constructor)

● constructor:ErrorConstroctor | String | RegExp。

断言目标函数会抛出一个指定错误或错误类型(使用instanceOf计算),也可使用正则表达式或者字符串来检测错误消息:

    var err = new RefernceError(\'this is a bad function\')
    var fn = function  { throw err }

    expect(fn).to.throw(ReferenceError)
    expect(fn).to.throw(Error)
    expect(fn).to.throw(/bad function/)
    expect(fn).to.not.throw(\'good function\')
    expect(fn).to.throw(ReferrenceError, /bad function/)
    expect(fn).to.throw(err)  

注意,当一个抛错断言被否定了(前面有not),那么它会从Error构造函数开始依次检查各个可能传入的参数。检查一个只是消息类型不匹配但是已知的错误,合理的方式是先断言该错误存在,然后使用and后断言错误消息不匹配:

    expect(fn).to.throw(ReferenceError)
      .and.not.throw(/good function/)  
respondTo(method)

● method:String。

断言目标类或对象会响应一个方法(存在这个方法):

    Klass.prototype.bar = function  {}
    expect(Klass).to.respondTo(\'bar\')
    expect(obj).to.respondTo(\'bar\')  

如果需要检查一个构造函数是否会响应一个静态方法(挂载在构造函数本身的方法),请查看itself标记:

    Klass.baz = function  {}
    expect(Klass).itself.to.respondTo(\'baz\')  
itself

设置itself标记,然后使用respondTo断言:

    function Foo  {}
    Foo.bar = function  {}
    Foo.prototype.baz = function  {}

    expect(Foo).itself.to.respondTo(\'bar\')
    expect(Foo).itself.not.to.respond(\'baz\')  
satisfy(method)

● method:Function,测试器,接受一个参数表示目标值,返回一个布尔值。

断言目标值能够让给定的测试器返回真值:

    expect(1).to.satisfy(function (num) { return num > 0 })  
closeTo(expected, delta)

● expect:Numbre,期望值;

● delta:Numbre,范围半径。

断言目标数字等于expected,或在期望值的+/−delta范围内:

    expect(1.5).to.be.closeTo(1, 0.5)  
members(set)

● set:Array

断言目标是set的超集,或前者有后者所有严格相等(===)的成员。另外,如果设置了deep标记,则成员进行深度比较(include/contains只能接受单个值,但它们的主语除了 是数组,还可以判断字符串;members则将它们的能力扩展为能够接受一个数组,但主语只能是数组):

    expect([1, 2, 3]).to.include.members([3, 2])
    expect([1, 2, 3]).to.not.include.members([3, 2, 8])

    expect([4, 2]).to.have.members([2, 4])
    expect([5, 2]).to.not.have.members([5, 2, 1])
    expect([{ id: 1 }]).to.deep.include.members([{ id: 1 }])  
oneOf(list)

● list:Array。

断言目标值出现在list数组的某个顶层位置(直接子元素,严格相等):

    expect(\'a\').to.be.oneOf([\'a\', \'b\', \'c\'])
    expect(9).to.not.be.oneOf([\'z\'])

    // 严格相等,所以对象类的值必须为同一个引用才能被判定为相等
    var three = [3]
    expect([3]).to.not.be.oneOf([1, 2, [3]])
    expect(three).to.not.be.oneOf([1, 2, [3]])
    expect(three).to.be.oneOf([1, 2, three])  
change(object, property)

● object:Object,对象;

● property:String,属性名。

断言目标方法会改变指定对象的指定属性:

    var obj = { val: 10 }
    var fn = function  { obj.val += 3 }
    var noChangeFn = function  { return \'bar\' + \'baz\' }

    expect(fn).to.change(obj, \'val\')  
increase(object, property)

● object:Object,对象;

● property:String,属性名。

断言目标方法会增加指定对象的属性:

    var obj = { val: 10 }
    var fn = function  { obj.val = 15 }
    expect(fn).to.increase(obj, val)  
decrease(object, property)

● object:Object,对象;

● property:String,属性名。

断言目标方法会减少指定对象的属性:

    var obj = { val: 10 }
    var fn = function  { obj.val = 5 }
    expect(fn).to.decrease(obj, val)  
extensible

断言目标对象是可扩展的(可以添加新的属性):

    var nonExtensibleObject = Object.preventExtensions({})
    var sealedObject = Object.seal({})
    var frozenObject = Object.freeze({})

    expect({}).to.be.extensible
    expect(nonExtensibleObject).to.not.be.extensible
    expect(sealObject).to.not.be.extensible
    expect(frozenObject).to.not.be.extensible  
sealed

断言目标对象是封闭的(无法添加新的属性并且存在的属性不能被删除但可以被修改):

    var sealedObject= Object.seal({})
    var frozenObject = Object.freeze({})

    expect(sealedObject).to.be.sealed
    expect(frozenObject).to.be.sealed
    expect({}).to.not.be.sealed  
frozen

断言目标对象是冻结的(无法添加新的属性并且存在的属性不能被删除和修改):

    var frozenObject = Object.freeze({})
    expect(frozenObject).to.be.frozen
    expect({}).to.not.be.frozen