详解Chai.js断言库API中文文档


Posted in Javascript onJanuary 31, 2018

Chai.js断言库API中文文档

基于chai.js官方API文档翻译。仅列出BDD风格的expect/should API。TDD风格的Assert API由于不打算使用,暂时不放,后续可能会更新。

BDD

expect和should是BDD风格的,二者使用相同的链式语言来组织断言,但不同在于他们初始化断言的方式:expect使用构造函数来创建断言对象实例,而should通过为Object.prototype新增方法来实现断言(所以should不支持IE);expect直接指向chai.expect,而should则是chai.should()。

个人比较建议使用expect,should不仅不兼容IE,在某些情况下还需要改变断言方式来填坑。详细的比较可以看看官网Assertion Styles,说的很清楚。

var chai = require('chai') ,
 expect = chai.expect ,
 should = chai.should()

语言链

下面的接口是单纯作为语言链提供以期提高断言的可读性。除非被插件改写否则它们一般不提供测试功能。

  1. to
  2. be
  3. been
  4. is
  5. that
  6. which
  7. and
  8. has
  9. have
  10. with
  11. at
  12. of
  13. same

.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])

  1. name:String,属性名
  2. 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)

  1. object:Object,对象
  2. 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)

  1. object:Object,对象
  2. property:String,属性名

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

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

.decrease(object, property)

  1. object:Object,对象
  2. 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

TDD

除了一些语法糖以外,Chai提供的assert风格的断言和node.js包含的assert模块非常相似。assert风格是三种断言风格中唯一不支持链式调用的。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js 鼠标点击事件及其它捕获
Jun 04 Javascript
动态改变div的z-index属性的简单实例
Aug 08 Javascript
Node.js 去掉种子(torrent)文件里的邪恶信息
Mar 27 Javascript
JavaScript简单表格编辑功能实现方法
Apr 16 Javascript
微信小程序-消息提示框实例
Nov 24 Javascript
简单实现js浮动框
Dec 13 Javascript
JS实现图片手风琴效果
Apr 17 Javascript
详解React Native开源时间日期选择器组件(react-native-datetime)
Sep 13 Javascript
用p5.js制作烟花特效的示例代码
Mar 21 Javascript
基于Bootstrap下拉框插件bootstrap-select使用方法详解
Aug 07 Javascript
Vue axios设置访问基础路径方法
Sep 19 Javascript
深入浅析Node.js 事件循环、定时器和process.nextTick()
Oct 22 Javascript
微信小程序 如何引入外部字体库iconfont的图标
Jan 31 #Javascript
详解Vue单元测试Karma+Mocha学习笔记
Jan 31 #Javascript
Vue单页面应用保证F5强刷不清空数据的解决方案
Jan 31 #Javascript
Vue服务器渲染Nuxt学习笔记
Jan 31 #Javascript
微信小程序页面生命周期详解
Jan 31 #Javascript
在vue项目中使用Nprogress.js进度条的方法
Jan 31 #Javascript
pace.js和NProgress.js两个加载进度插件的一点小总结
Jan 31 #Javascript
You might like
PHP中feof()函数实例测试
2014/08/23 PHP
ThinkPHP整合百度Ueditor图文教程
2014/10/21 PHP
Yii实现自动加载类地图的方法
2015/04/01 PHP
Fleaphp常见函数功能与用法示例
2016/11/15 PHP
JavaScript 一行代码,轻松搞定浮动快捷留言-V2升级版
2010/04/02 Javascript
jquery select(列表)的操作(取值/赋值)
2011/03/16 Javascript
IE6 fixed的完美解决方案
2011/03/31 Javascript
jquery.pagination.js 无刷新分页实现步骤分享
2012/05/23 Javascript
javascript实现验证IP地址等相关信息代码
2015/05/10 Javascript
《JavaScript函数式编程》读后感
2015/08/07 Javascript
js删除数组元素、清空数组的简单方法(必看)
2016/07/27 Javascript
JavaScript自定义浏览器滚动条兼容IE、 火狐和chrome
2017/01/05 Javascript
Vue获取DOM元素样式和样式更改示例
2017/03/07 Javascript
webpack学习教程之publicPath路径问题详解
2017/06/17 Javascript
jQuery实现的表格前端排序功能示例
2017/09/18 jQuery
Vue源码学习之初始化模块init.js解析
2017/11/02 Javascript
微信小程序之圆形进度条实现思路
2018/02/22 Javascript
Vue 让元素抖动/摆动起来的实现代码
2018/05/31 Javascript
JavaScript中call和apply方法的区别实例分析
2018/08/03 Javascript
Koa代理Http请求的示例代码
2018/10/10 Javascript
浅析JavaScript中的事件委托机制跟深浅拷贝
2021/01/20 Javascript
Python编程对列表中字典元素进行排序的方法详解
2017/05/26 Python
Scrapy框架使用的基本知识
2018/10/21 Python
Django admin禁用编辑链接和添加删除操作详解
2019/11/15 Python
Julep官网:美容产品和指甲油
2017/02/25 全球购物
全球最大的中文旅行网站:去哪儿网
2017/11/16 全球购物
Farah官方网站:男士服装及配件
2019/11/01 全球购物
青年教师培训方案
2014/02/06 职场文书
小学开学典礼主持词
2014/03/19 职场文书
教师教学评估方案
2014/05/09 职场文书
计算机售后服务承诺书
2014/05/30 职场文书
企业办公室主任岗位职责
2015/04/01 职场文书
如何在Mac上通过docker配置PHP开发环境
2021/05/29 PHP
Mysql中存储引擎的区别及比较
2021/06/04 MySQL
Python操作CSV格式文件的方法大全
2021/07/15 Python
CSS link与@import的区别和用法解析
2023/05/07 HTML / CSS