677 lines
21 KiB
JavaScript
677 lines
21 KiB
JavaScript
/* global require, chai, describe, before, it */
|
||
// 数据模板定义(Data Temaplte Definition,DTD)
|
||
/*
|
||
## BDD
|
||
1. 结构
|
||
describe suite
|
||
[ describe ]
|
||
before after beforeEach afterEach
|
||
it test
|
||
done
|
||
搜索 this.async = fn && fn.length
|
||
2. 常用 expect
|
||
expect().to
|
||
.equal .deep.equal .not.equal
|
||
.match
|
||
.have.length .with.length
|
||
.have.property .have.deep.property
|
||
.to.be.a .to.be.an
|
||
.that
|
||
.least .most .within
|
||
3. 速度
|
||
搜索 test.speed
|
||
slow > 75
|
||
75 / 2 < medium < 75
|
||
fast < 75 / 2
|
||
*/
|
||
var expect = chai.expect
|
||
var Mock, $, _
|
||
|
||
describe('DTD', function() {
|
||
before(function(done) {
|
||
require(['mock', 'underscore', 'jquery'], function() {
|
||
Mock = arguments[0]
|
||
_ = arguments[1]
|
||
$ = arguments[2]
|
||
expect(Mock).to.not.equal(undefined)
|
||
expect(_).to.not.equal(undefined)
|
||
expect($).to.not.equal(undefined)
|
||
done()
|
||
})
|
||
})
|
||
describe('Literal', function() {
|
||
it('', function() {
|
||
var data = Mock.mock(this.test.title)
|
||
expect(data).to.equal(this.test.title)
|
||
})
|
||
it('foo', function() {
|
||
var data = Mock.mock(this.test.title)
|
||
expect(data).to.equal(this.test.title)
|
||
})
|
||
it(1, function() {
|
||
var data = Mock.mock(this.test.title)
|
||
expect(data).to.equal(this.test.title)
|
||
})
|
||
it(true, function() {
|
||
var data = Mock.mock(this.test.title)
|
||
expect(data).to.equal(this.test.title)
|
||
})
|
||
it(false, function() {
|
||
var data = Mock.mock(this.test.title)
|
||
expect(data).to.equal(this.test.title)
|
||
})
|
||
it({}, function() {
|
||
var data = Mock.mock(this.test.title)
|
||
expect(data).to.deep.equal(this.test.title)
|
||
})
|
||
it([], function() {
|
||
var data = Mock.mock(this.test.title)
|
||
expect(data).to.deep.equal(this.test.title)
|
||
})
|
||
it(function() {}, function() {
|
||
var data = Mock.mock(this.test.title)
|
||
expect(data).to.equal(undefined)
|
||
})
|
||
})
|
||
describe('String', function() {
|
||
// `'name|min-max': 'value'`
|
||
it('name|min-max', function() {
|
||
var data = Mock.mock({
|
||
'name|1-10': '★号'
|
||
})
|
||
expect(data.name).to.have.length.within(2, 20)
|
||
})
|
||
|
||
// `'name|count': 'value'`
|
||
it('name|count', function() {
|
||
var data = Mock.mock({
|
||
'name|10': '★号'
|
||
})
|
||
expect(data.name).to.be.a('string')
|
||
.that.have.length(20)
|
||
})
|
||
})
|
||
describe('Number', function() {
|
||
// `'name|+step': value`
|
||
it('name|+step', function() {
|
||
var data = Mock.mock({
|
||
'list|10': [{
|
||
'name|+1': 100
|
||
}]
|
||
})
|
||
expect(data.list).to.be.an('array').with.length(10)
|
||
_.each(data.list, function(item, index) {
|
||
expect(item).to.have.property('name')
|
||
.that.be.a('number')
|
||
if (index === 0) expect(item.name).to.equal(100)
|
||
else expect(item.name).to.equal(
|
||
data.list[index - 1].name + 1
|
||
)
|
||
})
|
||
})
|
||
|
||
// `'name|min-max': value`
|
||
it('name|min-max', function() {
|
||
var data = Mock.mock({
|
||
'name|1-100': 100
|
||
})
|
||
expect(data).to.have.property('name')
|
||
.that.be.a('number').within(1, 100)
|
||
})
|
||
it('name|max-min', function() {
|
||
var data = Mock.mock({
|
||
'name|100-1': 100
|
||
})
|
||
expect(data).to.have.property('name')
|
||
.that.be.a('number').within(1, 100)
|
||
})
|
||
it('name|-min--max', function() {
|
||
var data = Mock.mock({
|
||
'name|-100--1': 100
|
||
})
|
||
expect(data).to.have.property('name')
|
||
.that.be.a('number').within(-100, -1)
|
||
})
|
||
it('name|-max--min', function() {
|
||
var data = Mock.mock({
|
||
'name|-1--100': 100
|
||
})
|
||
expect(data).to.have.property('name')
|
||
.that.be.a('number').within(-100, -1)
|
||
})
|
||
it('name|min-min', function() {
|
||
var data = Mock.mock({
|
||
'name|10-10': 100
|
||
})
|
||
expect(data).to.have.property('name')
|
||
.that.be.a('number').equal(10)
|
||
})
|
||
it('name|count', function() {
|
||
var data = Mock.mock({
|
||
'name|10': 100
|
||
})
|
||
expect(data).to.have.property('name')
|
||
.that.be.a('number').equal(10)
|
||
})
|
||
|
||
// `'name|min-max.dmin-dmax': value`
|
||
|
||
// 1 整数部分 2 小数部分
|
||
var RE_FLOAT = /([\+\-]?\d+)\.?(\d+)?/
|
||
|
||
function validNumber(number, min, max, dmin, dmax) {
|
||
expect(number).to.be.a('number')
|
||
RE_FLOAT.lastIndex = 0
|
||
var parts = RE_FLOAT.exec('' + number)
|
||
expect(+parts[1]).to.be.a('number').within(min, max)
|
||
expect(parts[2]).to.have.length.within(dmin, dmax)
|
||
}
|
||
|
||
it('name|min-max.dmin-dmax', function() {
|
||
var data = Mock.mock({
|
||
'name|1-10.1-10': 123.456
|
||
})
|
||
validNumber(data.name, 1, 10, 1, 10)
|
||
})
|
||
it('name|min-max.dcount', function() {
|
||
var data = Mock.mock({
|
||
'name|1-10.10': 123.456
|
||
})
|
||
validNumber(data.name, 1, 10, 10, 10)
|
||
})
|
||
it('name|count.dmin-dmax', function() {
|
||
var data = Mock.mock({
|
||
'name|10.1-10': 123.456
|
||
})
|
||
validNumber(data.name, 10, 10, 1, 10)
|
||
})
|
||
it('name|count.dcount', function() {
|
||
var data = Mock.mock({
|
||
'name|10.10': 123.456
|
||
})
|
||
validNumber(data.name, 10, 10, 10, 10)
|
||
})
|
||
it('name|.dmin-dmax', function() {
|
||
var data = Mock.mock({
|
||
'name|.1-10': 123.456
|
||
})
|
||
validNumber(data.name, 123, 123, 1, 10)
|
||
})
|
||
it('name|.dcount', function() {
|
||
var data = Mock.mock({
|
||
'name|.10': 123.456
|
||
})
|
||
validNumber(data.name, 123, 123, 10, 10)
|
||
})
|
||
})
|
||
describe('Boolean', function() {
|
||
// `'name|1': value`
|
||
it('name|1', function() {
|
||
var data = Mock.mock({
|
||
'name|1': true
|
||
})
|
||
expect(data).to.have.property('name')
|
||
.that.be.a('boolean')
|
||
})
|
||
|
||
// `'name|min-max': value`
|
||
it('name|min-max', function() {
|
||
var data = Mock.mock({
|
||
'name|8-2': true
|
||
})
|
||
expect(data).to.have.property('name')
|
||
.that.be.a('boolean')
|
||
})
|
||
})
|
||
describe('Object', function() {
|
||
var methods = {
|
||
GET: '@URL',
|
||
POST: '@URL',
|
||
HEAD: '@URL',
|
||
PUT: '@URL',
|
||
DELETE: '@URL'
|
||
}
|
||
var methodCount, tpl, data
|
||
|
||
// `'name|min-max': {}`
|
||
it('name|min-max', function() {
|
||
methodCount = _.keys(methods).length // 5
|
||
for (var min = 0, max; min <= methodCount + 1; min++) {
|
||
tpl = {}
|
||
max = Mock.Random.integer(0, methodCount)
|
||
|
||
// methods|0-? |1-? |2-? |3-? |4-? |5-? |6-?
|
||
tpl['methods|' + min + '-' + max] = methods
|
||
data = Mock.mock(tpl)
|
||
expect(_.keys(data.methods)).to.have.length
|
||
.that.within(Math.min(min, max), Math.max(min, max))
|
||
}
|
||
})
|
||
|
||
// `'name|count': {}`
|
||
it('name|count', function() {
|
||
methodCount = _.keys(methods).length // 5
|
||
for (var count = 0; count <= methodCount + 1; count++) {
|
||
tpl = {}
|
||
tpl['methods|' + count] = methods
|
||
data = Mock.mock(tpl)
|
||
expect(_.keys(data.methods)).to.have.length(
|
||
Math.min(count, methodCount)
|
||
)
|
||
}
|
||
})
|
||
})
|
||
describe('Array', function() {
|
||
// `'name': [{}, {} ...]`
|
||
it('name', function() {
|
||
var value = [{
|
||
foo: 'foo'
|
||
}, {
|
||
bar: 'bar'
|
||
}, {
|
||
foobar: 'foobar'
|
||
}]
|
||
var data = Mock.mock({
|
||
name: value
|
||
})
|
||
expect(data).to.have.property('name')
|
||
.that.be.an('array').with.length(3)
|
||
.that.not.equal(value)
|
||
expect(data).to.have.property('name')
|
||
|
||
for (var i = 0; i < data.name.length; i++) {
|
||
expect(data.name[i]).to.not.equal(value[i])
|
||
expect(data.name[i]).to.deep.equal(value[i])
|
||
}
|
||
})
|
||
|
||
// `'name|1': [{}, {} ...]`
|
||
it('name|1: [1, 2, 4, 8]', function() {
|
||
// number array
|
||
var value = [1, 2, 4, 8]
|
||
var data = Mock.mock({
|
||
'name|1': value
|
||
})
|
||
expect(data).to.have.property('name')
|
||
.that.be.a('number')
|
||
expect(value).to.include(data.name)
|
||
})
|
||
it('name|1: ["GET", "POST", "HEAD", "DELETE"]', function() {
|
||
// string array
|
||
var value = ['GET', 'POST', 'HEAD', 'DELETE']
|
||
var data = Mock.mock({
|
||
'name|1': value
|
||
})
|
||
expect(data).to.have.property('name')
|
||
.that.be.a('string')
|
||
expect(value).to.include(data.name)
|
||
})
|
||
it('name|1 [{}]', function() {
|
||
// object array
|
||
var value = [{}]
|
||
var data = Mock.mock({
|
||
'name|1': value
|
||
})
|
||
expect(data).to.have.property('name')
|
||
.that.be.a('object')
|
||
.that.deep.equal({})
|
||
expect(data.name).to.not.equal(value[0])
|
||
})
|
||
it('name|1 [{}, {}, {}]', function() {
|
||
// object array
|
||
var data = Mock.mock({
|
||
'name|1': [{}, {}, {}]
|
||
})
|
||
expect(data).to.have.property('name')
|
||
.that.be.a('object')
|
||
.that.deep.equal({})
|
||
})
|
||
it('name|1 [{}, {}, {}]', function() {
|
||
// object array
|
||
var value = [{
|
||
method: 'GET'
|
||
}, {
|
||
method: 'POST'
|
||
}, {
|
||
method: 'HEAD'
|
||
}, {
|
||
method: 'DELETE'
|
||
}]
|
||
var data = Mock.mock({
|
||
'name|1': value
|
||
})
|
||
expect(data).to.have.property('name')
|
||
.that.be.a('object')
|
||
.that.have.property('method')
|
||
.that.be.a('string')
|
||
expect(_.pluck(value, 'method')).include(data.name.method)
|
||
})
|
||
|
||
// `'name|+1': [{}, {} ...]`
|
||
it('name|+1: ["a", "b", "c"]', function() {
|
||
var data = Mock.mock({
|
||
'list|5': [{
|
||
'name|+1': ['a', 'b', 'c']
|
||
}]
|
||
})
|
||
expect(data).to.have.property('list')
|
||
.that.be.an('array').with.length(5)
|
||
expect(data.list[0].name).to.equal('a')
|
||
expect(data.list[1].name).to.equal('b')
|
||
expect(data.list[2].name).to.equal('c')
|
||
expect(data.list[3].name).to.equal('a')
|
||
expect(data.list[4].name).to.equal('b')
|
||
})
|
||
it('name|+1: ["@integer", "@email", "@boolean"]', function() {
|
||
var data = Mock.mock({
|
||
'list|5-10': [{
|
||
'name|+1': ['@integer', '@email', '@boolean']
|
||
}]
|
||
})
|
||
expect(data).to.have.property('list')
|
||
.that.be.an('array').have.length.within(5, 10)
|
||
expect(data.list[0].name).to.be.a('number')
|
||
expect(data.list[1].name).to.be.a('string')
|
||
expect(data.list[2].name).to.be.a('boolean')
|
||
expect(data.list[3].name).to.be.a('number')
|
||
expect(data.list[4].name).to.be.a('string')
|
||
})
|
||
|
||
// `'name|min-max': [{}, {} ...]`
|
||
it('name|min-min', function() {
|
||
var data = Mock.mock({
|
||
'name|1-1': [{}]
|
||
})
|
||
expect(data.name).to.be.an('array').with.length(1)
|
||
_.each(data.name, function(item /*, index*/ ) {
|
||
expect(item).to.deep.equal({})
|
||
})
|
||
})
|
||
it('name|min-max [{}]', function() {
|
||
var data = Mock.mock({
|
||
'name|1-10': [{}]
|
||
})
|
||
expect(data.name).to.be.an('array').with.length.within(1, 10)
|
||
_.each(data.name, function(item /*, index*/ ) {
|
||
expect(item).to.deep.equal({})
|
||
})
|
||
})
|
||
it('name|max-min [{}]', function() {
|
||
var data = Mock.mock({
|
||
'name|10-1': [{}]
|
||
})
|
||
expect(data.name).to.be.an('array').with.length.within(1, 10)
|
||
_.each(data.name, function(item /*, index*/ ) {
|
||
expect(item).to.deep.equal({})
|
||
})
|
||
})
|
||
it('name|min-max [{}, {}]', function() {
|
||
var data = Mock.mock({
|
||
'name|1-10': [{}, {}]
|
||
})
|
||
expect(data.name).to.be.an('array').with.length.within(2, 20)
|
||
_.each(data.name, function(item /*, index*/ ) {
|
||
expect(item).to.deep.equal({})
|
||
})
|
||
})
|
||
it('name|max-min [{}, {}]', function() {
|
||
var data = Mock.mock({
|
||
'name|10-1': [{}, {}]
|
||
})
|
||
expect(data.name).to.be.an('array').with.length.within(2, 20)
|
||
_.each(data.name, function(item /*, index*/ ) {
|
||
expect(item).to.deep.equal({})
|
||
})
|
||
})
|
||
|
||
// `'name|count': [{}, {} ...]`
|
||
it('name|count [{}]', function() {
|
||
var data = Mock.mock({
|
||
'name|10': [{}]
|
||
})
|
||
expect(data.name).to.be.an('array').with.length(10)
|
||
_.each(data.name, function(item /*, index*/ ) {
|
||
expect(item).to.deep.equal({})
|
||
})
|
||
})
|
||
it('name|count [{}, {}]', function() {
|
||
var data = Mock.mock({
|
||
'name|10': [{}, {}]
|
||
})
|
||
expect(data.name).to.be.an('array').with.length(20)
|
||
_.each(data.name, function(item /*, index*/ ) {
|
||
expect(item).to.deep.equal({})
|
||
})
|
||
})
|
||
})
|
||
describe('Function', function() {
|
||
// `'name': function(){}`
|
||
it('name: function', function() {
|
||
var data = Mock.mock({
|
||
prop: 'hello',
|
||
name: function( /*root, path*/ ) {
|
||
return this.prop
|
||
}
|
||
})
|
||
expect(data).to.have.property('name')
|
||
.that.be.a('string').equal('hello')
|
||
})
|
||
|
||
// 无序的 function
|
||
it('name: function', function() {
|
||
var data = Mock.mock({
|
||
name2: function() {
|
||
return this.prop * 2
|
||
},
|
||
prop: 1,
|
||
name4: function() {
|
||
return this.prop * 4
|
||
}
|
||
})
|
||
expect(data.name2).to.equal(2)
|
||
expect(data.name4).to.equal(4)
|
||
})
|
||
|
||
// #25 改变了非函数属性的顺序,查找起来不方便
|
||
it('name: function', function() {
|
||
var data = Mock.mock({
|
||
name: function() {},
|
||
first: '',
|
||
second: '',
|
||
third: ''
|
||
})
|
||
var keys = _.keys(data)
|
||
expect(keys[0]).equal('first')
|
||
expect(keys[1]).equal('second')
|
||
expect(keys[2]).equal('third')
|
||
expect(keys[3]).equal('name')
|
||
})
|
||
})
|
||
|
||
/*
|
||
按照 http://www.regexr.com/ 的 Reference 设计测试用例。
|
||
https://github.com/nuysoft/Mock/blob/7c1e3a686bcc515855f1f583d70ae0ee89acc65e/test/regexp.js#L120
|
||
*/
|
||
describe('RegExp', function() {
|
||
function validRegExp(regexp) {
|
||
if (arguments.length > 1) {
|
||
for (var i = 0; i < arguments.length; i++) {
|
||
validRegExp(arguments[i])
|
||
}
|
||
}
|
||
|
||
it(regexp, function() {
|
||
var data = Mock.mock(regexp)
|
||
this.test.title += ' => ' + data
|
||
expect(regexp.test(data)).to.be.true
|
||
})
|
||
}
|
||
|
||
describe('Character Classes', function() {
|
||
validRegExp(/./)
|
||
validRegExp(
|
||
/[a-z]/,
|
||
/[A-Z]/,
|
||
/[0-9]/
|
||
)
|
||
validRegExp(
|
||
/\w/,
|
||
/\W/,
|
||
/\s/,
|
||
/\S/,
|
||
/\d/,
|
||
/\D/
|
||
)
|
||
validRegExp(
|
||
/[.]/,
|
||
/[\w]/,
|
||
/[\W]/,
|
||
/[\s]/,
|
||
/[\S]/,
|
||
/[\d]/,
|
||
/[\D]/
|
||
)
|
||
validRegExp(
|
||
/[^.]/,
|
||
/[^\w]/,
|
||
/[^\W]/,
|
||
/[^\s]/,
|
||
/[^\S]/,
|
||
/[^\d]/,
|
||
/[^\D]/
|
||
)
|
||
})
|
||
describe('Quantifiers', function() {
|
||
validRegExp(
|
||
/\d?/,
|
||
/\d+/,
|
||
/\d*/
|
||
)
|
||
|
||
// {n}, {n,}, {n,m}, {0,1} ?, {1,0} +, {0,} *
|
||
validRegExp(
|
||
/\d{5}/,
|
||
/\d{5,}/,
|
||
/\d{5,10}/,
|
||
/\d{0,1}/,
|
||
/\d{0,}/
|
||
)
|
||
|
||
validRegExp(/[\u4E00-\u9FA5]+/) // 汉字
|
||
})
|
||
describe('Anchors', function() {
|
||
validRegExp(/^/)
|
||
validRegExp(/$/)
|
||
validRegExp(/^foo/)
|
||
validRegExp(/foo$/)
|
||
validRegExp(/\bfoo/)
|
||
validRegExp(/\Bfoo/)
|
||
})
|
||
|
||
describe('Escaped Characters', function() {
|
||
validRegExp(/\000/)
|
||
validRegExp(/\xFF/)
|
||
validRegExp(/\uFFFF/)
|
||
validRegExp(/\cI/)
|
||
})
|
||
|
||
describe('Groups & Lookaround', function() {
|
||
validRegExp(/(ABC)/)
|
||
validRegExp(/(ABC)\1/)
|
||
validRegExp(/(?:ABC)/)
|
||
validRegExp(/(?=ABC)/)
|
||
validRegExp(/(?!ABC)/)
|
||
// validRegExp(/(?<=ABC)/)
|
||
// validRegExp(/(?<!ABC)/)
|
||
|
||
validRegExp(/(\d{5,10})|([a-zA-Z]{5,10})/)
|
||
validRegExp(/(?:\d{5,10})|(?:[a-zA-Z]{5,10})/)
|
||
validRegExp(/(.)(\w)(\W)(\s)(\S)(\d)(\D),\1\2\3\4\5\6\7,\1\2\3\4\5\6\7/)
|
||
})
|
||
|
||
describe('Quantifiers & Alternation', function() {
|
||
validRegExp(/.+/)
|
||
validRegExp(/.*/)
|
||
validRegExp(/.{1,3}/)
|
||
validRegExp(/.?/)
|
||
validRegExp(/a|bc/)
|
||
|
||
validRegExp(/\d{5,10}|[a-zA-Z]{5,10}/)
|
||
})
|
||
|
||
describe('Flags', function() {
|
||
// ignoreCase
|
||
// multiline
|
||
// global
|
||
})
|
||
})
|
||
|
||
describe('Complex', function() {
|
||
var tpl = {
|
||
'title': 'Syntax Demo',
|
||
|
||
'string1|1-10': '★',
|
||
'string2|3': 'value',
|
||
|
||
'number1|+1': 100,
|
||
'number2|1-100': 100,
|
||
'number3|1-100.1-10': 1,
|
||
'number4|123.1-10': 1,
|
||
'number5|123.3': 1,
|
||
'number6|123.10': 1.123,
|
||
|
||
'boolean1|1': true,
|
||
'boolean2|1-2': true,
|
||
|
||
'object1|2-4': {
|
||
'110000': '北京市',
|
||
'120000': '天津市',
|
||
'130000': '河北省',
|
||
'140000': '山西省'
|
||
},
|
||
'object2|2': {
|
||
'310000': '上海市',
|
||
'320000': '江苏省',
|
||
'330000': '浙江省',
|
||
'340000': '安徽省'
|
||
},
|
||
|
||
'array1|1': ['AMD', 'CMD', 'KMD', 'UMD'],
|
||
'array2|1-10': ['Mock.js'],
|
||
'array3|3': ['Mock.js'],
|
||
'array4|1-10': [{
|
||
'name|+1': ['Hello', 'Mock.js', '!']
|
||
}],
|
||
|
||
'function': function() {
|
||
return this.title
|
||
},
|
||
|
||
'regexp1': /[a-z][A-Z][0-9]/,
|
||
'regexp2': /\w\W\s\S\d\D/,
|
||
'regexp3': /\d{5,10}/,
|
||
|
||
'nested': {
|
||
a: {
|
||
b: {
|
||
c: 'Mock.js'
|
||
}
|
||
}
|
||
},
|
||
'absolutePath': '@/title @/nested/a/b/c',
|
||
'relativePath': {
|
||
a: {
|
||
b: {
|
||
c: '@../../../nested/a/b/c'
|
||
}
|
||
}
|
||
},
|
||
}
|
||
|
||
it('', function() {
|
||
var data = Mock.mock(tpl)
|
||
this.test.title += JSON.stringify(data /*, null, 4*/ )
|
||
expect(data).to.be.a('object')
|
||
})
|
||
})
|
||
}) |