diff --git a/README.md b/README.md index ca828e557..0927e45a9 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,25 @@ Thrown on failed validations, with the following properties validation chain. When the `abortEarly` option is `false` this is where you can inspect each error thrown, alternatively `errors` will have all the of the messages from each inner error. +#### `ref(String path, Object options)` + +Creates a reference to another sibling or sibling descendant field. Ref's are resolved +at _run time_ and supported where specified. Ref's are evaluated in in the proper order so that +the ref value is resolved before the field using the ref (be careful of circular dependencies!). + +```js +var schema = object({ + baz: ref('foo.bar'), + foo: object({ + bar: string() + }) + x: ref('$x') +}) + +inst.cast({ foo: { bar: 'boom' } }, { context: { x: 5 } }) +// { baz: 'boom', x: 5, { foo: { bar: 'boom' } }, } +``` + ### mixed @@ -365,7 +384,7 @@ schema.isValid(42) //=> false schema.isValid(new Date) //=> true ``` -#### `mixed.when(String key, Object options | Function func)` +#### `mixed.when(String|Array keys, Object options | Function func)` Adjust the schema based on a sibling or sibling children fields. You can provide an object literal where the key `is` is value or a matcher function, `then` provides the true schema and/or @@ -374,11 +393,8 @@ literal where the key `is` is value or a matcher function, `then` provides the t `is` conditions are strictly compared (`===`) if you want to use a different form of equality you can provide a function like: `is: (value) => value == true`. -Alternatively you can provide a function the returns a schema (called with the value of the key - and the current schema). `when` conditions are additive. - Like joi you can also prefix properties with `$` to specify a property that is dependent -on `context` passed in by `validate()` or `isValid`. +on `context` passed in by `validate()` or `isValid`. `when` conditions are additive. ```javascript var inst = yup.object({ @@ -397,6 +413,42 @@ var inst = yup.object({ inst.validate(value, { context: { other: 4 }}) ``` +You can also specify more than one dependent key, in which case each value will be spread as an argument. + +```javascript +var inst = yup.object({ + isSpecial: yup.bool() + isBig: yup.bool(), + count: yup.number() + .when(['isBig', 'isSpecial'], { + is: true, // alternatively: (isBig, isSpecial) => isBig && isSpecial + then: yup.number().min(5), + otherwise: yup.number().min(0) + }) + }) + +inst.validate({ + isBig: true, + isSpecial: true, + count: 10 +}) +``` + +Alternatively you can provide a function the returns a schema +(called with the value of the key and the current schema). + +```js +var inst = yup.object({ + isBig: yup.boolean(), + count: yup.number() + .when('isBig', (isBig, schema) => { + return isBig ? schema.min(5) : schema.min(0) + }) + }) + +inst.validate({ isBig: false, count: 4 }) +``` + #### `mixed.test(String name, String message, Function fn, [Bool callbackStyleAsync])` @@ -539,11 +591,11 @@ schema.isValid('hello') //=> true The same as the `mixed()` schema required, except that empty strings are also considered 'missing' values. To allow empty strings but fail on `undefined` values use: `string().required().min(0)` -#### `string.min(Number limit, [String message])` +#### `string.min(Number|Ref limit, [String message])` Set an minimum length limit for the string value. The `${min}` interpolation can be used in the `message` argument -#### `string.max(Number limit, [String message])` +#### `string.max(Number|Ref limit, [String message])` Set an maximum length limit for the string value. The `${max}` interpolation can be used in the `message` argument @@ -588,12 +640,12 @@ var schema = yup.number(); schema.isValid(10) //=> true ``` -#### `number.min(Number limit, [String message])` +#### `number.min(Number|Ref limit, [String message])` Set the minimum value allowed. The `${min}` interpolation can be used in the `message` argument. -#### `number.max(Number limit, [String message])` +#### `number.max(Number|Ref limit, [String message])` Set the maximum value allowed. The `${max}` interpolation can be used in the `message` argument. @@ -636,11 +688,11 @@ var schema = yup.date(); schema.isValid(new Date) //=> true ``` -#### `date.min(Date|String limit, [String message])` +#### `date.min(Date|String|Ref limit, [String message])` Set the minimum date allowed. -#### `date.max(Date|String limit, [String message])` +#### `date.max(Date|String|Ref limit, [String message])` Set the maximum date allowed. @@ -668,11 +720,11 @@ not validate its contents. The same as the `mixed()` schema required, except that empty arrays are also considered 'missing' values. To allow empty arrays but fail on `undefined` values use: `array().required().min(0)` -#### `array.min(Number limit, [String message])` +#### `array.min(Number|Ref limit, [String message])` Set an minimum length limit for the array. The `${min}` interpolation can be used in the `message` argument. -#### `array.max(Number limit, [String message])` +#### `array.max(Number|Ref limit, [String message])` Set an maximum length limit for the array. The `${max}` interpolation can be used in the `message` argument. diff --git a/package.json b/package.json index e1e1cedbe..75a5ba185 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,6 @@ "karma-jsdom-launcher": "^1.0.0", "karma-mocha": "^0.2.0", "karma-mocha-reporter": "^1.0.2", - "karma-phantomjs-launcher": "^0.2.0", "karma-sourcemap-loader": "^0.3.5", "karma-webpack": "^1.7.0", "mocha": "^1.21.4", diff --git a/src/array.js b/src/array.js index f52b10853..32acccabc 100644 --- a/src/array.js +++ b/src/array.js @@ -109,7 +109,9 @@ inherits(ArraySchema, MixedSchema, { name: 'min', exclusive: true, params: { min }, - test: value => isAbsent(value) || value.length >= min + test(value) { + return isAbsent(value) || value.length >= this.resolve(min) + } }) }, @@ -120,7 +122,9 @@ inherits(ArraySchema, MixedSchema, { name: 'max', exclusive: true, params: { max }, - test: value => isAbsent(value) || value.length <= max + test(value) { + return isAbsent(value) || value.length <= this.resolve(max) + } }) }, diff --git a/src/date.js b/src/date.js index 3eff59de7..4dc92d74f 100644 --- a/src/date.js +++ b/src/date.js @@ -42,7 +42,9 @@ inherits(DateSchema, MixedSchema, { exclusive: true, message: msg || locale.min, params: { min: min }, - test: value => isAbsent(value) || (value >= limit) + test(value) { + return isAbsent(value) || value >= this.resolve(limit) + } }) }, @@ -57,7 +59,9 @@ inherits(DateSchema, MixedSchema, { exclusive: true, message: msg || locale.max, params: { max: max }, - test: value => isAbsent(value) || (value <= limit) + test(value) { + return isAbsent(value) || value <= this.resolve(limit) + } }) } diff --git a/src/index.js b/src/index.js index 53b27df2d..b8bdab582 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,7 @@ 'use strict'; var mixed = require('./mixed') - , bool = require('./boolean'); + , bool = require('./boolean') + , Ref = require('./util/reference'); var isSchema = schema => schema && !!schema.__isYupSchema__; @@ -17,6 +18,7 @@ module.exports = { reach: require('./util/reach'), ValidationError: require('./util/validation-error'), + ref: (key, options) => new Ref(key, options), isSchema, diff --git a/src/mixed.js b/src/mixed.js index 0085920bb..9cc540fc6 100644 --- a/src/mixed.js +++ b/src/mixed.js @@ -2,13 +2,13 @@ var Promise = require('promise/lib/es6-extensions') , Condition = require('./util/condition') - , ValidationError = require('./util/validation-error') , locale = require('./locale.js').mixed , _ = require('./util/_') , isAbsent = require('./util/isAbsent') , cloneDeep = require('./util/clone') , createValidation = require('./util/createValidation') - , BadSet = require('./util/set'); + , BadSet = require('./util/set') + , Ref = require('./util/reference'); let notEmpty = value => !isAbsent(value); @@ -25,6 +25,7 @@ function SchemaType(options = {}){ return new SchemaType() this._deps = [] + this._conditions = [] this._options = { abortEarly: true, recursive: true } this._exclusive = Object.create(null) this._whitelist = new BadSet() @@ -100,9 +101,9 @@ SchemaType.prototype = { return !this._typeCheck || this._typeCheck(v) }, - cast(_value, _opts) { - var schema = this._resolve((_opts || {}).context) - return schema._cast(_value, _opts) + cast(value, opts = {}) { + var schema = this._resolve(opts.context, opts.parent) + return schema._cast(value, opts) }, _cast(_value) { @@ -116,9 +117,9 @@ SchemaType.prototype = { return value }, - _resolve(context, parent){ - if (this._deps.length) { - return this._deps.reduce((schema, match) => + _resolve(context, parent) { + if (this._conditions.length) { + return this._conditions.reduce((schema, match) => match.resolve(schema, match.getValue(parent, context)), this) } @@ -186,7 +187,7 @@ SchemaType.prototype = { }, default(def) { - if( arguments.length === 0){ + if (arguments.length === 0) { var dflt = _.has(this, '_default') ? this._default : this._defaultDefault return typeof dflt === 'function' ? dflt.call(this) : cloneDeep(dflt) @@ -277,11 +278,16 @@ SchemaType.prototype = { return next }, - when(key, options){ + when(keys, options) { var next = this.clone() - , dep = new Condition(key, next._type, options); + , deps = [].concat(keys).map(key => new Ref(key)); - next._deps.push(dep) + deps.forEach(dep => { + if (!dep.isContext) + next._deps.push(dep.key) + }) + + next._conditions.push(new Condition(deps, options)) return next }, @@ -295,7 +301,9 @@ SchemaType.prototype = { test(value) { if (value !== undefined && !this.schema.isType(value)) return this.createError({ - params: { type: this.schema._type } + params: { + type: this.schema._type + } }) return true } @@ -320,7 +328,11 @@ SchemaType.prototype = { test(value) { let valids = this.schema._whitelist if (valids.length && !(valids.has(value) || isAbsent(value))) - return this.createError({ params: { values: valids.values().join(', ') }}) + return this.createError({ + params: { + values: valids.values().join(', ') + } + }) return true } }) @@ -342,7 +354,11 @@ SchemaType.prototype = { test(value) { let invalids = this.schema._blacklist if (invalids.length && invalids.has(value)) - return this.createError({ params: { values: invalids.values().join(', ') }}) + return this.createError({ + params: { + values: invalids.values().join(', ') + } + }) return true } }) diff --git a/src/number.js b/src/number.js index 918a3c151..5ea70890d 100644 --- a/src/number.js +++ b/src/number.js @@ -39,7 +39,9 @@ inherits(NumberSchema, SchemaObject, { exclusive: true, params: { min }, message: msg || locale.min, - test: value => isAbsent(value) || value >= min + test(value) { + return isAbsent(value) || value >= this.resolve(min) + } }) }, @@ -49,7 +51,9 @@ inherits(NumberSchema, SchemaObject, { exclusive: true, params: { max }, message: msg || locale.max, - test: value => isAbsent(value) || value <= max + test(value) { + return isAbsent(value) || value <= this.resolve(max) + } }) }, diff --git a/src/object.js b/src/object.js index 0ab690fcb..368d10bb6 100644 --- a/src/object.js +++ b/src/object.js @@ -4,6 +4,7 @@ var MixedSchema = require('./mixed') , toposort = require('toposort') , locale = require('./locale.js').object , split = require('property-expr').split + , Ref = require('./util/reference') , c = require('case') , { isObject @@ -11,7 +12,7 @@ var MixedSchema = require('./mixed') , assign , inherits , collectErrors - , has } = require('./util/_'); + , isSchema, has } = require('./util/_'); let isRecursive = schema => (schema._subType || schema) === '$this' @@ -23,11 +24,9 @@ c.type('altCamel', function(str) { }) let childSchema = (field, parent) => { - return isRecursive(field) - ? field.of - ? field.of(parent) - : parent - : field + if (!isRecursive(field)) return field + + return field.of ? field.of(parent) : parent } let scopeError = value => err => { @@ -78,7 +77,7 @@ inherits(ObjectSchema, MixedSchema, { return isObject(value) || typeof value === 'function'; }, - _cast(_value, _opts) { + _cast(_value, _opts = {}) { var schema = this , value = MixedSchema.prototype._cast.call(schema, _value) @@ -92,28 +91,43 @@ inherits(ObjectSchema, MixedSchema, { , props = schema._nodes.concat(extra); schema.withMutation(() => { - let innerOptions = { ..._opts, context: {} }; + let innerOptions = { ..._opts, parent: {} }; + + value = transform(props, function(obj, prop) { - var exists = has(value, prop); + let field = fields[prop] + let exists = has(value, prop); + + if (Ref.isRef(field)) { + let refValue = field.getValue(obj, innerOptions.context) + + if (refValue !== undefined) + obj[prop] = refValue + } + else if (exists && field) { + // ugly optimization avoiding a clone. clears default for recursive + // cast and resets it below; + let hasDflt = has(schema, '_default') + , dflt = schema._default; - if (exists && fields[prop]) { - var fieldSchema = childSchema(fields[prop], schema.default(undefined)) + let fieldSchema = childSchema(field, schema.default(undefined)) obj[prop] = fieldSchema.cast(value[prop], innerOptions) + + if (hasDflt) schema.default(dflt) + else delete schema._default } else if (exists && !strip) obj[prop] = value[prop] - else if(fields[prop]) { - var fieldDefault = fields[prop].default ? fields[prop].default() : undefined + else if (field) { + var fieldDefault = field.default ? field.default() : undefined if (fieldDefault !== undefined) obj[prop] = fieldDefault } - }, innerOptions.context) - - delete schema._default + }, innerOptions.parent) }) return value @@ -243,21 +257,25 @@ function sortFields(fields, excludes = []){ var edges = [], nodes = [] for (var key in fields) if (has(fields, key)) { - if (!~nodes.indexOf(key)) nodes.push(key) + let value = fields[key]; - fields[key]._deps && - fields[key]._deps.forEach(dep => { //eslint-disable-line no-loop-func - if (dep.isContext) - return + if (!~nodes.indexOf(key)) + nodes.push(key) - var node = split(dep.key)[0] + let addNode = depPath => { //eslint-disable-line no-loop-func + var node = split(depPath)[0] - if (!~nodes.indexOf(node)) - nodes.push(node) + if (!~nodes.indexOf(node)) + nodes.push(node) - if (!~excludes.indexOf(`${key}-${node}`)) - edges.push([key, node]) - }) + if (!~excludes.indexOf(`${key}-${node}`)) + edges.push([key, node]) + } + + if (Ref.isRef(value) && !value.isContext) + addNode(value.path) + else if (isSchema(value)) + value._deps.forEach(addNode) } return toposort.array(nodes, edges).reverse() diff --git a/src/string.js b/src/string.js index 3b68a14c0..549384889 100644 --- a/src/string.js +++ b/src/string.js @@ -33,7 +33,7 @@ inherits(StringSchema, MixedSchema, { return (typeof value === 'string') || (typeof value === 'object' && value instanceof String) }, - required(msg){ + required(msg) { var next = MixedSchema.prototype.required.call(this, msg || mixed.required ) return next.test( @@ -43,27 +43,31 @@ inherits(StringSchema, MixedSchema, { ) }, - min(min, msg){ + min(min, msg) { return this.test({ name: 'min', exclusive: true, message: msg || locale.min, params: { min }, - test: value => isAbsent(value) || value.length >= min + test(value) { + return isAbsent(value) || value.length >= this.resolve(min) + } }) }, - max(max, msg){ + max(max, msg) { return this.test({ name: 'max', exclusive: true, message: msg || locale.max, params: { max }, - test: value => isAbsent(value) || value.length <= max + test(value) { + return isAbsent(value) || value.length <= this.resolve(max) + } }) }, - matches(regex, msg){ + matches(regex, msg) { return this.test({ message: msg || locale.matches, params: { regex }, @@ -71,16 +75,16 @@ inherits(StringSchema, MixedSchema, { }) }, - email(msg){ + email(msg) { return this.matches(rEmail, msg || locale.email); }, - url(msg){ + url(msg) { return this.matches(rUrl, msg || locale.url); }, //-- transforms -- - trim(msg){ + trim(msg) { msg = msg || locale.trim return this @@ -88,7 +92,7 @@ inherits(StringSchema, MixedSchema, { .test('trim', msg, isTrimmed) }, - lowercase(msg){ + lowercase(msg) { return this .transform(value => !isAbsent(value) ? value.toLowerCase() : value) .test({ diff --git a/src/util/condition.js b/src/util/condition.js index 15e48e7f1..de701a95a 100644 --- a/src/util/condition.js +++ b/src/util/condition.js @@ -1,47 +1,44 @@ 'use strict'; -var { has, isSchema } = require('./_') - , getter = require('property-expr').getter +var { transform, has, isSchema } = require('./_') module.exports = Conditional class Conditional { - constructor(key, type, options){ - let { is, then, otherwise } = options - , prefix = options.contextPrefix || '$'; + constructor(refs, options) { + let { is, then, otherwise } = options; - this.prefix = prefix; - this.key = key - this.isContext = key.indexOf(prefix) === 0 + this.refs = [].concat(refs) - if ( typeof options === 'function') + if (typeof options === 'function') this.fn = options else { - if( !has(options, 'is') ) + if (!has(options, 'is')) throw new TypeError('`is:` is required for `when()` conditions') - if( !options.then && !options.otherwise ) + if (!options.then && !options.otherwise) throw new TypeError('either `then:` or `otherwise:` is required for `when()` conditions') - is = typeof is === 'function' - ? is : ((is, value) => is === value).bind(null, is) - this.fn = (value, ctx) => is(value) ? ctx.concat(then) : ctx.concat(otherwise) + let isFn = typeof is === 'function' + ? is : ((...values) => values.every(value => value === is)) + + this.fn = function (...values) { + let ctx = values.pop(); + return isFn(...values) ? ctx.concat(then) : ctx.concat(otherwise) + } } } - getValue(parent, context){ - var path = this.isContext ? this.key.slice(this.prefix.length) : this.key - - if ( (this.isContext && !context) || (!this.isContext && !context && !parent)) - throw new Error('missing the context necessary to cast this value') + getValue(parent, context) { + let values = this.refs.map(r => r.getValue(parent, context)) - return getter(path)(this.isContext ? context : (parent || context) ) + return values } - resolve(ctx, value) { - let schema = this.fn.call(ctx, value, ctx) + resolve(ctx, values) { + let schema = this.fn.apply(ctx, values.concat(ctx)) if (schema !== undefined && !isSchema(schema)) throw new TypeError('conditions must return a schema object') diff --git a/src/util/createValidation.js b/src/util/createValidation.js index 11ae94be1..ec588a5cf 100644 --- a/src/util/createValidation.js +++ b/src/util/createValidation.js @@ -1,13 +1,27 @@ 'use strict'; var Promise = require('promise/lib/es6-extensions') - , ValidationError = require('./validation-error'); + , ValidationError = require('./validation-error') + , Ref = require('./reference') + , { transform } = require('./_'); let formatError = ValidationError.formatError -function createErrorFactory(orginalMessage, orginalPath, value, orginalParams, originalType, label) { - return function createError({ path = orginalPath, message = orginalMessage, type = originalType, params } = {}) { +function resolveParams(oldParams, newParams, resolve) { + let start = { ...oldParams, ...newParams } + return transform(start, (obj, value, key) => { + obj[key] = resolve(value) + }) +} + +function createErrorFactory({ value, label, resolve, ...opts}) { + return function createError({ path = opts.path, message = opts.message, type = opts.name, params } = {}) { + params = resolveParams(opts.params, params, resolve) + return new ValidationError( - formatError(message, { path, value, label, ...orginalParams, ...params }), value, path, type) + formatError(message, { path, value, label, ...params }) + , value + , path + , type) } } @@ -15,8 +29,16 @@ module.exports = function createValidation(options) { let { name, message, test, params, useCallback } = options function validate({ value, path, label, state: { parent }, ...rest }) { - var createError = createErrorFactory(message, path, value, params, name, label) - var ctx = { path, parent, createError, type: name, ...rest } + var resolve = (value) => Ref.isRef(value) + ? value.getValue(parent, rest.options.context) + : value + + var createError = createErrorFactory({ + message, path, value, params + , label, resolve, name + }) + + var ctx = { path, parent, type: name, createError, resolve, ...rest } return new Promise((resolve, reject) => { !useCallback diff --git a/src/util/reference.js b/src/util/reference.js index c75719815..2af39d3f7 100644 --- a/src/util/reference.js +++ b/src/util/reference.js @@ -1,13 +1,36 @@ +var getter = require('property-expr').getter +let validateName = d => { + if (typeof d !== 'string') + throw new TypeError('ref\'s must be strings, got: ' + d) +} -class Reference { - constructor(string) { - this._deps = [] +export default class Ref { + static isRef(value) { + return !!(value && (value.__isYupRef || value instanceof Ref)) } - default() {} - - cast(value, parent, options){ - return parent.default(undefined).cast(value, options) + constructor(key, mapFn, options = {}) { + validateName(key) + let prefix = options.contextPrefix || '$'; + + this.key = key; + this.prefix = prefix; + this.isContext = key.indexOf(prefix) === 0 + this.path = this.isContext ? this.key.slice(this.prefix.length) : this.key + this.map = mapFn || (value => value); } -} \ No newline at end of file + + getValue(parent, context) { + let isContext = this.isContext + + if ((isContext && !context) || (!isContext && !context && !parent)) + throw new Error('missing the context necessary to cast this value') + + let value = getter(this.path)(isContext ? context : (parent || context)) + + return this.map(value) + } +} + +Ref.prototype.__isYupRef = true diff --git a/src/util/set.js b/src/util/set.js index bcde6b03b..6c14475fc 100644 --- a/src/util/set.js +++ b/src/util/set.js @@ -1,9 +1,10 @@ -var hasOwnProperty = Object.prototype.hasOwnProperty +var { has } = require('./_') module.exports = class BadSet { constructor(){ this._map = Object.create(null) + this._refs = Object.create(null) } values(){ @@ -23,7 +24,7 @@ module.exports = class BadSet { } has(item){ - return hasOwnProperty.call(this._map, stringify(item)) + return has(this._map, stringify(item)) } } diff --git a/test/mixed.js b/test/mixed.js index fd09001da..4a43a0a3a 100644 --- a/test/mixed.js +++ b/test/mixed.js @@ -410,6 +410,29 @@ describe( 'Mixed Types ', function(){ }) }) + it('should handle multiple conditionals', function() { + let called = false + var inst = mixed() + .when(['prop', 'other'], function(prop, other) { + other.should.equal(true) + prop.should.equal(1) + called = true + }) + + inst.cast({}, { context: { prop: 1, other: true }}) + called.should.equal(true) + + inst = mixed().when(['prop', 'other'], { + is: 5, + then: mixed().required() + }) + + return inst + .isValid(undefined, { context: { prop: 5, other: 5 }}) + .should.eventually.equal(false) + + }) + it('should require context when needed', function(){ var inst = mixed() .when('$prop', { is: 5, then: mixed().required('from context') }) @@ -442,17 +465,17 @@ describe( 'Mixed Types ', function(){ inst.default().should.eql({ prop: undefined }) }) - it('should use label in error message', function () { - var label = 'Label' - var inst = object({ - prop: string().required().label(label) - }) + it('should use label in error message', function () { + var label = 'Label' + var inst = object({ + prop: string().required().label(label) + }) - return Promise.all([ - inst.validate({}).should.be.rejected.then(function (err) { - err.message.should.equal(`${label} is a required field`) - }) - ]) + return Promise.all([ + inst.validate({}).should.be.rejected.then(function (err) { + err.message.should.equal(`${label} is a required field`) + }) + ]) }) }) diff --git a/test/object.js b/test/object.js index 84b326bfb..f3813e3a7 100644 --- a/test/object.js +++ b/test/object.js @@ -3,13 +3,10 @@ var chai = require('chai') , chaiAsPromised = require('chai-as-promised') , Promise = require('promise/src/es6-extensions') - , mixed = require('../src/mixed') - , string = require('../src/string') - , date = require('../src/date') - , number = require('../src/number') - , bool = require('../src/boolean') - , array = require('../src/array') - , object = require('../src/object'); + , { + mixed, string, date, number + , bool, array, object, ref + } = require('../src'); chai.use(chaiAsPromised); chai.should(); @@ -248,6 +245,27 @@ describe('Object types', function(){ }) }) + it('should allow refs', function() { + var schema = object({ + quz: ref('baz'), + baz: ref('foo.bar'), + foo: object({ + bar: string() + }), + x: ref('$x') + }) + + schema.cast({ foo: { bar: 'boom' } }, { context: { x: 5 } }) + .should.eql({ + foo: { + bar: 'boom' + }, + baz: 'boom', + quz: 'boom', + x: 5 + }) + }) + it('should allow nesting with "$this"', function(){ var inst = object().shape({ child: '$this', diff --git a/test/string.js b/test/string.js index 2cdeaa2a7..0146afae3 100644 --- a/test/string.js +++ b/test/string.js @@ -4,7 +4,7 @@ var chai = require('chai') , Promise = require('promise/src/es6-extensions') , sinonChai = require('sinon-chai') , chaiAsPromised = require('chai-as-promised') - , string = require('../src/string'); + , { string, number, object, ref } = require('../src'); chai.use(chaiAsPromised); chai.use(sinonChai); @@ -89,6 +89,10 @@ describe('String types', function(){ it('should check MIN correctly', function(){ var v = string().min(5); + var obj = object({ + len: number(), + name: string().min(ref('len')) + }) return Promise.all([ v.isValid('hiiofff').should.eventually.equal(true), @@ -96,14 +100,19 @@ describe('String types', function(){ v.isValid('noffasfasfasf saf').should.eventually.equal(true), v.isValid(null).should.eventually.equal(false), // null -> '' - v.nullable().isValid(null).should.eventually.equal(true) // null -> null + v.nullable().isValid(null).should.eventually.equal(true), // null -> null + + obj.isValid({ len: 10, name: 'john' }).should.eventually.equal(false) ]) }) it('should check MAX correctly', function(){ var v = string().max(5); - + var obj = object({ + len: number(), + name: string().max(ref('len')) + }) return Promise.all([ v.isValid('adgf').should.eventually.equal(true), v.isValid('bigdfdsfsdf').should.eventually.equal(false), @@ -114,7 +123,9 @@ describe('String types', function(){ v.isValid(null).should.eventually.equal(true), - v.nullable().isValid(null).should.eventually.equal(true) + v.nullable().isValid(null).should.eventually.equal(true), + + obj.isValid({ len: 3, name: 'john' }).should.eventually.equal(false) ]) })