From 64d71c436bd80380b7093c388db86cab73626a5e Mon Sep 17 00:00:00 2001 From: Nicolas Morel Date: Wed, 11 Sep 2019 18:08:33 +0200 Subject: [PATCH] Use helper in tests (1st part) --- .eslintignore | 1 + test/base.js | 367 +++++++++++++++++++++-------------------- test/compile.js | 2 +- test/helper.js | 5 +- test/types/boolean.js | 32 ++-- test/types/date.js | 110 ++++++------ test/types/function.js | 182 +++++++++----------- test/types/number.js | 66 ++++---- test/types/object.js | 300 +++++++++++++++------------------ test/types/string.js | 138 ++++++---------- test/types/symbol.js | 8 +- 11 files changed, 574 insertions(+), 637 deletions(-) diff --git a/.eslintignore b/.eslintignore index 430a9bfb6..9bbba5775 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,5 @@ browser +dist examples sandbox.js /benchmarks/node_modules diff --git a/test/base.js b/test/base.js index 05efd73e3..a0925ceca 100755 --- a/test/base.js +++ b/test/base.js @@ -974,7 +974,7 @@ describe('any', () => { }; const schema = Joi.function().default(defaultGeneratorFn); - expect(schema.validate(undefined)).to.equal({ value: defaultFn }); + Helper.validate(schema, [[undefined, true, defaultFn]]); }); it('allows passing a ref as a default without a description', () => { @@ -984,7 +984,7 @@ describe('any', () => { b: Joi.string().default(Joi.ref('a')) }); - expect(schema.validate({ a: 'test' })).to.equal({ value: { a: 'test', b: 'test' } }); + Helper.validate(schema, [[{ a: 'test' }, true, { a: 'test', b: 'test' }]]); }); it('ignores description when passing a ref as a default', () => { @@ -994,7 +994,7 @@ describe('any', () => { b: Joi.string().default(Joi.ref('a')) }); - expect(schema.validate({ a: 'test' })).to.equal({ value: { a: 'test', b: 'test' } }); + Helper.validate(schema, [[{ a: 'test' }, true, { a: 'test', b: 'test' }]]); }); it('catches errors in default methods', () => { @@ -1009,21 +1009,21 @@ describe('any', () => { const schema = Joi.string().default(defaultFn); - const err = schema.validate(undefined).error; - expect(err.details).to.have.length(1); - expect(err.details).to.equal([{ - message: '"value" threw an error when running default method', - path: [], - type: 'any.default', - context: { error, label: 'value', value: null } - }]); + Helper.validate(schema, [ + [undefined, false, { + message: '"value" threw an error when running default method', + path: [], + type: 'any.default', + context: { error, label: 'value', value: null } + }] + ]); }); it('should not overide a value when value is given', () => { const schema = Joi.object({ foo: Joi.string().default('bar') }); const input = { foo: 'test' }; - expect(schema.validate(input)).to.equal({ value: { foo: 'test' } }); + Helper.validate(schema, [[input, true, { foo: 'test' }]]); }); it('sets value based on condition (outer)', () => { @@ -1035,7 +1035,7 @@ describe('any', () => { .when('a', { is: true, then: Joi.required(), otherwise: Joi.forbidden() }) }); - expect(schema.validate({ a: false })).to.equal({ value: { a: false, b: false } }); + Helper.validate(schema, [[{ a: false }, true, { a: false, b: false }]]); }); it('sets value based on condition (inner)', () => { @@ -1045,7 +1045,7 @@ describe('any', () => { b: Joi.boolean().when('a', { is: true, then: Joi.any().default(false), otherwise: Joi.forbidden() }) }); - expect(schema.validate({ a: true })).to.equal({ value: { a: true, b: false } }); + Helper.validate(schema, [[{ a: true }, true, { a: true, b: false }]]); }); it('creates deep defaults', () => { @@ -1096,7 +1096,7 @@ describe('any', () => { }); const input = { b: 42 }; - expect(schema.validate(input, { noDefaults: true })).to.equal({ value: { b: 42 } }); + Helper.validate(schema, { noDefaults: true }, [[input, true, { b: 42 }]]); }); it('should not apply default values from functions if the noDefaults option is enquire', () => { @@ -1114,7 +1114,7 @@ describe('any', () => { }); const input = { b: 42 }; - expect(schema.validate(input, { noDefaults: true })).to.equal({ value: { b: 42 } }); + Helper.validate(schema, { noDefaults: true }, [[input, true, { b: 42 }]]); }); it('should not apply default values from references if the noDefaults option is enquire', () => { @@ -1125,7 +1125,7 @@ describe('any', () => { }); const input = { b: 42 }; - expect(schema.validate(input, { noDefaults: true })).to.equal({ value: { b: 42 } }); + Helper.validate(schema, { noDefaults: true }, [[input, true, { b: 42 }]]); }); it('should be able to support both empty and noDefaults', () => { @@ -1136,7 +1136,7 @@ describe('any', () => { }); const input = { a: 'foo', b: 42 }; - expect(schema.validate(input, { noDefaults: true })).to.equal({ value: { b: 42 } }); + Helper.validate(schema, { noDefaults: true }, [[input, true, { b: 42 }]]); }); }); @@ -1627,9 +1627,11 @@ describe('any', () => { const schema = Joi.object({ x: Joi.number().default(1).failover(2) }); - expect(schema.validate({})).to.equal({ value: { x: 1 } }); - expect(schema.validate({ x: 3 })).to.equal({ value: { x: 3 } }); - expect(schema.validate({ x: [] })).to.equal({ value: { x: 2 } }); + Helper.validate(schema, [ + [{}, true, { x: 1 }], + [{ x: 3 }, true, { x: 3 }], + [{ x: [] }, true, { x: 2 }] + ]); }); }); @@ -1692,8 +1694,8 @@ describe('any', () => { it('preserves passed value when cloned', () => { const o = {}; - expect(Joi.object().invalid(o).clone().validate(o).error).to.be.an.error('"value" contains an invalid value'); - expect(Joi.object().invalid({}).clone().validate({}).error).to.be.an.error('"value" contains an invalid value'); + Helper.validate(Joi.object().invalid(o).clone(), [[o, false, '"value" contains an invalid value']]); + Helper.validate(Joi.object().invalid({}).clone(), [[{}, false, '"value" contains an invalid value']]); }); it('errors on blocked schema', () => { @@ -1716,15 +1718,19 @@ describe('any', () => { it('overrides previous values', () => { const schema = Joi.number().invalid(2).invalid(Joi.override, 1); - expect(schema.validate(1).error).to.be.an.error('"value" contains an invalid value'); - expect(schema.validate(2).error).to.not.exist(); + Helper.validate(schema, [ + [1, false , '"value" contains an invalid value'], + [2, true, 2] + ]); }); it('cancels previous values', () => { const schema = Joi.number().invalid(2).invalid(Joi.override); - expect(schema.validate(1).error).to.not.exist(); - expect(schema.validate(2).error).to.not.exist(); + Helper.validate(schema, [ + [1, true, 1], + [2, true, 2] + ]); }); it('ignores empty override', () => { @@ -1742,7 +1748,7 @@ describe('any', () => { .min(10).keep() .min(100); - expect(schema.validate(1, { abortEarly: false }).error).to.be.an.error('"value" must be larger than or equal to 10. "value" must be larger than or equal to 100'); + Helper.validate(schema, { abortEarly: false }, [[1, false, '"value" must be larger than or equal to 10. "value" must be larger than or equal to 100']]); }); it('retains both unique rule instances in concat', () => { @@ -1751,7 +1757,7 @@ describe('any', () => { .min(10).keep() .concat(Joi.number().min(100)); - expect(schema.validate(1, { abortEarly: false }).error).to.be.an.error('"value" must be larger than or equal to 10. "value" must be larger than or equal to 100'); + Helper.validate(schema, { abortEarly: false }, [[1, false, '"value" must be larger than or equal to 10. "value" must be larger than or equal to 100']]); }); }); @@ -1761,13 +1767,12 @@ describe('any', () => { const schema = Joi.object({ b: Joi.string().email().label('Custom label') }); const input = { b: 'not_a_valid_email' }; - const err = schema.validate(input).error; - expect(err.details[0]).to.equal({ + Helper.validate(schema, [[input, false, { message: '"Custom label" must be a valid email', path: ['b'], type: 'string.email', context: { value: 'not_a_valid_email', invalids: ['not_a_valid_email'], label: 'Custom label', key: 'b' } - }); + }]]); }); it('throws when label is missing', () => { @@ -1787,14 +1792,12 @@ describe('any', () => { it('does not leak into sub objects', () => { const schema = Joi.object({ a: Joi.number() }).label('foo'); - const err = schema.validate({ a: 'a' }).error; - expect(err).to.be.an.error('"a" must be a number'); - expect(err.details).to.equal([{ + Helper.validate(schema, [[{ a: 'a' }, false, { message: '"a" must be a number', path: ['a'], type: 'number.base', context: { label: 'a', key: 'a', value: 'a' } - }]); + }]]); }); it('does not leak into sub objects from an array', () => { @@ -1803,27 +1806,23 @@ describe('any', () => { Joi.object({ a: Joi.number() }).label('foo') ).label('bar'); - const err = schema.validate([{ a: 'a' }]).error; - expect(err).to.be.an.error('"[0].a" must be a number'); - expect(err.details).to.equal([{ + Helper.validate(schema, [[[{ a: 'a' }], false, { message: '"[0].a" must be a number', path: [0, 'a'], type: 'number.base', context: { label: '[0].a', key: 'a', value: 'a' } - }]); + }]]); }); it('does not leak into unknown keys', () => { const schema = Joi.object({ a: Joi.number() }).label('foo'); - const err = schema.validate({ b: 'a' }).error; - expect(err).to.be.an.error('"b" is not allowed'); - expect(err.details).to.equal([{ + Helper.validate(schema, [[{ b: 'a' }, false, { message: '"b" is not allowed', path: ['b'], type: 'object.unknown', context: { child: 'b', label: 'b', key: 'b', value: 'a' } - }]); + }]]); }); it('applies only to hierarchy edge', () => { @@ -1836,16 +1835,12 @@ describe('any', () => { }).label('A') }); - const err = schema.validate({ a: { b: { c: 'x' } } }).error; - expect(err).to.be.an.error('"C" must be a number'); - expect(err.details).to.equal([ - { - message: '"C" must be a number', - path: ['a', 'b', 'c'], - type: 'number.base', - context: { label: 'C', value: 'x', key: 'c' } - } - ]); + Helper.validate(schema, [[{ a: { b: { c: 'x' } } }, false, { + message: '"C" must be a number', + path: ['a', 'b', 'c'], + type: 'number.base', + context: { label: 'C', value: 'x', key: 'c' } + }]]); }); }); @@ -1857,8 +1852,10 @@ describe('any', () => { .min(10).message('way too small') .max(100).message('way too big'); - expect(schema.validate(1).error).to.be.an.error('way too small'); - expect(schema.validate(1000).error).to.be.an.error('way too big'); + Helper.validate(schema, [ + [1, false, 'way too small'], + [1000, false, 'way too big'] + ]); }); it('overrides message with template', () => { @@ -1866,7 +1863,7 @@ describe('any', () => { const schema = Joi.number() .min(10).message(Joi.x('way too small')); - expect(schema.validate(1).error).to.be.an.error('way too small'); + Helper.validate(schema, [[1, false, 'way too small']]); }); it('overrides message in multiple language', () => { @@ -1918,7 +1915,7 @@ describe('any', () => { }; const schema = Joi.object({ a: Joi.number().min(10).message(messages) }); - expect(schema.validate({ a: 1 }).error).to.be.an.error('a angustus'); + Helper.validate(schema, [[{ a: 1 }, false, 'a angustus']]); }); it('overrides message in multiple language (flat template)', () => { @@ -1929,7 +1926,7 @@ describe('any', () => { }; const schema = Joi.object({ a: Joi.number().min(10).message(messages) }); - expect(schema.validate({ a: 1 }).error).to.be.an.error('a angustus'); + Helper.validate(schema, [[{ a: 1 }, false, 'a angustus']]); }); it('errors on invalid message value', () => { @@ -2003,9 +2000,11 @@ describe('any', () => { const schema = Joi.number().allow(1, 'x').only(); - expect(schema.validate(1).error).to.not.exist(); - expect(schema.validate('x').error).to.not.exist(); - expect(schema.validate(2).error).to.be.an.error('"value" must be one of [1, x]'); + Helper.validate(schema, [ + [1, true], + ['x', true], + [2, false, '"value" must be one of [1, x]'] + ]); }); }); @@ -2082,7 +2081,7 @@ describe('any', () => { const schema = Joi.object({ b: Joi.number().strict().prefs({ convert: true }) }); const input = { b: '2' }; - expect(schema.validate(input)).to.equal({ value: { b: 2 } }); + Helper.validate(schema, [[input, true, { b: 2 }]]); }); it('throws with an invalid option', () => { @@ -2169,14 +2168,14 @@ describe('any', () => { for (const test of tests) { const input = test[1]; const schema = test[0].raw(); - expect(schema.raw().validate(input)).to.equal({ value: input }); + Helper.validate(schema.raw(), [[input, true, input]]); } }); it('cancels raw mode', () => { const schema = Joi.number().raw().raw(false); - expect(schema.validate('123')).to.equal({ value: 123 }); + Helper.validate(schema, [['123', true, 123]]); }); it('avoids unnecessary cloning when called twice', () => { @@ -2232,8 +2231,10 @@ describe('any', () => { .min(10).rule({ message: 'way too small', keep: true }) .min(100).message('still too small'); - expect(schema.validate(1).error).to.be.an.error('way too small'); - expect(schema.validate(90).error).to.be.an.error('still too small'); + Helper.validate(schema, [ + [1, false, 'way too small'], + [90, false, 'still too small'] + ]); }); }); @@ -2249,15 +2250,19 @@ describe('any', () => { it('overrides ruleset with single message', () => { const schema = Joi.number().$.max(100).min(10).rule({ message: 'number out of bound' }); - expect(schema.validate(1).error).to.be.an.error('number out of bound'); - expect(schema.validate(101).error).to.be.an.error('number out of bound'); + Helper.validate(schema, [ + [1, false, 'number out of bound'], + [101, false, 'number out of bound'] + ]); }); it('overrides ruleset messages', () => { const schema = Joi.number().$.max(100).min(10).rule({ message: { 'number.max': 'way too big', 'number.min': 'way too small' } }); - expect(schema.validate(1).error).to.be.an.error('way too small'); - expect(schema.validate(101).error).to.be.an.error('way too big'); + Helper.validate(schema, [ + [1, false, 'way too small'], + [101, false, 'way too big'] + ]); }); it('overrides template', () => { @@ -2270,22 +2275,28 @@ describe('any', () => { it('overrides ruleset with single template', () => { const schema = Joi.number().$.max(100).min(10).rule({ message: '{{#label}} number out of bound' }); - expect(schema.validate(1).error).to.be.an.error('value number out of bound'); - expect(schema.validate(101).error).to.be.an.error('value number out of bound'); + Helper.validate(schema, [ + [1, false, 'value number out of bound'], + [101, false, 'value number out of bound'] + ]); }); it('overrides ruleset templates', () => { const schema = Joi.number().$.max(100).min(10).rule({ message: { 'number.max': '{{#label}} way too big', 'number.min': '{{#label}} way too small' } }); - expect(schema.validate(1).error).to.be.an.error('value way too small'); - expect(schema.validate(101).error).to.be.an.error('value way too big'); + Helper.validate(schema, [ + [1, false, 'value way too small'], + [101, false, 'value way too big'] + ]); }); it('overrides ruleset with both message and template', () => { const schema = Joi.number().$.max(100).min(10).rule({ message: { 'number.max': 'way too big', 'number.min': '{{#label}} way too small' } }); - expect(schema.validate(1).error).to.be.an.error('value way too small'); - expect(schema.validate(101).error).to.be.an.error('way too big'); + Helper.validate(schema, [ + [1, false, 'value way too small'], + [101, false, 'way too big'] + ]); }); }); }); @@ -2353,14 +2364,12 @@ describe('any', () => { const schema = Joi.object({ b: Joi.number().prefs({ convert: true }).strict() }); const input = { b: '2' }; - const err = schema.validate(input).error; - expect(err.message).to.equal('"b" must be a number'); - expect(err.details).to.equal([{ + Helper.validate(schema, [[input, false, { message: '"b" must be a number', path: ['b'], type: 'number.base', context: { label: 'b', key: 'b', value: '2' } - }]); + }]]); }); }); @@ -2369,21 +2378,19 @@ describe('any', () => { it('validates and returns undefined', () => { const schema = Joi.string().strip(); - expect(schema.validate('test')).to.equal({ value: undefined }); + Helper.validate(schema, [['test', true, undefined]]); }); it('validates and returns an error', () => { const schema = Joi.string().strip(); - const err = schema.validate(1).error; - expect(err.message).to.equal('"value" must be a string'); - expect(err.details).to.equal([{ + Helper.validate(schema, [[1, false, { message: '"value" must be a string', path: [], type: 'string.base', context: { value: 1, label: 'value' } - }]); + }]]); }); it('avoids unnecessary cloning when called twice', () => { @@ -2539,75 +2546,81 @@ describe('any', () => { it('validates different types of values', () => { - expect(Joi.valid(1).validate(1).error).to.not.exist(); - expect(Joi.valid(1).validate(2).error).to.exist(); + Helper.validate(Joi.valid(1), [[1, true]]); + Helper.validate(Joi.valid(1), [[2, false, '"value" must be [1]']]); const d = new Date(); - expect(Joi.valid(d).validate(new Date(d.getTime())).error).to.not.exist(); - expect(Joi.valid(d).validate(new Date(d.getTime() + 1)).error).to.be.an.error(`"value" must be [${d.toISOString()}]`); - expect(Joi.valid(d).validate(new Date(d.getTime() + 1)).error.details).to.equal([{ - message: `"value" must be [${d.toISOString()}]`, - path: [], - type: 'any.only', - context: { value: new Date(d.getTime() + 1), valids: [d], label: 'value' } - }]); - expect(Joi.valid(Joi.ref('$a')).validate(d, { context: { a: new Date(d.getTime()) } }).error).to.not.exist(); - expect(Joi.object({ a: Joi.date(), b: Joi.valid(Joi.ref('a')) }).validate({ a: d, b: d }).error).to.not.exist(); - expect(Joi.object({ a: Joi.array().items(Joi.date()).single(), b: Joi.valid(Joi.in('a')) }).validate({ a: d, b: d }).error).to.not.exist(); - expect(Joi.object({ a: Joi.array().items(Joi.date()).single(), b: Joi.valid(Joi.in('a')) }).validate({ a: new Date(0), b: d }).error).to.be.an.error('"b" must be [ref:a]'); + Helper.validate(Joi.valid(d), [ + [new Date(d.getTime()), true], + [new Date(d.getTime() + 1), false, { + message: `"value" must be [${d.toISOString()}]`, + path: [], + type: 'any.only', + context: { value: new Date(d.getTime() + 1), valids: [d], label: 'value' } + }] + ]); + Helper.validate(Joi.valid(Joi.ref('$a')), { context: { a: new Date(d.getTime()) } }, [[d, true]]); + Helper.validate(Joi.object({ a: Joi.date(), b: Joi.valid(Joi.ref('a')) }), [[{ a: d, b: d }, true]]); + Helper.validate(Joi.object({ a: Joi.array().items(Joi.date()).single(), b: Joi.valid(Joi.in('a')) }), [[{ a: d, b: d }, true]]); + Helper.validate(Joi.object({ a: Joi.array().items(Joi.date()).single(), b: Joi.valid(Joi.in('a')) }), [[{ a: new Date(0), b: d }, false, '"b" must be [ref:a]']]); const str = 'foo'; - expect(Joi.valid(str).validate(str).error).to.not.exist(); - expect(Joi.valid(str).validate('foobar').error).to.be.an.error('"value" must be [foo]'); - expect(Joi.valid(str).validate('foobar').error.details).to.equal([{ - message: '"value" must be [foo]', - path: [], - type: 'any.only', - context: { value: 'foobar', valids: [str], label: 'value' } - }]); + Helper.validate(Joi.valid(str), [ + [str, true], + ['foobar', false, { + message: '"value" must be [foo]', + path: [], + type: 'any.only', + context: { value: 'foobar', valids: [str], label: 'value' } + }] + ]); const s = Symbol('foo'); - expect(Joi.valid(s).validate(s).error).to.not.exist(); const otherSymbol = Symbol('foo'); - expect(Joi.valid(s).validate(otherSymbol).error).to.be.an.error('"value" must be [Symbol(foo)]'); - expect(Joi.valid(s).validate(otherSymbol).error.details).to.equal([{ - message: '"value" must be [Symbol(foo)]', - path: [], - type: 'any.only', - context: { value: otherSymbol, valids: [s], label: 'value' } - }]); + Helper.validate(Joi.valid(s), [ + [s, true], + [otherSymbol, false, { + message: '"value" must be [Symbol(foo)]', + path: [], + type: 'any.only', + context: { value: otherSymbol, valids: [s], label: 'value' } + }] + ]); const o = {}; - expect(Joi.valid(o).validate(o).error).to.not.exist(); - expect(Joi.valid(o).validate({}).error).to.not.exist(); - expect(Joi.valid(o).validate({ x: 1 }).error).to.be.an.error('"value" must be [[object Object]]'); - expect(Joi.valid(o).validate({ x: 1 }).error.details).to.equal([{ - message: '"value" must be [[object Object]]', - path: [], - type: 'any.only', - context: { value: { x: 1 }, valids: [o], label: 'value' } - }]); + Helper.validate(Joi.valid(o), [ + [o, true], + [{}, true], + [{ x: 1 }, false, { + message: '"value" must be [[object Object]]', + path: [], + type: 'any.only', + context: { value: { x: 1 }, valids: [o], label: 'value' } + }] + ]); const f = () => { }; - expect(Joi.valid(f).validate(f).error).to.not.exist(); const otherFunction = () => { }; - expect(Joi.valid(f).validate(otherFunction).error).to.be.an.error('"value" must be [() => { }]'); - expect(Joi.valid(f).validate(otherFunction).error.details).to.equal([{ - message: '"value" must be [() => { }]', - path: [], - type: 'any.only', - context: { value: otherFunction, valids: [f], label: 'value' } - }]); + Helper.validate(Joi.valid(f), [ + [f, true], + [otherFunction, false, { + message: '"value" must be [() => { }]', + path: [], + type: 'any.only', + context: { value: otherFunction, valids: [f], label: 'value' } + }] + ]); const b = Buffer.from('foo'); - expect(Joi.valid(b).validate(b).error).to.not.exist(); - expect(Joi.valid(b).validate(Buffer.from('foobar')).error).to.be.an.error('"value" must be [foo]'); - expect(Joi.valid(b).validate(Buffer.from('foobar')).error.details).to.equal([{ - message: '"value" must be [foo]', - path: [], - type: 'any.only', - context: { value: Buffer.from('foobar'), valids: [b], label: 'value' } - }]); + Helper.validate(Joi.valid(b), [ + [b, true], + [Buffer.from('foobar'), false, { + message: '"value" must be [foo]', + path: [], + type: 'any.only', + context: { value: Buffer.from('foobar'), valids: [b], label: 'value' } + }] + ]); }); it('supports templates', () => { @@ -2617,8 +2630,10 @@ describe('any', () => { b: Joi.valid(Joi.x('{a + 1}')) }); - expect(schema.validate({ a: 5, b: 6 }).error).to.not.exist(); - expect(schema.validate({ a: 5, b: 5 }).error).to.be.an.error('"b" must be [{a + 1}]'); + Helper.validate(schema, [ + [{ a: 5, b: 6 }, true], + [{ a: 5, b: 5 }, false, '"b" must be [{a + 1}]'] + ]); }); it('supports templates with literals', () => { @@ -2628,8 +2643,10 @@ describe('any', () => { b: Joi.valid(Joi.x('x{a + 1}')) }); - expect(schema.validate({ a: 5, b: 'x6' }).error).to.not.exist(); - expect(schema.validate({ a: 5, b: 'x5' }).error).to.be.an.error('"b" must be [x{a + 1}]'); + Helper.validate(schema, [ + [{ a: 5, b: 'x6' }, true], + [{ a: 5, b: 'x5' }, false, '"b" must be [x{a + 1}]'] + ]); }); it('supports pure literal templates', () => { @@ -2639,8 +2656,10 @@ describe('any', () => { b: Joi.valid(Joi.x('x')) }); - expect(schema.validate({ a: 5, b: 'x' }).error).to.not.exist(); - expect(schema.validate({ a: 5, b: 'y' }).error).to.be.an.error('"b" must be [x]'); + Helper.validate(schema, [ + [{ a: 5, b: 'x' }, true], + [{ a: 5, b: 'y' }, false, '"b" must be [x]'] + ]); }); it('supports templates with functions', () => { @@ -2651,8 +2670,10 @@ describe('any', () => { c: Joi.valid(Joi.x('{if(a == 5 && b == true, a * 2, null)}')) }); - expect(schema.validate({ a: 5, b: true, c: 10 }).error).to.not.exist(); - expect(schema.validate({ a: 5, b: false, c: null }).error).to.not.exist(); + Helper.validate(schema, [ + [{ a: 5, b: true, c: 10 }, true], + [{ a: 5, b: false, c: null }, true] + ]); }); it('looks up values in array (from single value)', () => { @@ -2662,8 +2683,10 @@ describe('any', () => { b: Joi.in('a') }); - expect(schema.validate({ a: ['1', '2'], b: '2' }).error).to.not.exist(); - expect(schema.validate({ a: ['1', '2'], b: '3' }).error).to.be.an.error('"b" must be [ref:a]'); + Helper.validate(schema, [ + [{ a: ['1', '2'], b: '2' }, true], + [{ a: ['1', '2'], b: '3' }, false, '"b" must be [ref:a]'] + ]); }); it('looks up values in array (from array value)', () => { @@ -2673,8 +2696,10 @@ describe('any', () => { b: Joi.array().valid(Joi.ref('a')) }); - expect(schema.validate({ a: ['1', '2'], b: ['1', '2'] }).error).to.not.exist(); - expect(schema.validate({ a: ['1', '2'], b: ['1'] }).error).to.be.an.error('"b" must be [ref:a]'); + Helper.validate(schema, [ + [{ a: ['1', '2'], b: ['1', '2'] }, true], + [{ a: ['1', '2'], b: ['1'] }, false, '"b" must be [ref:a]'] + ]); }); }); @@ -2683,14 +2708,15 @@ describe('any', () => { it('checks value after conversion', () => { const schema = Joi.number().invalid(2); - const err = schema.validate('2', { abortEarly: false }).error; - expect(err).to.be.an.error('"value" contains an invalid value'); - expect(err.details).to.equal([{ + Helper.validate(schema, { abortEarly: false }, [['2', false, { message: '"value" contains an invalid value', - path: [], - type: 'any.invalid', - context: { value: 2, invalids: [2], label: 'value' } - }]); + details: [{ + message: '"value" contains an invalid value', + path: [], + type: 'any.invalid', + context: { value: 2, invalids: [2], label: 'value' } + }] + }]]); }); }); @@ -2699,40 +2725,29 @@ describe('any', () => { it('accepts only value (sync way)', () => { const schema = Joi.number(); - const result = schema.validate('2'); - expect(result).to.contain({ value: 2 }); - }); - - it('accepts value and callback', () => { - - const schema = Joi.number(); - expect(schema.validate('2')).to.equal({ value: 2 }); + Helper.validate(schema, [['2', true, 2]]); }); it('accepts value and options', () => { const schema = Joi.number(); - const result = schema.validate('2', { convert: false }); - expect(result.error).to.be.an.error('"value" must be a number'); - expect(result.error.details).to.equal([{ + Helper.validate(schema, { convert: false }, [['2', false, { message: '"value" must be a number', path: [], type: 'number.base', context: { label: 'value', value: '2' } - }]); + }]]); }); it('accepts value, options and callback', () => { const schema = Joi.number(); - const err = schema.validate('2', { convert: false }).error; - expect(err).to.be.an.error('"value" must be a number'); - expect(err.details).to.equal([{ + Helper.validate(schema, { convert: false }, [['2', false, { message: '"value" must be a number', path: [], type: 'number.base', context: { label: 'value', value: '2' } - }]); + }]]); }); }); diff --git a/test/compile.js b/test/compile.js index d7d04d119..c89b0e538 100755 --- a/test/compile.js +++ b/test/compile.js @@ -26,7 +26,7 @@ describe('cast', () => { b: Joi.x('{a + 1}') }); - expect(schema.validate({ a: 5, b: 6 }).error).to.not.exist(); + Helper.validate(schema, [[{ a: 5, b: 6 }, true]]); }); it('compiles null schema', () => { diff --git a/test/helper.js b/test/helper.js index 71b52dd66..bd5dd187c 100755 --- a/test/helper.js +++ b/test/helper.js @@ -32,7 +32,8 @@ exports.validate = function (schema, prefs, tests) { try { expect(schema.$_root.build(schema.describe())).to.equal(schema, { deepFunction: true, skip: ['$_temp'] }); - for (const [input, pass, expected] of tests) { + for (const test of tests) { + const [input, pass, expected] = test; if (!pass) { expect(expected, 'Failing tests messages must be tested').to.exist(); } @@ -57,7 +58,7 @@ exports.validate = function (schema, prefs, tests) { expect(!error).to.equal(pass); - if (expected === undefined) { + if (test.length === 2) { continue; } diff --git a/test/types/boolean.js b/test/types/boolean.js index 8d832e0d1..968bfde23 100755 --- a/test/types/boolean.js +++ b/test/types/boolean.js @@ -88,8 +88,10 @@ describe('boolean', () => { it('respects case for allow', () => { const schema = Joi.boolean().allow('X'); - expect(schema.validate('X').error).to.not.exist(); - expect(schema.validate('x').error).to.be.an.error('"value" must be a boolean'); + Helper.validate(schema, [ + ['X', true], + ['x', false, '"value" must be a boolean'] + ]); }); describe('cast()', () => { @@ -97,27 +99,31 @@ describe('boolean', () => { it('casts value to number', () => { const schema = Joi.boolean().cast('number'); - expect(schema.validate(true).value).to.equal(1); - expect(schema.validate(false).value).to.equal(0); + Helper.validate(schema, [ + [true, true, 1], + [false, true, 0] + ]); }); it('casts value to string', () => { const schema = Joi.boolean().cast('string'); - expect(schema.validate(true).value).to.equal('true'); - expect(schema.validate(false).value).to.equal('false'); + Helper.validate(schema, [ + [true, true, 'true'], + [false, true, 'false'] + ]); }); it('ignores null', () => { const schema = Joi.boolean().allow(null).cast('string'); - expect(schema.validate(null).value).to.be.null(); + Helper.validate(schema, [[null, true, null]]); }); it('ignores string', () => { const schema = Joi.boolean().allow('x').cast('string'); - expect(schema.validate('x').value).to.equal('x'); + Helper.validate(schema, [['x', true, 'x']]); }); }); @@ -203,7 +209,7 @@ describe('boolean', () => { it('should default to case insensitive', () => { const schema = Joi.boolean().truthy('Y'); - expect(schema.validate('y').error).not.to.exist(); + Helper.validate(schema, [['y', true, true]]); }); it('should stick to case insensitive if called', () => { @@ -215,14 +221,12 @@ describe('boolean', () => { it('should be able to do strict comparison', () => { const schema = Joi.boolean().truthy('Y').sensitive(); - const error = schema.validate('y').error; - expect(error).to.be.an.error('"value" must be a boolean'); - expect(error.details).to.equal([{ + Helper.validate(schema, [['y', false, { message: '"value" must be a boolean', path: [], type: 'boolean.base', context: { label: 'value', value: 'y' } - }]); + }]]); }); it('should return the same instance if nothing changed', () => { @@ -599,7 +603,7 @@ describe('boolean', () => { it('errors on truthy without convert', () => { const schema = Joi.boolean().truthy('y'); - expect(schema.validate('y', { convert: false }).error).be.an.error('"value" must be a boolean'); + Helper.validate(schema, { convert: false }, [['y', false, '"value" must be a boolean']]); }); }); }); diff --git a/test/types/date.js b/test/types/date.js index fa789d50f..43923723f 100755 --- a/test/types/date.js +++ b/test/types/date.js @@ -90,25 +90,25 @@ describe('date', () => { it('matches specific date', () => { const now = Date.now(); - expect(Joi.date().valid(new Date(now)).validate(new Date(now)).error).to.not.exist(); - expect(Joi.date().valid(new Date(now)).validate(new Date(now).toISOString()).error).to.not.exist(); + Helper.validate(Joi.date().valid(new Date(now)), [ + [new Date(now), true], + [new Date(now).toISOString(), true] + ]); }); it('errors on invalid input and convert disabled', () => { - const err = Joi.date().prefs({ convert: false }).validate('1-1-2013 UTC').error; - expect(err).to.be.an.error('"value" must be a valid date'); - expect(err.details).to.equal([{ + Helper.validate(Joi.date().prefs({ convert: false }), [['1-1-2013 UTC', false, { message: '"value" must be a valid date', path: [], type: 'date.base', context: { label: 'value', value: '1-1-2013 UTC' } - }]); + }]]); }); it('validates date', () => { - expect(Joi.date().validate(new Date()).error).to.not.exist(); + Helper.validate(Joi.date(), [[new Date(), true]]); }); it('validates millisecond date as a string', () => { @@ -116,7 +116,7 @@ describe('date', () => { const now = new Date(); const mili = now.getTime(); - expect(Joi.date().validate(mili.toString())).to.equal({ value: now }); + Helper.validate(Joi.date(), [[mili.toString(), true, now]]); }); it('validates only valid dates', () => { @@ -146,31 +146,31 @@ describe('date', () => { it('casts value to number', () => { const schema = Joi.date().cast('number'); - expect(schema.validate(new Date('1974-05-07')).value).to.equal(137116800000); + Helper.validate(schema, [[new Date('1974-05-07'), true, 137116800000]]); }); it('casts value to string', () => { const schema = Joi.date().cast('string'); - expect(schema.validate(new Date('1974-05-07')).value).to.equal('1974-05-07T00:00:00.000Z'); + Helper.validate(schema, [[new Date('1974-05-07'), true, '1974-05-07T00:00:00.000Z']]); }); it('casts value to string (custom format)', () => { const schema = Joi.date().prefs({ dateFormat: 'date' }).cast('string'); - expect(schema.validate(new Date('1974-05-07')).value).to.equal('Tue May 07 1974'); + Helper.validate(schema, [[new Date('1974-05-07'), true, 'Tue May 07 1974']]); }); it('ignores null', () => { const schema = Joi.date().allow(null).cast('string'); - expect(schema.validate(null).value).to.be.null(); + Helper.validate(schema, [[null, true, null]]); }); it('ignores string', () => { const schema = Joi.date().allow('x').cast('string'); - expect(schema.validate('x').value).to.equal('x'); + Helper.validate(schema, [['x', true, 'x']]); }); }); @@ -193,9 +193,11 @@ describe('date', () => { } }); - expect(custom.date().format('unknown').validate('x').error).to.be.an.error('"value" must be in unknown format'); - expect(custom.date().format(['unknown']).validate('x').error).to.be.an.error('"value" must be in [unknown] format'); - expect(custom.date().format('unknown').validate(Date.now()).error).to.not.exist(); + Helper.validate(custom.date().format('unknown'), [ + ['x', false, '"value" must be in unknown format'], + [Date.now(), true] + ]); + Helper.validate(custom.date().format(['unknown']), [['x', false, '"value" must be in [unknown] format']]); }); }); @@ -251,15 +253,14 @@ describe('date', () => { const now = Date.now(); const past = new Date(now - 1000000); - const err = Joi.date().greater('now').validate(past).error; - const message = '"value" must be greater than "now"'; - expect(err).to.be.an.error(message); - expect(err.details).to.equal([{ - message: '"value" must be greater than "now"', - path: [], - type: 'date.greater', - context: { limit: 'now', label: 'value', value: past } - }]); + Helper.validate(Joi.date().greater('now'), [ + [past, false, { + message: '"value" must be greater than "now"', + path: [], + type: 'date.greater', + context: { limit: 'now', label: 'value', value: past } + }] + ]); }); it('accepts references as greater date', () => { @@ -480,20 +481,20 @@ describe('date', () => { it('validates isoDate with a friendly error message', () => { const schema = { item: Joi.date().iso() }; - const err = Joi.compile(schema).validate({ item: 'something' }).error; - expect(err.message).to.equal('"item" must be in ISO 8601 date format'); - expect(err.details).to.equal([{ - message: '"item" must be in ISO 8601 date format', - path: ['item'], - type: 'date.format', - context: { label: 'item', key: 'item', value: 'something', format: 'iso' } - }]); + Helper.validate(Joi.compile(schema), [ + [{ item: 'something' }, false, { + message: '"item" must be in ISO 8601 date format', + path: ['item'], + type: 'date.format', + context: { label: 'item', key: 'item', value: 'something', format: 'iso' } + }] + ]); }); it('validates isoDate after clone', () => { const schema = { item: Joi.date().iso().clone() }; - expect(Joi.compile(schema).validate({ item: '2013-06-07T14:21:46.295Z' }).error).to.not.exist(); + Helper.validate(Joi.compile(schema), [[{ item: '2013-06-07T14:21:46.295Z' }, true]]); }); }); @@ -547,7 +548,7 @@ describe('date', () => { it('accepts "now" as the less date', () => { const past = new Date(Date.now() - 1000000); - expect(Joi.date().less('now').validate(past)).to.equal({ value: past }); + Helper.validate(Joi.date().less('now'), [[past, true, past]]); }); it('errors if .less("now") is used with a future date', () => { @@ -555,15 +556,12 @@ describe('date', () => { const now = Date.now(); const future = new Date(now + 1000000); - const err = Joi.date().less('now').validate(future).error; - const message = '"value" must be less than "now"'; - expect(err).to.be.an.error(message); - expect(err.details).to.equal([{ + Helper.validate(Joi.date().less('now'), [[future, false, { message: '"value" must be less than "now"', path: [], type: 'date.less', context: { limit: 'now', label: 'value', value: future } - }]); + }]]); }); it('accepts references as less date', () => { @@ -700,7 +698,7 @@ describe('date', () => { it('accepts "now" as the max date', () => { const past = new Date(Date.now() - 1000000); - expect(Joi.date().max('now').validate(past)).to.equal({ value: past }); + Helper.validate(Joi.date().max('now'), [[past, true, past]]); }); it('errors if .max("now") is used with a future date', () => { @@ -708,15 +706,12 @@ describe('date', () => { const now = Date.now(); const future = new Date(now + 1000000); - const err = Joi.date().max('now').validate(future).error; - const message = '"value" must be less than or equal to "now"'; - expect(err).to.be.an.error(message); - expect(err.details).to.equal([{ - message, + Helper.validate(Joi.date().max('now'), [[future, false, { + message: '"value" must be less than or equal to "now"', path: [], type: 'date.max', context: { limit: 'now', label: 'value', value: future } - }]); + }]]); }); it('accepts references as max date', () => { @@ -877,15 +872,12 @@ describe('date', () => { const now = Date.now(); const past = new Date(now - 1000000); - const err = Joi.date().min('now').validate(past).error; - const message = '"value" must be larger than or equal to "now"'; - expect(err).to.be.an.error(message); - expect(err.details).to.equal([{ - message, + Helper.validate(Joi.date().min('now'), [[past, false, { + message: '"value" must be larger than or equal to "now"', path: [], type: 'date.min', context: { limit: 'now', label: 'value', value: past } - }]); + }]]); }); it('accepts references as min date', () => { @@ -1036,9 +1028,9 @@ describe('date', () => { const now = new Date(); const milliseconds = now.getTime(); - expect(Joi.date().timestamp().validate(milliseconds)).to.equal({ value: now }); - expect(Joi.date().timestamp('javascript').validate(milliseconds)).to.equal({ value: now }); - expect(Joi.date().timestamp('unix').timestamp('javascript').validate(milliseconds)).to.equal({ value: now }); + Helper.validate(Joi.date().timestamp(), [[milliseconds, true, now]]); + Helper.validate(Joi.date().timestamp('javascript'), [[milliseconds, true, now]]); + Helper.validate(Joi.date().timestamp('unix').timestamp('javascript'), [[milliseconds, true, now]]); }); it('validates unix timestamp', () => { @@ -1046,9 +1038,9 @@ describe('date', () => { const now = new Date(); const seconds = now.getTime() / 1000; - expect(Joi.date().timestamp('unix').validate(seconds)).to.equal({ value: now }); - expect(Joi.date().timestamp().timestamp('unix').validate(seconds)).to.equal({ value: now }); - expect(Joi.date().timestamp('javascript').timestamp('unix').validate(seconds)).to.equal({ value: now }); + Helper.validate(Joi.date().timestamp('unix'), [[seconds, true, now]]); + Helper.validate(Joi.date().timestamp().timestamp('unix'), [[seconds, true, now]]); + Helper.validate(Joi.date().timestamp('javascript').timestamp('unix'), [[seconds, true, now]]); }); it('validates timestamps with decimals', () => { diff --git a/test/types/function.js b/test/types/function.js index 08cd3dcd6..27a14e34c 100755 --- a/test/types/function.js +++ b/test/types/function.js @@ -61,41 +61,36 @@ describe('function', () => { }] ]); - const error1 = schema.validate(function (a, b, c) { }).error; // eslint-disable-line prefer-arrow-callback - expect(error1).to.be.an.error('"value" must have an arity of 2'); - expect(error1.details).to.equal([{ - message: '"value" must have an arity of 2', - path: [], - type: 'function.arity', - context: { n: 2, label: 'value', value: error1.details[0].context.value } - }]); - - const error2 = schema.validate(function (a) { }).error; // eslint-disable-line prefer-arrow-callback - expect(error2).to.be.an.error('"value" must have an arity of 2'); - expect(error2.details).to.equal([{ - message: '"value" must have an arity of 2', - path: [], - type: 'function.arity', - context: { n: 2, label: 'value', value: error2.details[0].context.value } - }]); + const f1 = function (a, b, c) {}; + const f2 = function (a) { }; + const f3 = (a, b, c) => { }; + const f4 = (a) => { }; - const error3 = schema.validate((a, b, c) => { }).error; - expect(error3).to.be.an.error('"value" must have an arity of 2'); - expect(error3.details).to.equal([{ - message: '"value" must have an arity of 2', - path: [], - type: 'function.arity', - context: { n: 2, label: 'value', value: error3.details[0].context.value } - }]); - - const error4 = schema.validate((a) => { }).error; - expect(error4).to.be.an.error('"value" must have an arity of 2'); - expect(error4.details).to.equal([{ - message: '"value" must have an arity of 2', - path: [], - type: 'function.arity', - context: { n: 2, label: 'value', value: error4.details[0].context.value } - }]); + Helper.validate(schema, [ + [f1, false, { + message: '"value" must have an arity of 2', + path: [], + type: 'function.arity', + context: { n: 2, label: 'value', value: f1 } + }], + [f2, false, { + message: '"value" must have an arity of 2', + path: [], + type: 'function.arity', + context: { n: 2, label: 'value', value: f2 } + }], + [f3, false, { + message: '"value" must have an arity of 2', + path: [], + type: 'function.arity', + context: { n: 2, label: 'value', value: f3 } + }], [f4, false, { + message: '"value" must have an arity of 2', + path: [], + type: 'function.arity', + context: { n: 2, label: 'value', value: f4 } + }] + ]); }); it('validates a function arity unless values are illegal', () => { @@ -117,6 +112,9 @@ describe('function', () => { it('validates a function min arity', () => { const schema = Joi.function().minArity(2).required(); + const f1 = function (a) { }; + const f2 = (a) => { }; + Helper.validate(schema, [ [function (a, b) { }, true], [function (a, b, c) { }, true], @@ -127,26 +125,20 @@ describe('function', () => { path: [], type: 'object.base', context: { label: 'value', value: '', type: 'function' } + }], + [f1, false, { + message: '"value" must have an arity greater or equal to 2', + path: [], + type: 'function.minArity', + context: { n: 2, label: 'value', value: f1 } + }], + [f2, false, { + message: '"value" must have an arity greater or equal to 2', + path: [], + type: 'function.minArity', + context: { n: 2, label: 'value', value: f2 } }] ]); - - const error1 = schema.validate(function (a) { }).error; // eslint-disable-line prefer-arrow-callback - expect(error1).to.be.an.error('"value" must have an arity greater or equal to 2'); - expect(error1.details).to.equal([{ - message: '"value" must have an arity greater or equal to 2', - path: [], - type: 'function.minArity', - context: { n: 2, label: 'value', value: error1.details[0].context.value } - }]); - - const error2 = schema.validate((a) => { }).error; - expect(error2).to.be.an.error('"value" must have an arity greater or equal to 2'); - expect(error2.details).to.equal([{ - message: '"value" must have an arity greater or equal to 2', - path: [], - type: 'function.minArity', - context: { n: 2, label: 'value', value: error2.details[0].context.value } - }]); }); it('validates a function arity unless values are illegal', () => { @@ -174,39 +166,33 @@ describe('function', () => { it('validates a function max arity', () => { const schema = Joi.function().maxArity(2).required(); + const f1 = function (a, b, c) { }; + const f2 = (a, b, c) => { }; + Helper.validate(schema, [ [function (a, b) { }, true], [function (a) { }, true], [(a, b) => { }, true], - [(a) => { }, true] + [(a) => { }, true], + [f1, false, { + message: '"value" must have an arity lesser or equal to 2', + path: [], + type: 'function.maxArity', + context: { n: 2, label: 'value', value: f1 } + }], + [f2, false, { + message: '"value" must have an arity lesser or equal to 2', + path: [], + type: 'function.maxArity', + context: { n: 2, label: 'value', value: f2 } + }], + ['', false, { + message: '"value" must be of type function', + path: [], + type: 'object.base', + context: { label: 'value', value: '', type: 'function' } + }] ]); - - const error1 = schema.validate(function (a, b, c) { }).error; // eslint-disable-line prefer-arrow-callback - expect(error1).to.be.an.error('"value" must have an arity lesser or equal to 2'); - expect(error1.details).to.equal([{ - message: '"value" must have an arity lesser or equal to 2', - path: [], - type: 'function.maxArity', - context: { n: 2, label: 'value', value: error1.details[0].context.value } - }]); - - const error2 = schema.validate((a, b, c) => { }).error; - expect(error2).to.be.an.error('"value" must have an arity lesser or equal to 2'); - expect(error2.details).to.equal([{ - message: '"value" must have an arity lesser or equal to 2', - path: [], - type: 'function.maxArity', - context: { n: 2, label: 'value', value: error2.details[0].context.value } - }]); - - const error3 = schema.validate('').error; - expect(error3).to.be.an.error('"value" must be of type function'); - expect(error3.details).to.equal([{ - message: '"value" must be of type function', - path: [], - type: 'object.base', - context: { label: 'value', value: '', type: 'function' } - }]); }); it('validates a function arity unless values are illegal', () => { @@ -311,29 +297,23 @@ describe('function', () => { const b = function () { }; b.a = 'abc'; - Helper.validate(schema, [ - [a, true] - ]); - - const err1 = schema.validate(b).error; - expect(err1).to.be.an.error('"value" must have an arity greater or equal to 1'); - expect(err1.details).to.equal([{ - message: '"value" must have an arity greater or equal to 1', - path: [], - type: 'function.minArity', - context: { value: err1.details[0].context.value, label: 'value', n: 1 } - }]); - const c = function (x) { }; - const err2 = schema.validate(c).error; - expect(err2).to.be.an.error('"value" must have at least 1 key'); - expect(err2.details).to.equal([{ - message: '"value" must have at least 1 key', - path: [], - type: 'object.min', - context: { value: err2.details[0].context.value, label: 'value', limit: 1 } - }]); + Helper.validate(schema, [ + [a, true], + [b, false, { + message: '"value" must have an arity greater or equal to 1', + path: [], + type: 'function.minArity', + context: { value: b, label: 'value', n: 1 } + }], + [c, false, { + message: '"value" must have at least 1 key', + path: [], + type: 'object.min', + context: { value: c, label: 'value', limit: 1 } + }] + ]); }); it('keeps validated value as a function', () => { diff --git a/test/types/number.js b/test/types/number.js index afc424d03..aec3a2aad 100755 --- a/test/types/number.js +++ b/test/types/number.js @@ -68,7 +68,14 @@ describe('number', () => { it('displays correctly for int type', () => { const t = Joi.number().integer(); - expect(Joi.compile(t).validate('1.1').error).to.be.an.error(/integer/); + Helper.validate(Joi.compile(t), [ + ['1.1', false, { + message: '"value" must be an integer', + path: [], + type: 'number.integer', + context: { label: 'value', value: 1.1 } + }] + ]); }); }); @@ -77,21 +84,23 @@ describe('number', () => { it('casts value to string', () => { const schema = Joi.number().cast('string'); - expect(schema.validate(0).value).to.equal('0'); - expect(schema.validate(0.01).value).to.equal('0.01'); - expect(schema.validate(-12).value).to.equal('-12'); + Helper.validate(schema, [ + [0, true, '0'], + [0.01, true, '0.01'], + [-12, true, '-12'] + ]); }); it('ignores null', () => { const schema = Joi.number().allow(null).cast('string'); - expect(schema.validate(null).value).to.be.null(); + Helper.validate(schema, [[null, true, null]]); }); it('ignores string', () => { const schema = Joi.number().allow('x').cast('string'); - expect(schema.validate('x').value).to.equal('x'); + Helper.validate(schema, [['x', true, 'x']]); }); }); @@ -510,7 +519,7 @@ describe('number', () => { const schema = Joi.number().min(1394035612500); const input = 1394035612552; - expect(schema.validate(input)).to.equal({ value: input }); + Helper.validate(schema, [[input, true, input]]); }); it('accepts references as min value', () => { @@ -969,26 +978,26 @@ describe('number', () => { it('compares valid matching post-coerce value', () => { const schema = Joi.number().valid(1, 2, 3); - expect(schema.validate('1')).to.equal({ value: 1 }); + Helper.validate(schema, [['1', true, 1]]); }); it('ignores invalid matching of pre-coerce value', () => { const schema = Joi.number().invalid('1'); - expect(schema.validate('1')).to.equal({ value: 1 }); + Helper.validate(schema, [['1', true, 1]]); }); it('returns false for denied value', () => { const text = Joi.number().invalid(50); - const err = text.validate(50).error; - expect(err).to.be.an.error('"value" contains an invalid value'); - expect(err.details).to.equal([{ - message: '"value" contains an invalid value', - path: [], - type: 'any.invalid', - context: { value: 50, invalids: [50], label: 'value' } - }]); + Helper.validate(text, [ + [50, false, { + message: '"value" contains an invalid value', + path: [], + type: 'any.invalid', + context: { value: 50, invalids: [50], label: 'value' } + }] + ]); }); it('validates integer', () => { @@ -1128,25 +1137,26 @@ describe('number', () => { const config = { a: Joi.number() }; const obj = { a: '123' }; - - expect(Joi.compile(config).validate(obj)).to.equal({ value: { a: 123 } }); + Helper.validate(Joi.compile(config), [ + [obj, true, { a: 123 }] + ]); }); it('converts a string to a number', () => { - expect(Joi.number().validate('1')).to.equal({ value: 1 }); + Helper.validate(Joi.number(), [['1', true, 1]]); }); it('errors on null', () => { - const err = Joi.number().validate(null).error; - expect(err).to.be.an.error('"value" must be a number'); - expect(err.details).to.equal([{ - message: '"value" must be a number', - path: [], - type: 'number.base', - context: { label: 'value', value: null } - }]); + Helper.validate(Joi.number(), [ + [null, false, { + message: '"value" must be a number', + path: [], + type: 'number.base', + context: { label: 'value', value: null } + }] + ]); }); it('handles combination of min and max', () => { diff --git a/test/types/object.js b/test/types/object.js index 0dcb1d890..f2923d007 100755 --- a/test/types/object.js +++ b/test/types/object.js @@ -48,7 +48,7 @@ describe('object', () => { c: 'joe@example.com' }; - expect(schema.validate(obj).error).to.not.exist(); + Helper.validate(schema, [[obj, true]]); }); it('validates references', () => { @@ -73,19 +73,19 @@ describe('object', () => { }); const item = { x: 5 }; - expect(schema.validate({ a: item })).to.equal({ value: { a: item } }); + Helper.validate(schema, [[{ a: item }, true, { a: item }]]); }); it('retains ignored values', () => { const schema = Joi.object(); - expect(schema.validate({ a: 5 })).to.equal({ value: { a: 5 } }); + Helper.validate(schema, [[{ a: 5 }, true, { a: 5 }]]); }); it('retains skipped values', () => { const schema = Joi.object({ b: 5 }).unknown(true); - expect(schema.validate({ b: 5, a: 5 })).to.equal({ value: { a: 5, b: 5 } }); + Helper.validate(schema, [[{ b: 5, a: 5 }, true, { a: 5, b: 5 }]]); }); it('retains symbols', () => { @@ -93,7 +93,7 @@ describe('object', () => { const schema = Joi.object({ a: Joi.number() }); const symbol = Symbol(); - expect(schema.validate({ [symbol]: 5, a: 5 })).to.equal({ value: { [symbol]: 5, a: 5 } }); + Helper.validate(schema, [[{ [symbol]: 5, a: 5 }, true, { [symbol]: 5, a: 5 }]]); }); it('retains non-enumerable', () => { @@ -103,7 +103,7 @@ describe('object', () => { const obj = { a: 100 }; Object.defineProperty(obj, 'test', { value: 42, enumerable: false }); expect(obj.test).to.equal(42); - expect(schema.validate(obj, { nonEnumerables: true })).to.equal({ value: { a: 100 } }); + Helper.validate(schema, { nonEnumerables: true }, [[obj, true, { a: 100 }]]); }); it('retains prototype', () => { @@ -122,13 +122,13 @@ describe('object', () => { it('allows any key when schema is undefined', () => { - expect(Joi.object().validate({ a: 4 }).error).to.not.exist(); - expect(Joi.object(undefined).validate({ a: 4 }).error).to.not.exist(); + Helper.validate(Joi.object(), [[{ a: 4 }, true]]); + Helper.validate(Joi.object(undefined), [[{ a: 4 }, true]]); }); it('allows any key when schema is null', () => { - expect(Joi.object(null).validate({ a: 4 }).error).to.not.exist(); + Helper.validate(Joi.object(null), [[{ a: 4 }, true]]); }); it('throws on invalid object schema', () => { @@ -149,19 +149,17 @@ describe('object', () => { it('skips conversion when value is undefined', () => { - expect(Joi.object({ a: Joi.object() }).validate(undefined)).to.equal({ value: undefined }); + Helper.validate(Joi.object({ a: Joi.object() }), [[undefined, true, undefined]]); }); it('errors on array', () => { - const err = Joi.object().validate([1, 2, 3]).error; - expect(err).to.be.an.error('"value" must be of type object'); - expect(err.details).to.equal([{ + Helper.validate(Joi.object(), [[[1, 2, 3], false, { message: '"value" must be of type object', path: [], type: 'object.base', context: { label: 'value', value: [1, 2, 3], type: 'object' } - }]); + }]]); }); it('should prevent extra keys from existing by default', () => { @@ -491,14 +489,12 @@ describe('object', () => { const schema = Joi.object({ a: Joi.number() }).prefs({ skipFunctions: true }); const obj = { a: 5, b: 'value' }; - const err = schema.validate(obj).error; - expect(err).to.be.an.error('"b" is not allowed'); - expect(err.details).to.equal([{ + Helper.validate(schema, [[obj, false, { message: '"b" is not allowed', path: ['b'], type: 'object.unknown', context: { child: 'b', label: 'b', key: 'b', value: 'value' } - }]); + }]]); }); it('validates both valid() and with()', () => { @@ -572,28 +568,24 @@ describe('object', () => { const schema = Joi.object({ a: Joi.object().keys({}) }); const obj = { a: { b: 'value' } }; - const err = schema.validate(obj).error; - expect(err).to.be.an.error('"a.b" is not allowed'); - expect(err.details).to.equal([{ + Helper.validate(schema, [[obj, false, { message: '"a.b" is not allowed', path: ['a', 'b'], type: 'object.unknown', context: { child: 'b', label: 'a.b', key: 'b', value: 'value' } - }]); + }]]); }); it('errors on unknown nested keys with the correct path at the root level', () => { const schema = Joi.object({ a: Joi.object().keys({}) }); const obj = { c: 'hello' }; - const err = schema.validate(obj).error; - expect(err).to.be.an.error('"c" is not allowed'); - expect(err.details).to.equal([{ + Helper.validate(schema, [[obj, false, { message: '"c" is not allowed', path: ['c'], type: 'object.unknown', context: { child: 'c', label: 'c', key: 'c', value: 'hello' } - }]); + }]]); }); it('should work on prototype-less objects', () => { @@ -605,7 +597,7 @@ describe('object', () => { input.a = 1337; - expect(schema.validate(input).error).to.not.exist(); + Helper.validate(schema, [[input, true]]); }); it('should be able to use rename safely with a fake hasOwnProperty', () => { @@ -615,14 +607,12 @@ describe('object', () => { const input = { b: 2, a: 1, hasOwnProperty: 'foo' }; - const err = schema.validate(input).error; - expect(err).to.be.an.error('"value" cannot rename "b" because override is disabled and target "a" exists'); - expect(err.details).to.equal([{ + Helper.validate(schema, [[input, false, { message: '"value" cannot rename "b" because override is disabled and target "a" exists', path: [], type: 'object.rename.override', context: { from: 'b', to: 'a', label: 'value', pattern: false, value: input } - }]); + }]]); }); it('should be able to use object.with() safely with a fake hasOwnProperty', () => { @@ -630,35 +620,35 @@ describe('object', () => { const input = { a: 1, hasOwnProperty: 'foo' }; const schema = Joi.object({ a: 1 }).with('a', 'b'); - const err = schema.validate(input, { abortEarly: false }).error; - expect(err).to.be.an.error(); - expect(err).to.be.an.error('"hasOwnProperty" is not allowed. "a" missing required peer "b"'); - expect(err.details).to.equal([ - { - message: '"hasOwnProperty" is not allowed', - path: ['hasOwnProperty'], - type: 'object.unknown', - context: { - child: 'hasOwnProperty', - label: 'hasOwnProperty', - key: 'hasOwnProperty', - value: 'foo' - } - }, - { - message: '"a" missing required peer "b"', - path: [], - type: 'object.with', - context: { - main: 'a', - mainWithLabel: 'a', - peer: 'b', - peerWithLabel: 'b', - label: 'value', - value: input + Helper.validate(schema, { abortEarly: false }, [[input, false, { + message: '"hasOwnProperty" is not allowed. "a" missing required peer "b"', + details: [ + { + message: '"hasOwnProperty" is not allowed', + path: ['hasOwnProperty'], + type: 'object.unknown', + context: { + child: 'hasOwnProperty', + label: 'hasOwnProperty', + key: 'hasOwnProperty', + value: 'foo' + } + }, + { + message: '"a" missing required peer "b"', + path: [], + type: 'object.with', + context: { + main: 'a', + mainWithLabel: 'a', + peer: 'b', + peerWithLabel: 'b', + label: 'value', + value: input + } } - } - ]); + ] + }]]); }); it('aborts early on unknown keys', () => { @@ -666,7 +656,7 @@ describe('object', () => { const input = { a: 1, unknown: 2 }; const schema = Joi.object({ a: 1 }).with('a', 'b'); - expect(schema.validate(input).error).to.be.an.error('"unknown" is not allowed'); + Helper.validate(schema, [[input, false, '"unknown" is not allowed']]); }); it('should apply labels with nested objects', () => { @@ -680,9 +670,7 @@ describe('object', () => { }) .with('a', ['b.c']); - const error = schema.validate({ a: 1, b: { d: 2 } }).error; - expect(error).to.be.an.error('"first" missing required peer "b.second"'); - expect(error.details).to.equal([{ + Helper.validate(schema, [[{ a: 1, b: { d: 2 } }, false, { message: '"first" missing required peer "b.second"', path: [], type: 'object.with', @@ -694,7 +682,7 @@ describe('object', () => { label: 'value', value: { a: 1, b: { d: 2 } } } - }]); + }]]); }); it('errors on unknown key', () => { @@ -705,11 +693,10 @@ describe('object', () => { }).allow(null) }; - const err = Joi.compile(config).validate({ auth: { unknown: true } }).error; - expect(err.message).to.contain('"auth.unknown" is not allowed'); - - const err2 = Joi.compile(config).validate({ something: false }).error; - expect(err2.message).to.contain('"something" is not allowed'); + Helper.validate(Joi.compile(config), [ + [{ auth: { unknown: true } }, false, '"auth.unknown" is not allowed'], + [{ something: false }, false, '"something" is not allowed'] + ]); }); describe('and()', () => { @@ -942,9 +929,7 @@ describe('object', () => { a: Joi.number().label('first'), b: Joi.string().label('second') }).and('a', 'b'); - const error = schema.validate({ a: 1 }).error; - expect(error).to.be.an.error('"value" contains [first] without its required peers [second]'); - expect(error.details).to.equal([{ + Helper.validate(schema, [[{ a: 1 }, false, { message: '"value" contains [first] without its required peers [second]', path: [], type: 'object.and', @@ -956,7 +941,7 @@ describe('object', () => { label: 'value', value: { a: 1 } } - }]); + }]]); }); it('allows nested objects', () => { @@ -970,24 +955,22 @@ describe('object', () => { const sampleObject = { a: 'test', b: { c: 'test2' } }; const sampleObject2 = { a: 'test', b: { d: 80 } }; - const error = schema.validate(sampleObject).error; - expect(error).to.not.exist(); - - const error2 = schema.validate(sampleObject2).error; - expect(error2).to.be.an.error('"value" contains [a] without its required peers [b.c]'); - expect(error2.details).to.equal([{ - message: '"value" contains [a] without its required peers [b.c]', - path: [], - type: 'object.and', - context: { - present: ['a'], - presentWithLabels: ['a'], - missing: ['b.c'], - missingWithLabels: ['b.c'], - label: 'value', - value: sampleObject2 - } - }]); + Helper.validate(schema, [ + [sampleObject, true], + [sampleObject2, false, { + message: '"value" contains [a] without its required peers [b.c]', + path: [], + type: 'object.and', + context: { + present: ['a'], + presentWithLabels: ['a'], + missing: ['b.c'], + missingWithLabels: ['b.c'], + label: 'value', + value: sampleObject2 + } + }] + ]); }); it('allows nested keys in functions', () => { @@ -1001,8 +984,7 @@ describe('object', () => { const sampleObject = { a: 'test', b: Object.assign(() => { }, { c: 'test2' }) }; const sampleObject2 = { a: 'test', b: Object.assign(() => { }, { d: 80 }) }; - const error = schema.validate(sampleObject).error; - expect(error).to.not.exist(); + Helper.validate(schema, [[sampleObject, true]]); const error2 = schema.validate(sampleObject2).error; expect(error2).to.be.an.error('"value" contains [a] without its required peers [b.c]'); @@ -1060,9 +1042,7 @@ describe('object', () => { }) .and('a', 'c.d'); - const error = schema.validate({ a: 1, b: { d: 1 } }).error; - expect(error).to.be.an.error('"value" contains [first] without its required peers [c.d]'); - expect(error.details).to.equal([{ + Helper.validate(schema, [[{ a: 1, b: { d: 1 } }, false, { message: '"value" contains [first] without its required peers [c.d]', path: [], type: 'object.and', @@ -1074,7 +1054,7 @@ describe('object', () => { label: 'value', value: { a: 1, b: { d: 1 } } } - }]); + }]]); }); }); @@ -1086,7 +1066,7 @@ describe('object', () => { .keys({ a: Joi.string() }) .append({ b: Joi.string() }); - expect(schema.validate({ a: 'x', b: 'y' }).error).to.not.exist(); + Helper.validate(schema, [[{ a: 'x', b: 'y' }, true]]); }); it('should not change schema if it is null', () => { @@ -1095,7 +1075,7 @@ describe('object', () => { .keys({ a: Joi.string() }) .append(null); - expect(schema.validate({ a: 'x' }).error).to.not.exist(); + Helper.validate(schema, [[{ a: 'x' }, true]]); }); it('should not change schema if it is undefined', () => { @@ -1104,7 +1084,7 @@ describe('object', () => { .keys({ a: Joi.string() }) .append(undefined); - expect(schema.validate({ a: 'x' }).error).to.not.exist(); + Helper.validate(schema, [[{ a: 'x' }, true]]); }); it('should not change schema if it is empty-object', () => { @@ -1113,7 +1093,7 @@ describe('object', () => { .keys({ a: Joi.string() }) .append({}); - expect(schema.validate({ a: 'x' }).error).to.not.exist(); + Helper.validate(schema, [[{ a: 'x' }, true]]); }); }); @@ -1156,7 +1136,7 @@ describe('object', () => { }) .assert(Joi.ref('/d/e', { separator: '/' }), Joi.ref('a.c'), 'equal to a/c'); - expect(schema.validate({ a: { b: 'x', c: 5 }, d: { e: 6 } }).error).to.be.an.error('"value" is invalid because "d/e" failed to equal to a/c'); + Helper.validate(schema, [[{ a: { b: 'x', c: 5 }, d: { e: 6 } }, false, '"value" is invalid because "d/e" failed to equal to a/c']]); Helper.validate(schema, [ [{ a: { b: 'x', c: 5 }, d: { e: 5 } }, true] @@ -1177,16 +1157,18 @@ describe('object', () => { }) .assert(ref, Joi.ref('a.c'), 'equal to a.c'); - const err = schema.validate({ a: { b: 'x', c: 5 }, d: { e: 6 } }).error; - expect(err).to.be.an.error('"value" is invalid because "d.e" failed to equal to a.c'); - expect(err.details).to.equal([{ - message: '"value" is invalid because "d.e" failed to equal to a.c', - path: [], - type: 'object.assert', - context: { subject: ref, message: 'equal to a.c', label: 'value', value: { a: { b: 'x', c: 5 }, d: { e: 6 } } } - }]); - Helper.validate(schema, [ + [{ a: { b: 'x', c: 5 }, d: { e: 6 } }, false, { + message: '"value" is invalid because "d.e" failed to equal to a.c', + path: [], + type: 'object.assert', + context: { + subject: ref, + message: 'equal to a.c', + label: 'value', + value: { a: { b: 'x', c: 5 }, d: { e: 6 } } + } + }], [{ a: { b: 'x', c: 5 }, d: { e: 5 } }, true] ]); }); @@ -1248,9 +1230,7 @@ describe('object', () => { } }).assert(ref, Joi.boolean()); - const err = schema.validate({ d: { e: [] } }).error; - expect(err).to.be.an.error('"value" is invalid because "d.e" failed to pass the assertion test'); - expect(err.details).to.equal([{ + Helper.validate(schema, [[{ d: { e: [] } }, false, { message: '"value" is invalid because "d.e" failed to pass the assertion test', path: [], type: 'object.assert', @@ -1260,7 +1240,7 @@ describe('object', () => { label: 'value', value: { d: { e: [] } } } - }]); + }]]); }); it('works with keys()', () => { @@ -1271,7 +1251,7 @@ describe('object', () => { .keys({ b: { c: Joi.any() } }) .assert('.b.c', Joi.number()); - expect(schema.validate({ a: { b: 1 }, b: { c: 2 } }).error).to.not.exist(); + Helper.validate(schema, [[{ a: { b: 1 }, b: { c: 2 } }, true]]); }); it('uses templates', () => { @@ -1284,10 +1264,8 @@ describe('object', () => { }) .assert(subject, true, 'at least one key must be true'); - expect(schema.validate().error).to.not.exist(); - expect(schema.validate({ a: false, b: true, c: true }).error).to.not.exist(); - Helper.validate(schema, [ + [undefined, true], [{ a: true, b: true, c: true }, true], [{ a: true, b: false, c: false }, true], [{ a: false, b: true, c: false }, true], @@ -1318,13 +1296,13 @@ describe('object', () => { it('ignores null', () => { const schema = Joi.object({ a: Joi.number(), b: Joi.number() }).allow(null).cast('map'); - expect(schema.validate(null).value).to.be.null(); + Helper.validate(schema, [[null, true, null]]); }); it('ignores string', () => { const schema = Joi.object({ a: Joi.number(), b: Joi.number() }).allow('x').cast('map'); - expect(schema.validate('x').value).to.equal('x'); + Helper.validate(schema, [['x', true, 'x']]); }); it('does not leak casts to any', () => { @@ -1407,14 +1385,12 @@ describe('object', () => { }; const schema = Joi.object().instance(Foo); - const err = schema.validate({}).error; - expect(err).to.be.an.error('"value" must be an instance of "Foo"'); - expect(err.details).to.equal([{ + Helper.validate(schema, [[{}, false, { message: '"value" must be an instance of "Foo"', path: [], type: 'object.instance', context: { type: 'Foo', label: 'value', value: {} } - }]); + }]]); }); it('uses custom type name if supplied', () => { @@ -1423,14 +1399,12 @@ describe('object', () => { }; const schema = Joi.object().instance(Foo, 'Bar'); - const err = schema.validate({}).error; - expect(err).to.be.an.error('"value" must be an instance of "Bar"'); - expect(err.details).to.equal([{ + Helper.validate(schema, [[{}, false, { message: '"value" must be an instance of "Bar"', path: [], type: 'object.instance', context: { type: 'Bar', label: 'value', value: {} } - }]); + }]]); }); it('overrides constructor name with custom name', () => { @@ -1439,14 +1413,12 @@ describe('object', () => { }; const schema = Joi.object().instance(Foo, 'Bar'); - const err = schema.validate({}).error; - expect(err).to.be.an.error('"value" must be an instance of "Bar"'); - expect(err.details).to.equal([{ + Helper.validate(schema, [[{}, false, { message: '"value" must be an instance of "Bar"', path: [], type: 'object.instance', context: { type: 'Bar', label: 'value', value: {} } - }]); + }]]); }); it('throws when constructor is not a function', () => { @@ -1477,47 +1449,41 @@ describe('object', () => { const a = Joi.object({ a: 4 }); const b = a.keys(); - const err = a.validate({ b: 3 }).error; - expect(err).to.be.an.error('"b" is not allowed'); - expect(err.details).to.equal([{ + Helper.validate(a, [[{ b: 3 }, false, { message: '"b" is not allowed', path: ['b'], type: 'object.unknown', context: { child: 'b', label: 'b', key: 'b', value: 3 } - }]); + }]]); - expect(b.validate({ b: 3 }).error).to.not.exist(); + Helper.validate(b, [[{ b: 3 }, true]]); }); it('forbids all keys', () => { const a = Joi.object(); const b = a.keys({}); - expect(a.validate({ b: 3 }).error).to.not.exist(); - const err = b.validate({ b: 3 }).error; - expect(err).to.be.an.error('"b" is not allowed'); - expect(err.details).to.equal([{ + Helper.validate(a, [[{ b: 3 }, true]]); + Helper.validate(b, [[{ b: 3 }, false, { message: '"b" is not allowed', path: ['b'], type: 'object.unknown', context: { child: 'b', label: 'b', key: 'b', value: 3 } - }]); + }]]); }); it('adds to existing keys', () => { const a = Joi.object({ a: 1 }); const b = a.keys({ b: 2 }); - const err = a.validate({ a: 1, b: 2 }).error; - expect(err).to.be.an.error('"b" is not allowed'); - expect(err.details).to.equal([{ + Helper.validate(a, [[{ a: 1, b: 2 }, false, { message: '"b" is not allowed', path: ['b'], type: 'object.unknown', context: { child: 'b', label: 'b', key: 'b', value: 2 } - }]); + }]]); - expect(b.validate({ a: 1, b: 2 }).error).to.not.exist(); + Helper.validate(b, [[{ a: 1, b: 2 }, true]]); }); it('overrides existing keys', () => { @@ -1554,7 +1520,7 @@ describe('object', () => { b: Joi.string() }); - expect(schema.validate({ a: 'test', b: 'test' })).to.equal({ value: { b: 'test' } }); + Helper.validate(schema, [[{ a: 'test', b: 'test' }, true, { b: 'test' }]]); }); it('strips keys after validation', () => { @@ -1564,7 +1530,7 @@ describe('object', () => { b: Joi.string().default(Joi.ref('a')) }); - expect(schema.validate({ a: 'test' })).to.equal({ value: { b: 'test' } }); + Helper.validate(schema, [[{ a: 'test' }, true, { b: 'test' }]]); }); it('strips keys while preserving transformed values', () => { @@ -1575,19 +1541,15 @@ describe('object', () => { b: Joi.number().min(ref) }); - const result = schema.validate({ a: '1', b: '2' }); - expect(result.error).to.not.exist(); - expect(result.value.a).to.not.exist(); - expect(result.value.b).to.equal(2); - - const result2 = schema.validate({ a: '1', b: '0' }); - expect(result2.error).to.be.an.error('"b" must be larger than or equal to ref:a'); - expect(result2.error.details).to.equal([{ - message: '"b" must be larger than or equal to ref:a', - path: ['b'], - type: 'number.min', - context: { limit: ref, value: 0, label: 'b', key: 'b' } - }]); + Helper.validate(schema, [ + [{ a: '1', b: '2' }, true, { b: 2 }], + [{ a: '1', b: '0' }, false, { + message: '"b" must be larger than or equal to ref:a', + path: ['b'], + type: 'number.min', + context: { limit: ref, value: 0, label: 'b', key: 'b' } + }] + ]); }); it('does not alter the original object when stripping keys', () => { @@ -1613,7 +1575,7 @@ describe('object', () => { a: [Joi.boolean().strip()] }); - expect(schema.validate({ a: true })).to.equal({ value: {} }); + Helper.validate(schema, [[{ a: true }, true, {}]]); }); it('keeps keys in ref order', () => { @@ -1630,10 +1592,12 @@ describe('object', () => { { is: 'a', then: Joi.object({ flag: false }) } ]); - expect(schema.validate({ flag: true }).error).to.be.an.error('"type" is required'); - expect(schema.validate({ flag: true }).error).to.be.an.error('"type" is required'); - expect(schema.validate({ type: 'a', flag: true }).error).to.be.an.error('"flag" must be [false]'); - expect(schema.validate({ type: 'a', set: true, flag: true }).error).to.be.an.error('"flag" must be [false]'); + Helper.validate(schema, [ + [{ flag: true }, false, '"type" is required'], + [{ flag: true }, false, '"type" is required'], + [{ type: 'a', flag: true }, false, '"flag" must be [false]'], + [{ type: 'a', set: true, flag: true }, false, '"flag" must be [false]'] + ]); }); }); diff --git a/test/types/string.js b/test/types/string.js index d61f2b62a..421919732 100755 --- a/test/types/string.js +++ b/test/types/string.js @@ -26,9 +26,9 @@ describe('string', () => { it('blocks empty strings by default', () => { - expect(Joi.string().validate('').error).to.be.an.error('"value" is not allowed to be empty'); - expect(Joi.string().allow('x').validate('').error).to.be.an.error('"value" is not allowed to be empty'); - expect(Joi.string().allow('').validate('').error).to.not.exist(); + Helper.validate(Joi.string(), [['', false, '"value" is not allowed to be empty']]); + Helper.validate(Joi.string().allow('x'), [['', false, '"value" is not allowed to be empty']]); + Helper.validate(Joi.string().allow(''), [['', true]]); }); it('fails on boolean', () => { @@ -986,7 +986,6 @@ describe('string', () => { it('should validate credit card', () => { const t = Joi.string().creditCard(); - expect(t.validate('4111111111111112').error).to.be.an.error('"value" must be a credit card'); Helper.validate(t, [ ['378734493671000', true], // american express @@ -1479,14 +1478,12 @@ describe('string', () => { it('validates email with a friendly error message', () => { const schema = { item: Joi.string().email() }; - const err = Joi.compile(schema).validate({ item: 'something' }).error; - expect(err).to.be.an.error('"item" must be a valid email'); - expect(err.details).to.equal([{ + Helper.validate(Joi.compile(schema), [[{ item: 'something' }, false, { message: '"item" must be a valid email', path: ['item'], type: 'string.email', context: { value: 'something', invalids: ['something'], label: 'item', key: 'item' } - }]); + }]]); }); it('validates combination of email and min', () => { @@ -2741,14 +2738,12 @@ describe('string', () => { it('validates guid with a friendly error message', () => { const schema = { item: Joi.string().guid() }; - const err = Joi.compile(schema).validate({ item: 'something' }).error; - expect(err).to.be.an.error('"item" must be a valid GUID'); - expect(err.details).to.equal([{ + Helper.validate(Joi.compile(schema), [[{ item: 'something' }, false, { message: '"item" must be a valid GUID', path: ['item'], type: 'string.guid', context: { value: 'something', label: 'item', key: 'item' } - }]); + }]]); }); it('validates combination of guid and min', () => { @@ -4180,16 +4175,16 @@ describe('string', () => { it('sets right values with valid', () => { const simpleSchema = Joi.string().insensitive().valid('A'); - expect(simpleSchema.validate('a').value).to.equal('A'); + Helper.validate(simpleSchema, [['a', true, 'A']]); const refSchema = Joi.string().insensitive().valid(Joi.ref('$v')); - expect(refSchema.validate('a', { context: { v: 'A' } }).value).to.equal('A'); + Helper.validate(refSchema, { context: { v: 'A' } }, [['a', true, 'A']]); const refArraySchema = Joi.string().insensitive().valid(Joi.in('$v')); - expect(refArraySchema.validate('a', { context: { v: ['B', 'A'] } }).value).to.equal('A'); + Helper.validate(refArraySchema, { context: { v: ['B', 'A'] } }, [['a', true, 'A']]); const strictSchema = Joi.string().insensitive().valid('A').strict(); - expect(strictSchema.validate('a').value).to.equal('a'); + Helper.validate(strictSchema, [['a', true, 'a']]); }); }); @@ -4198,7 +4193,7 @@ describe('string', () => { it('should return false for denied value', () => { const text = Joi.string().invalid('joi'); - expect(text.validate('joi').error).to.be.an.error(); + Helper.validate(text, [['joi', false, '"value" contains an invalid value']]); }); it('validates invalid values', () => { @@ -4570,9 +4565,7 @@ describe('string', () => { it('validates ip with a friendly error message', () => { const schema = { item: Joi.string().ip() }; - const err = Joi.compile(schema).validate({ item: 'something' }).error; - expect(err).to.be.an.error('"item" must be a valid ip address with a optional CIDR'); - expect(err.details).to.equal([{ + Helper.validate(Joi.compile(schema), [[{ item: 'something' }, false, { message: '"item" must be a valid ip address with a optional CIDR', path: ['item'], type: 'string.ip', @@ -4582,15 +4575,13 @@ describe('string', () => { label: 'item', key: 'item' } - }]); + }]]); }); it('validates ip and cidr presence with a friendly error message', () => { const schema = { item: Joi.string().ip({ cidr: 'required' }) }; - const err = Joi.compile(schema).validate({ item: 'something' }).error; - expect(err).to.be.an.error('"item" must be a valid ip address with a required CIDR'); - expect(err.details).to.equal([{ + Helper.validate(Joi.compile(schema), [[{ item: 'something' }, false, { message: '"item" must be a valid ip address with a required CIDR', path: ['item'], type: 'string.ip', @@ -4600,15 +4591,13 @@ describe('string', () => { label: 'item', key: 'item' } - }]); + }]]); }); it('validates custom ip version and cidr presence with a friendly error message', () => { const schema = { item: Joi.string().ip({ version: 'ipv4', cidr: 'required' }) }; - const err = Joi.compile(schema).validate({ item: 'something' }).error; - expect(err).to.be.an.error('"item" must be a valid ip address of one of the following versions [ipv4] with a required CIDR'); - expect(err.details).to.equal([{ + Helper.validate(Joi.compile(schema), [[{ item: 'something' }, false, { message: '"item" must be a valid ip address of one of the following versions [ipv4] with a required CIDR', path: ['item'], type: 'string.ipVersion', @@ -4619,7 +4608,7 @@ describe('string', () => { label: 'item', key: 'item' } - }]); + }]]); }); describe('ip({ version: "ipv4" })', () => { @@ -5100,8 +5089,8 @@ describe('string', () => { it('validates isoDate with a friendly error message', () => { const schema = { item: Joi.string().isoDate() }; - expect(Joi.compile(schema).validate({ item: 'something' }).error).to.be.an.error('"item" must be in iso format'); - expect(Joi.compile(schema).validate({ item: 'something' }, { convert: false }).error).to.be.an.error('"item" must be in iso format'); + Helper.validate(Joi.compile(schema), [[{ item: 'something' }, false, '"item" must be in iso format']]); + Helper.validate(Joi.compile(schema), { convert: false }, [[{ item: 'something' }, false, '"item" must be in iso format']]); }); it('validates and formats isoDate with convert set to true (default)', () => { @@ -5357,7 +5346,7 @@ describe('string', () => { it('coerce string to lowercase before validation', () => { const schema = Joi.string().lowercase(); - expect(schema.validate('UPPER TO LOWER')).to.equal({ value: 'upper to lower' }); + Helper.validate(schema, [['UPPER TO LOWER', true, 'upper to lower']]); }); it('should work in combination with a trim', () => { @@ -6186,27 +6175,27 @@ describe('string', () => { it('normalizes string using NFC before validation', () => { - expect(Joi.string().normalize('NFC').validate(normalizations.original)).to.equal({ value: normalizations.NFC }); + Helper.validate(Joi.string().normalize('NFC'), [[normalizations.original, true, normalizations.NFC]]); }); it('normalizes string using NFD before validation', () => { - expect(Joi.string().normalize('NFD').validate(normalizations.original)).to.equal({ value: normalizations.NFD }); + Helper.validate(Joi.string().normalize('NFD'), [[normalizations.original, true, normalizations.NFD]]); }); it('normalizes string using NFKC before validation', () => { - expect(Joi.string().normalize('NFKC').validate(normalizations.original)).to.equal({ value: normalizations.NFKC }); + Helper.validate(Joi.string().normalize('NFKC'), [[normalizations.original, true, normalizations.NFKC]]); }); it('normalizes string using NFKD before validation', () => { - expect(Joi.string().normalize('NFKD').validate(normalizations.original)).to.equal({ value: normalizations.NFKD }); + Helper.validate(Joi.string().normalize('NFKD'), [[normalizations.original, true, normalizations.NFKD]]); }); it('should default to NFC form', () => { - expect(Joi.string().normalize().validate(normalizations.original)).to.equal({ value: normalizations.NFC }); + Helper.validate(Joi.string().normalize(), [[normalizations.original, true, normalizations.NFC]]); }); // The below tests use the composed and decomposed form @@ -6215,11 +6204,9 @@ describe('string', () => { it('should work in combination with min', () => { const baseSchema = Joi.string().min(2); - expect(baseSchema.normalize('NFD').validate('\u00F1')).to.equal({ value: 'n\u0303' }); + Helper.validate(baseSchema.normalize('NFD'), [['\u00F1', true, 'n\u0303']]); - const err = baseSchema.normalize('NFC').validate('n\u0303').error; - expect(err).to.be.an.error('"value" length must be at least 2 characters long'); - expect(err.details).to.equal([{ + Helper.validate(baseSchema.normalize('NFC'), [['n\u0303', false, { message: '"value" length must be at least 2 characters long', path: [], type: 'string.min', @@ -6229,17 +6216,15 @@ describe('string', () => { encoding: undefined, label: 'value' } - }]); + }]]); }); it('should work in combination with max', () => { const baseSchema = Joi.string().max(1); - expect(baseSchema.normalize('NFC').validate('n\u0303')).to.equal({ value: '\u00F1' }); + Helper.validate(baseSchema.normalize('NFC'), [['n\u0303', true, '\u00F1']]); - const err = baseSchema.normalize('NFD').validate('\u00F1').error; - expect(err).to.be.an.error('"value" length must be less than or equal to 1 characters long'); - expect(err.details).to.equal([{ + Helper.validate(baseSchema.normalize('NFD'), [['\u00F1', false, { message: '"value" length must be less than or equal to 1 characters long', path: [], type: 'string.max', @@ -6249,7 +6234,7 @@ describe('string', () => { encoding: undefined, label: 'value' } - }]); + }]]); }); it('composition should work in combination with length', () => { @@ -6331,15 +6316,15 @@ describe('string', () => { it('should work in combination with lowercase', () => { const baseSchema = Joi.string().lowercase(); - expect(baseSchema.normalize('NFC').validate('N\u0303')).to.equal({ value: '\u00F1' }); - expect(baseSchema.normalize('NFD').validate('\u00D1')).to.equal({ value: 'n\u0303' }); + Helper.validate(baseSchema.normalize('NFC'), [['N\u0303', true, '\u00F1']]); + Helper.validate(baseSchema.normalize('NFD'), [['\u00D1', true, 'n\u0303']]); }); it('should work in combination with uppercase', () => { const baseSchema = Joi.string().uppercase(); - expect(baseSchema.normalize('NFC').validate('n\u0303')).to.equal({ value: '\u00D1' }); - expect(baseSchema.normalize('NFD').validate('\u00F1')).to.equal({ value: 'N\u0303' }); + Helper.validate(baseSchema.normalize('NFC'), [['n\u0303', true, '\u00D1']]); + Helper.validate(baseSchema.normalize('NFD'), [['\u00F1', true, 'N\u0303']]); }); }); @@ -6373,9 +6358,7 @@ describe('string', () => { it('should not include a pattern name by default', () => { const schema = Joi.string().regex(/[a-z]+/).regex(/[0-9]+/); - const err = schema.validate('abcd').error; - expect(err).to.be.an.error('"value" with value "abcd" fails to match the required pattern: /[0-9]+/'); - expect(err.details).to.equal([{ + Helper.validate(schema, [['abcd', false, { message: '"value" with value "abcd" fails to match the required pattern: /[0-9]+/', path: [], type: 'string.pattern.base', @@ -6385,15 +6368,13 @@ describe('string', () => { value: 'abcd', label: 'value' } - }]); + }]]); }); it('should include a pattern name if specified', () => { const schema = Joi.string().regex(/[a-z]+/, 'letters').regex(/[0-9]+/, 'numbers'); - const err = schema.validate('abcd').error; - expect(err).to.be.an.error('"value" with value "abcd" fails to match the numbers pattern'); - expect(err.details).to.equal([{ + Helper.validate(schema, [['abcd', false, { message: '"value" with value "abcd" fails to match the numbers pattern', path: [], type: 'string.pattern.name', @@ -6403,15 +6384,13 @@ describe('string', () => { value: 'abcd', label: 'value' } - }]); + }]]); }); it('should include a pattern name in options object', () => { const schema = Joi.string().regex(/[a-z]+/, { name: 'letters' }).regex(/[0-9]+/, { name: 'numbers' }); - const err = schema.validate('abcd').error; - expect(err).to.be.an.error('"value" with value "abcd" fails to match the numbers pattern'); - expect(err.details).to.equal([{ + Helper.validate(schema, [['abcd', false, { message: '"value" with value "abcd" fails to match the numbers pattern', path: [], type: 'string.pattern.name', @@ -6421,7 +6400,7 @@ describe('string', () => { value: 'abcd', label: 'value' } - }]); + }]]); }); it('should "invert" regex pattern if specified in options object', () => { @@ -6503,7 +6482,7 @@ describe('string', () => { it('successfully replaces multiple times', () => { const schema = Joi.string().replace(/a/g, 'b').replace(/b/g, 'c'); - expect(schema.validate('a quick brown fox')).to.equal({ value: 'c quick crown fox' }); + Helper.validate(schema, [['a quick brown fox', true, 'c quick crown fox']]); }); it('should work in combination with trim', () => { @@ -6512,7 +6491,7 @@ describe('string', () => { // carriage return, a "full width" ideographic space and a newline const schema = Joi.string().trim().replace(/\s+/g, ' '); - expect(schema.validate(' \u5C71\u7530\r\u3000\n\u592A\u90CE ')).to.equal({ value: '\u5C71\u7530 \u592A\u90CE' }); + Helper.validate(schema, [[' \u5C71\u7530\r\u3000\n\u592A\u90CE ', true, '\u5C71\u7530 \u592A\u90CE']]); }); it('should work in combination with min', () => { @@ -6588,28 +6567,24 @@ describe('string', () => { it('prints a friend error message for an empty string', () => { const schema = Joi.string().required(); - const err = Joi.compile(schema).validate('').error; - expect(err).to.be.an.error('"value" is not allowed to be empty'); - expect(err.details).to.equal([{ + Helper.validate(Joi.compile(schema), [['', false, { message: '"value" is not allowed to be empty', path: [], type: 'string.empty', context: { value: '', label: 'value' } - }]); + }]]); }); it('prints a friendly error message for trimmed whitespace', () => { const schema = Joi.string().trim().required(); - const err = Joi.compile(schema).validate(' ').error; - expect(err).to.be.an.error('"value" is not allowed to be empty'); - expect(err.details).to.equal([{ + Helper.validate(Joi.compile(schema), [[' ', false, { message: '"value" is not allowed to be empty', path: [], type: 'string.empty', context: { value: '', label: 'value' } - }]); + }]]); }); it('validates non-empty strings', () => { @@ -6705,13 +6680,13 @@ describe('string', () => { it('removes leading and trailing whitespace before validation', () => { const schema = Joi.string().trim(); - expect(schema.validate(' trim this ')).to.equal({ value: 'trim this' }); + Helper.validate(schema, [[' trim this ', true, 'trim this']]); }); it('removes leading and trailing whitespace before validation', () => { const schema = Joi.string().trim().allow(''); - expect(schema.validate(' ')).to.equal({ value: '' }); + Helper.validate(schema, [[' ', true, '']]); }); it('should work in combination with min', () => { @@ -6853,7 +6828,7 @@ describe('string', () => { it('does not change anything when used without max', () => { const schema = Joi.string().min(2).truncate(); - expect(schema.validate('fooooooooooooooooooo')).to.equal({ value: 'fooooooooooooooooooo' }); + Helper.validate(schema, [['fooooooooooooooooooo', true, 'fooooooooooooooooooo']]); }); it('truncates a string when used with max', () => { @@ -6934,7 +6909,7 @@ describe('string', () => { it('coerce string to uppercase before validation', () => { const schema = Joi.string().uppercase(); - expect(schema.validate('lower to upper')).to.equal({ value: 'LOWER TO UPPER' }); + Helper.validate(schema, [['lower to upper', true, 'LOWER TO UPPER']]); }); it('works in combination with a forced trim', () => { @@ -7377,8 +7352,7 @@ describe('string', () => { const schema = { item: Joi.string().uri() }; - const err = Joi.compile(schema).validate({ item: 'something invalid' }).error; - expect(err.message).to.contain('must be a valid uri'); + Helper.validate(Joi.compile(schema), [[{ item: 'something invalid' }, false, '"item" must be a valid uri']]); }); it('validates uri with a custom scheme with a friendly error message', () => { @@ -7389,8 +7363,7 @@ describe('string', () => { }) }; - const err = Joi.compile(schema).validate({ item: 'something invalid' }).error; - expect(err.message).to.contain('must be a valid uri with a scheme matching the http pattern'); + Helper.validate(Joi.compile(schema), [[{ item: 'something invalid' }, false, '"item" must be a valid uri with a scheme matching the http pattern']]); }); it('validates uri with a custom array of schemes with a friendly error message', () => { @@ -7401,8 +7374,7 @@ describe('string', () => { }) }; - const err = Joi.compile(schema).validate({ item: 'something invalid' }).error; - expect(err.message).to.contain('must be a valid uri with a scheme matching the http|https? pattern'); + Helper.validate(Joi.compile(schema), [[{ item: 'something invalid' }, false, '"item" must be a valid uri with a scheme matching the http|https? pattern']]); }); it('validates uri treats scheme as optional', () => { diff --git a/test/types/symbol.js b/test/types/symbol.js index 6be0bf220..9a84be794 100755 --- a/test/types/symbol.js +++ b/test/types/symbol.js @@ -181,21 +181,19 @@ describe('symbol', () => { const symbols = [Symbol(1), Symbol(2)]; const schema = Joi.symbol().map([[1, symbols[0]], ['two', symbols[1]]]).prefs({ convert: false }); - expect(schema.validate(symbols[1])).to.equal({ value: symbols[1] }); + Helper.validate(schema, [[symbols[1], true, symbols[1]]]); }); it('errors on mapped input and convert is disabled', () => { const symbols = [Symbol(1), Symbol(2)]; const schema = Joi.symbol().map([[1, symbols[0]], ['two', symbols[1]]]).prefs({ convert: false }); - const err = schema.validate(1).error; - expect(err).to.be.an.error('"value" must be one of [Symbol(1), Symbol(2)]'); - expect(err.details).to.equal([{ + Helper.validate(schema, [[1, false, { message: '"value" must be one of [Symbol(1), Symbol(2)]', path: [], type: 'any.only', context: { value: 1, valids: symbols, label: 'value' } - }]); + }]]); }); }); });