讀古今文學網 > 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