UNPKG

felicity

Version:

Javascript object instantiation from Joi schema

1,644 lines (1,165 loc) 53.4 kB
'use strict'; const Hoek = require('@hapi/hoek'); const Lab = require('@hapi/lab'); const Moment = require('moment'); const Joi = require('../lib/joi'); const { permutations, expectValidation } = require('./test_helpers'); const ValueGenerator = require('../lib/exampleGenerator'); const { describe, expect, it } = exports.lab = Lab.script(); const ExpectValidation = expectValidation(expect); describe('Any', () => { it('should default to string', () => { const schema = Joi.any(); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return an "allow"ed value', () => { let schema = Joi.any().allow('allowed'); ExpectValidation(ValueGenerator(schema), schema); let examples = {}; schema = Joi.any().allow('allowed1', 'allowed2'); for (let i = 0; i < 10; ++i) { const example = ValueGenerator(schema); examples[example] = true; ExpectValidation(example, schema); } expect(examples.allowed1).to.exist(); expect(examples.allowed2).to.exist(); examples = {}; schema = Joi.any().allow('first', 'second', true, 10); for (let i = 0; i < 25; ++i) { const example = ValueGenerator(schema); examples[example] = true; ExpectValidation(example, schema); } expect(['first', 'second', 'true', '10'].filter((valid) => examples[valid] !== undefined).length).to.equal(4); }); it('should ignore "allow"ed values when provided the "ignoreValids" option', () => { const schema = Joi.any().allow(null); const example = ValueGenerator(schema, { config: { ignoreValids: true } }); expect(example).to.be.a.string(); ExpectValidation(example, schema); }); it('should return a "valid" value', () => { let schema = Joi.any().valid('allowed'); let example = ValueGenerator(schema); expect(example).to.equal('allowed'); ExpectValidation(example, schema); schema = Joi.any().valid('allowed1', 'allowed2'); example = ValueGenerator(schema); expect(['allowed1', 'allowed2'].indexOf(example)).to.not.equal(-1); ExpectValidation(example, schema); schema = Joi.any().valid(true, 10); example = ValueGenerator(schema); expect([true, 10].indexOf(example)).to.not.equal(-1); ExpectValidation(example, schema); }); it('should return an "example" value from a single argument', () => { const schema = Joi.any().example(123); const example = ValueGenerator(schema); expect(example).to.equal(123); ExpectValidation(example, schema); }); it('should return an "example" value from multiple arguments', () => { const examples = [123, 321]; const schema = Joi.any().example(examples); const example = ValueGenerator(schema); const foundExample = examples.find((ex) => ex === example); expect(foundExample).to.equal(example); ExpectValidation(example, schema); }); it('should return an "example" value from a single array argument', () => { const schema = Joi.any().example([123]); const example = ValueGenerator(schema); expect(example).to.equal(123); ExpectValidation(example, schema); }); it('should return an "example" value from multiple single array arguments', () => { const examples = [[123], [321]]; const schema = Joi.any().example(examples); const example = ValueGenerator(schema); const [foundExample] = examples.find(([ex]) => ex === example); expect(foundExample).to.equal(example); ExpectValidation(example, schema); }); it('should return a default value', () => { const schema = Joi.any().default(123); const example = ValueGenerator(schema); expect(example).to.equal(123); ExpectValidation(example, schema); }); it('should return a dynamic default value', () => { const generateDefault = function () { return true; }; generateDefault.description = 'generates default'; const schema = Joi.any().default(generateDefault); const example = ValueGenerator(schema); expect(example).to.equal(true); ExpectValidation(example, schema); }); }); describe('String', () => { it('should return a basic string', () => { const schema = Joi.string(); const example = ValueGenerator(schema); expect(example).to.be.a.string(); ExpectValidation(example, schema); }); it('should return a string with valid value', () => { const schema = Joi.string().valid('a'); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return a GUID', () => { const schema = Joi.string().guid(); const example = ValueGenerator(schema); expect(example).to.be.a.string(); ExpectValidation(example, schema); }); it('should return a GUID with UUID syntax', () => { const schema = Joi.string().uuid(); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return an email', () => { const schema = Joi.string().email(); const example = ValueGenerator(schema); expect(example).to.be.a.string(); ExpectValidation(example, schema); }); it('should return default value', () => { const schema = Joi.string().default('fallback'); const example = ValueGenerator(schema); expect(example).to.equal('fallback'); ExpectValidation(example, schema); }); it('should return default value when valids are ignored', () => { const schema = Joi.string().valid('value1', 'value2', 'fallback').default('fallback'); const example = ValueGenerator(schema, { config: { ignoreValids: true } }); expect(example).to.equal('fallback'); ExpectValidation(example, schema); }); it('should utilize dynamic default function', () => { const defaultGenerator = function () { return 'fallback'; }; defaultGenerator.description = 'generates a default'; const schema = Joi.string().default(defaultGenerator); const example = ValueGenerator(schema); expect(example).to.equal('fallback'); ExpectValidation(example, schema); }); it('should return a string which adheres to .min requirement', () => { for (let i = 0; i <= 5; ++i) { const min = Math.ceil((Math.random() + 1) * Math.pow(1 + i, i)); const schema = Joi.string().min(min); const example = ValueGenerator(schema); expect(example.length).to.be.at.least(min); ExpectValidation(example, schema); } }); it('should return a string which adheres to .max requirement', () => { for (let i = 0; i <= 5; ++i) { const max = Math.ceil((Math.random() + 1) * Math.pow(1 + i, i)); const schema = Joi.string().max(max); const example = ValueGenerator(schema); expect(example.length).to.be.at.most(max); ExpectValidation(example, schema); } }); it('should return a string which adheres to both .min and .max requirements', () => { for (let i = 4; i <= 25; ++i) { const max = Math.ceil(Math.random() * i + 1); const possibleMin = max - Math.floor(Math.random() * i + 1); const min = possibleMin < 1 ? 1 : possibleMin; const schema = Joi.string().min(min).max(max); const example = ValueGenerator(schema); expect(example.length).to.be.at.most(max).and.at.least(min); ExpectValidation(example, schema); } const largeMax = 750; const largeMin = 500; const largeSchema = Joi.string().min(largeMin).max(largeMax); const largeExample = ValueGenerator(largeSchema); expect(largeExample.length).to.be.at.most(largeMax).and.at.least(largeMin); ExpectValidation(largeExample, largeSchema); }); it('should return a string which adheres to .length requirement', () => { for (let i = 0; i <= 5; ++i) { const length = Math.ceil((Math.random() + 1) * Math.pow(1 + i, i)); const schema = Joi.string().length(length); const example = ValueGenerator(schema); expect(example.length).to.equal(length); ExpectValidation(example, schema); } }); it('should return a string which adheres to .isoDate requirement', () => { const schema = Joi.string().isoDate(); const example = ValueGenerator(schema); expect((new Date(example)).toISOString()).to.equal(example); ExpectValidation(example, schema); }); it('should return a string that matches the given regexp', () => { const regex = new RegExp(/[a-c]{3}-[d-f]{3}-[0-9]{4}/); const schema = Joi.string().regex(regex); const example = ValueGenerator(schema); expect(example.match(regex)).to.not.equal(null); ExpectValidation(example, schema); }); it('should return a string that does not match the inverted regexp', () => { const regex = new RegExp(/[a-c]{3}-[d-f]{3}-[0-9]{4}/); const schema = Joi.string().regex(regex, { invert: true }); const example = ValueGenerator(schema); expect(example.match(regex)).to.equal(null); ExpectValidation(example, schema); }); it('should return a case-insensitive string', () => { const schema = Joi.string().valid('A').insensitive(); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return a Luhn-valid credit card number', () => { const schema = Joi.string().creditCard(); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return a hexadecimal string', () => { const schema = Joi.string().hex(); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return a hexadecimal string between min and max', () => { const schema = Joi.string().hex().min(128).max(130); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return a token', () => { const schema = Joi.string().token(); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return an alphanumeric string', () => { const schema = Joi.string().alphanum(); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return a hostname', () => { const schema = Joi.string().hostname(); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return a IPv4 when given no options', () => { const schema = Joi.string().ip(); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return a IPv4 when given options and cidr is forbidden', () => { const schema = Joi.string().ip( { cidr: 'forbidden' }); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return a IPv4 when given options', () => { const schema = Joi.string().ip( { version: ['ipv4'] }); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return a IPv4 when given options and cidr is forbidden', () => { const schema = Joi.string().ip( { version: ['ipv4'], cidr: 'forbidden' }); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return a IPv6 when given options', () => { const schema = Joi.string().ip( { version: ['ipv6'] }); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return a IPv6 when given options and cidr is forbidden', () => { const schema = Joi.string().ip( { version: ['ipv6'], cidr: 'forbidden' }); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return uppercase value', () => { const schema = Joi.string().uppercase(); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return uppercase value for guid to test chaining', () => { const schema = Joi.string().guid().uppercase(); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return lowercase value', () => { const schema = Joi.string().lowercase(); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return example.com for .uri', () => { const schema = Joi.string().uri(); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); }); describe('Number', () => { it('should return a number', () => { const schema = Joi.number(); const example = ValueGenerator(schema); expect(example).to.be.a.number(); ExpectValidation(example, schema); }); it('should return a default value > 0', () => { const schema = Joi.number().default(9); const example = ValueGenerator(schema); expect(example).to.equal(9); ExpectValidation(example, schema); }); it('should return a default value === 0', () => { const schema = Joi.number().default(0); const example = ValueGenerator(schema); expect(example).to.equal(0); ExpectValidation(example, schema); }); it('should return a dynamic default', () => { const generateNumber = () => 0; generateNumber.description = 'default description'; const schema = Joi.number().default(generateNumber); const example = ValueGenerator(schema); expect(example).to.equal(0); ExpectValidation(example, schema); }); it('should return a valid value instead of default', () => { const schema = Joi.number().valid(2).default(1); const example = ValueGenerator(schema); expect(example).to.equal(2); ExpectValidation(example, schema); }); it('should return a negative number', () => { const schema = Joi.number().negative(); const example = ValueGenerator(schema); expect(example).to.be.below(0); ExpectValidation(example, schema); }); it('should return an integer', () => { const schema = Joi.number().integer(); const example = ValueGenerator(schema); expect(example % 1).to.equal(0); ExpectValidation(example, schema); }); it('should return a number which adheres to .min requirement', () => { const schema = Joi.number().min(20); const example = ValueGenerator(schema); expect(example).to.be.at.least(20); ExpectValidation(example, schema); }); it('should return a number which adheres to .max requirement', () => { const schema = Joi.number().max(2); const example = ValueGenerator(schema); expect(example).to.be.at.most(2); ExpectValidation(example, schema); }); it('should return a number which has equal .min and .max requirements', () => { const schema = Joi.number().min(1).max(1); const example = ValueGenerator(schema); expect(example).to.equal(1); ExpectValidation(example, schema); }); it('should return a number which adheres to .greater requirement', () => { const schema = Joi.number().greater(20); const example = ValueGenerator(schema); expect(example).to.be.at.least(20); ExpectValidation(example, schema); }); it('should return a number which adheres to .less requirement', () => { const schema = Joi.number().less(2); const example = ValueGenerator(schema); expect(example).to.be.at.most(2); ExpectValidation(example, schema); }); it('should return a number which adheres to .precision requirement', () => { for (let i = 0; i < 500; ++i) { const schema = Joi.number().precision(2); const example = ValueGenerator(schema); expect(example.toString().split('.')[1].length).to.be.at.most(2); ExpectValidation(example, schema); } }); it('should return a number which adheres to .multiple requirement', () => { const schema = Joi.number().multiple(4); const example = ValueGenerator(schema); expect(example % 4).to.equal(0); ExpectValidation(example, schema); }); it('should return a number which adheres to .multiple requirement in conjunction with min and max', () => { const schema = Joi.number().multiple(6).min(5).max(8); const example = ValueGenerator(schema); expect(example % 2).to.equal(0); ExpectValidation(example, schema); }); it('should return numbers which adhere to any valid combination of requirements', () => { const requirements = [ 'positive', 'negative', 'integer', 'min', 'max', 'greater', 'less', 'precision', 'multiple' ]; const requirementExclusions = { positive: ['positive','negative'], negative: ['negative','positive'], precision: ['precision','integer', 'multiple'], integer: ['integer','precision'], multiple: ['multiple','precision'], max: ['max','less'], less: ['less','max'], min: ['min','greater'], greater: ['greater','min'] }; const optionArguments = { min: 16, max: 56, greater: 35, less: 45, precision: 3, multiple: 8 }; const numberOptions = permutations(requirements, requirementExclusions); numberOptions.forEach((optionSet) => { let schema = Joi.number(); const setContainsNegative = optionSet.indexOf('negative') !== -1; const setContainsMinAndMax = Hoek.intersect(optionSet, ['min', 'greater']).length > 0 && Hoek.intersect(optionSet, ['max', 'less']).length > 0; optionSet.forEach((option) => { let optionArgument = setContainsNegative ? 0 - optionArguments[option] : optionArguments[option]; if (option === 'multiple' || option === 'precision') { optionArgument = Math.abs(optionArgument); } else if (setContainsNegative && setContainsMinAndMax && (option === 'min' || option === 'greater') ) { optionArgument = 0 - optionArguments.max; } else if (setContainsNegative && setContainsMinAndMax && (option === 'max' || option === 'less')) { optionArgument = 0 - optionArguments.min; } schema = schema[option](optionArgument); }); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); }); it('should return NaN for impossible combinations', () => { const impossibleMinSchema = Joi.number().negative().min(1); let example = ValueGenerator(impossibleMinSchema); expect(example).to.equal(NaN); example = 0; const impossibleMinMultipleSchema = Joi.number().negative().min(-10).multiple(12); example = ValueGenerator(impossibleMinMultipleSchema); expect(example).to.equal(NaN); }); }); describe('Boolean', () => { it('should return a boolean', () => { const schema = Joi.boolean(); const example = ValueGenerator(schema); expect(example).to.be.a.boolean(); ExpectValidation(example, schema); }); it('should return default "true" value', () => { for (let i = 0; i < 10; ++i) { const schema = Joi.boolean().default(true); const example = ValueGenerator(schema); expect(example).to.equal(true); } }); it('should return default "false" value', () => { for (let i = 0; i < 10; ++i) { const schema = Joi.boolean().default(false); const example = ValueGenerator(schema); expect(example).to.equal(false); } }); it('should return valid value', () => { for (let i = 0; i < 10; ++i) { const schema = Joi.boolean().valid(true).default(false); const example = ValueGenerator(schema); expect(example).to.equal(true); } }); it('should return a truthy value when singlar number', () => { const schema = Joi.boolean().truthy(1); const example = ValueGenerator(schema); expect(example).to.be.a.number(); expect(example).to.equal(1); ExpectValidation(example, schema); }); it('should return a truthy value when singlar string', () => { const schema = Joi.boolean().truthy('y'); const example = ValueGenerator(schema); expect(example).to.be.a.string(); expect(example).to.equal('y'); ExpectValidation(example, schema); }); it('should return a truthy value when pluralized', () => { const schema = Joi.boolean().truthy(1, 'y'); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return a falsy value when singlar number', () => { const schema = Joi.boolean().falsy(0); const example = ValueGenerator(schema); expect(example).to.be.a.number(); expect(example).to.equal(0); ExpectValidation(example, schema); }); it('should return a falsy value when singlar string', () => { const schema = Joi.boolean().falsy('n'); const example = ValueGenerator(schema); expect(example).to.be.a.string(); expect(example).to.equal('n'); ExpectValidation(example, schema); }); it('should return a falsy value when pluralized', () => { const schema = Joi.boolean().falsy(0, 'n'); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should validate when a mix of truthy and falsy is set', () => { const schema = Joi.boolean().truthy(1, 'y').falsy(0, 'n'); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); }); describe('Binary', () => { it('should return a buffer', () => { const schema = Joi.binary(); const example = ValueGenerator(schema); expect(example).to.be.a.buffer(); ExpectValidation(example, schema); }); it('should return a string with specified encoding', () => { const supportedEncodings = [ 'base64', 'utf8', 'ascii', 'utf16le', 'ucs2', 'hex' ]; supportedEncodings.forEach((encoding) => { const schema = Joi.binary().encoding(encoding); const example = ValueGenerator(schema); expect(example).to.be.a.string(); ExpectValidation(example, schema); }); }); it('should return a buffer of minimum size', () => { const schema = Joi.binary().min(100); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return a buffer of maximum size', () => { const schema = Joi.binary().max(100); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return a buffer of specified size', () => { const schema = Joi.binary().length(75); const example = ValueGenerator(schema); expect(example.length).to.equal(75); ExpectValidation(example, schema); }); it('should return a buffer of size between min and max', () => { const schema = Joi.binary().min(27).max(35); const example = ValueGenerator(schema); expect(example.length).to.be.at.least(27).and.at.most(35); ExpectValidation(example, schema); }); it('should return a dynamic default buffer', () => { const defaultBuffer = Buffer.alloc(10); const generateDefault = () => defaultBuffer; generateDefault.description = 'generates default'; const schema = Joi.binary().default(generateDefault); const example = ValueGenerator(schema); expect(example).to.be.a.buffer(); expect(example).to.equal(defaultBuffer); ExpectValidation(example, schema); }); }); describe('Date', () => { it('should return a date', () => { const schema = Joi.date(); const example = ValueGenerator(schema); expect(example).to.be.a.date(); ExpectValidation(example, schema); }); it('should return a Date more recent than .min value', () => { const schema = Joi.date().min('1/01/3016'); const example = ValueGenerator(schema); expect(example).to.be.above(new Date('1/01/3016')); ExpectValidation(example, schema); }); it('should return a Date more recent than "now"', () => { const schema = Joi.date().min('now'); const now = new Date(); const example = ValueGenerator(schema); expect(example).to.be.above(now); ExpectValidation(example, schema); }); it('should return a Date less recent than .max value', () => { const schema = Joi.date().max('1/01/1968'); const example = ValueGenerator(schema); expect(example).to.be.below(new Date(0)); ExpectValidation(example, schema); }); it('should return a Date less recent than "now"', () => { const schema = Joi.date().max('now'); const now = new Date(); const example = ValueGenerator(schema); expect(example).to.be.below(now); ExpectValidation(example, schema); }); it('should return a Date between .min and .max values', () => { for (let i = 1; i <= 20; ++i) { const minYear = 2000 + Math.ceil((Math.random() * 100)); const maxYear = minYear + Math.ceil((Math.random()) * 10); const min = '1/01/' + minYear.toString(); const max = '1/01/' + maxYear.toString(); const schema = Joi.date().min(min).max(max); const example = ValueGenerator(schema); expect(example).to.be.above(new Date(min)).and.below(new Date(max)); ExpectValidation(example, schema); } const smallMin = '1/01/2016'; const smallMax = '3/01/2016'; const smallSchema = Joi.date().min(smallMin).max(smallMax); const smallExample = ValueGenerator(smallSchema); ExpectValidation(smallExample, smallSchema); }); it('should return a Date in ISO format', () => { const schema = Joi.date().iso(); const example = ValueGenerator(schema); expect(example).to.be.a.string(); ExpectValidation(example, schema); }); it('should return a timestamp', () => { const schema = Joi.date().timestamp(); const example = ValueGenerator(schema); expect(example).to.be.a.number(); ExpectValidation(example, schema); }); it('should return a unix timestamp', () => { const schema = Joi.date().timestamp('unix'); const example = ValueGenerator(schema); expect(example).to.be.a.number(); ExpectValidation(example, schema); }); it('should return a moment formatted date', () => { const fmt = 'HH:mm'; const schema = Joi.date().format(fmt); const example = ValueGenerator(schema); const moment = new Moment(example, fmt, true); expect(example).to.be.a.string(); expect(moment.isValid()).to.equal(true); ExpectValidation(example, schema); }); it('should return a moment formatted date with Joi version <= 10.2.1', () => { const fmt = 'HH:mm'; const schema = Joi.date().format(fmt); schema._flags.momentFormat = fmt; const example = ValueGenerator(schema); const moment = new Moment(example, fmt, true); expect(example).to.be.a.string(); expect(moment.isValid()).to.equal(true); ExpectValidation(example, schema); }); it('should return one of the allowed moment formatted dates', () => { const fmt = ['HH:mm', 'YYYY/MM/DD']; const schema = Joi.date().format(fmt); const example = ValueGenerator(schema); const moment = new Moment(example, fmt, true); expect(example).to.be.a.string(); expect(moment.isValid()).to.equal(true); ExpectValidation(example, schema); }); }); describe('Function', () => { it('should return a function', () => { const schema = Joi.func(); const example = ValueGenerator(schema); expect(example).to.be.a.function(); ExpectValidation(example, schema); }); it('should return a function with arity(1)', () => { const schema = Joi.func().arity(1); const example = ValueGenerator(schema); expect(example).to.be.a.function(); ExpectValidation(example, schema); }); it('should return a function with arity(10)', () => { const schema = Joi.func().arity(10); const example = ValueGenerator(schema); expect(example).to.be.a.function(); ExpectValidation(example, schema); }); it('should return a function with minArity(3)', () => { const schema = Joi.func().minArity(3); const example = ValueGenerator(schema); expect(example).to.be.a.function(); ExpectValidation(example, schema); }); it('should return a function with maxArity(4)', () => { const schema = Joi.func().maxArity(4); const example = ValueGenerator(schema); expect(example).to.be.a.function(); ExpectValidation(example, schema); }); it('should return a function with minArity(3) and maxArity(4)', () => { const schema = Joi.func().minArity(3).maxArity(4); const example = ValueGenerator(schema); expect(example).to.be.a.function(); ExpectValidation(example, schema); }); }); describe('Array', () => { it('should return an array', () => { const schema = Joi.array(); const example = ValueGenerator(schema); expect(example).to.be.an.array(); ExpectValidation(example, schema); }); it('should return an array with valid items', () => { const schema = Joi.array().items(Joi.number().required(), Joi.string().guid().required(), Joi.array().items(Joi.number().integer().min(43).required()).required()); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return an array with valid items and without forbidden items', () => { const schema = Joi.array().items(Joi.string().forbidden(), Joi.number().multiple(3)); const example = ValueGenerator(schema); const stringItems = example.filter((item) => { return typeof item === 'string'; }); expect(stringItems.length).to.equal(0); ExpectValidation(example, schema); }); it('should return an empty array with "sparse"', () => { const schema = Joi.array() .items(Joi.number()) .sparse(); const example = ValueGenerator(schema); expect(example.length).to.equal(0); ExpectValidation(example, schema); }); it('should return an ordered array', () => { const schema = Joi.array().ordered(Joi.string().max(3).required(), Joi.number().negative().integer().required(), Joi.boolean().required()); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return an array with "length" random items', () => { const schema = Joi.array().length(4); const example = ValueGenerator(schema); expect(example.length).to.equal(4); ExpectValidation(example, schema); }); it('should return an array with examples that match item types and in the same order', () => { const schema = Joi.array().length(2).items(Joi.string(), Joi.number().integer()); const example = ValueGenerator(schema); expect(example.length).to.equal(2); expect(example[0]).to.be.a.string(); expect(example[1]).to.be.a.number(); ExpectValidation(example, schema); }); it('should return an array with "length" specified items', () => { const schema = Joi.array() .items(Joi.number().integer(), Joi.string().guid(), Joi.boolean()) .length(10); const example = ValueGenerator(schema); expect(example.length).to.equal(10); ExpectValidation(example, schema); }); it('should return an array with no more than "length" specified items', () => { const schema = Joi.array() .items(Joi.number().integer(), Joi.string().guid(), Joi.boolean()) .length(2); const example = ValueGenerator(schema); expect(example.length).to.equal(2); ExpectValidation(example, schema); }); it('should return an array with "min" random items', () => { const schema = Joi.array().min(4); const example = ValueGenerator(schema); expect(example.length).to.equal(4); ExpectValidation(example, schema); }); it('should return an array with "min" specified items', () => { const schema = Joi.array() .items(Joi.number().integer(), Joi.string().guid(), Joi.boolean()) .min(3); const example = ValueGenerator(schema); expect(example.length).to.equal(3); ExpectValidation(example, schema); }); it('should return an array with "min" specified items that all match the provided types', () => { const schema = Joi.array() .items(Joi.number().integer(), Joi.string().guid()) .min(4); const example = ValueGenerator(schema); const eitherIntOrGuid = example.some((ex) => { return typeof ex === 'string' || typeof ex === 'number'; }); expect(example.length).to.equal(4); expect(eitherIntOrGuid).to.equal(true); ExpectValidation(example, schema); }); it('should return an array with "max" random items', () => { const schema = Joi.array().max(4); const example = ValueGenerator(schema); expect(example.length).to.be.at.least(1); expect(example.length).to.be.at.most(4); ExpectValidation(example, schema); }); it('should return an array with "max" specified items', () => { const schema = Joi.array() .items(Joi.number().integer(), Joi.string().guid(), Joi.boolean()) .max(10); const example = ValueGenerator(schema); expect(example.length).to.be.at.least(1); expect(example.length).to.be.at.most(10); ExpectValidation(example, schema); }); it('should return an array with "min" and "max" random items', () => { const schema = Joi.array() .min(4) .max(5); const example = ValueGenerator(schema); expect(example.length).to.be.at.least(4); expect(example.length).to.be.at.most(5); ExpectValidation(example, schema); }); it('should return an array with "min" and "max" specified items', () => { const schema = Joi.array() .items(Joi.number().integer(), Joi.string().guid(), Joi.boolean()) .min(10) .max(15); const example = ValueGenerator(schema); expect(example.length).to.be.at.least(10); expect(example.length).to.be.at.most(15); ExpectValidation(example, schema); }); it('should return a semi-ordered array with "min" specified items', () => { const schema = Joi.array() .ordered(Joi.string(), Joi.number()) .items(Joi.boolean().required()) .min(6); const example = ValueGenerator(schema); expect(example[0]).to.be.a.string(); expect(example[1]).to.be.a.number(); expect(example.length).to.be.at.least(6); ExpectValidation(example, schema); }); it('should return a single item array with a number', () => { const schema = Joi.array().items(Joi.number().required()).single(); const example = ValueGenerator(schema); expect(example).to.be.a.number(); ExpectValidation(example, schema); }); it('should return a single item with a number', () => { const schema = Joi.array().items(Joi.number().required()).single(false); const example = ValueGenerator(schema); expect(example[0]).to.be.a.number(); ExpectValidation(example, schema); }); it('should return a default array', () => { const schema = Joi.array().default([1, 2, 3]); const example = ValueGenerator(schema); expect(example[0]).to.be.a.number(); ExpectValidation(example, schema); }); }); describe('Alternatives', () => { it('should return one of the "try" schemas', () => { const schema = Joi.alternatives() .try(Joi.string(), Joi.number()); const example = ValueGenerator(schema); expect(example).to.not.be.undefined(); ExpectValidation(example, schema); }); it('should return the single "try" schema', () => { const schema = Joi.alternatives() .try(Joi.string()); const example = ValueGenerator(schema); expect(example).to.be.a.string(); ExpectValidation(example, schema); }); it('should return the single "try" object schema', () => { const schema = Joi.alternatives() .try(Joi.object().keys({ a: Joi.string() })); const example = ValueGenerator(schema); expect(example).to.be.an.object(); ExpectValidation(example, schema); }); it('should return the single "try" object schema with additional key constraints', () => { const schema = Joi.alternatives() .try(Joi.object().keys({ a: Joi.string().lowercase(), b: Joi.string().guid(), c: Joi.string().regex(/a{3}b{3}c{3}/), d: Joi.object().keys({ e: Joi.string().alphanum().uppercase() }) })); const example = ValueGenerator(schema); expect(example).to.be.an.object(); ExpectValidation(example, schema); }); it('should return "conditional" alternative', () => { const schema = Joi.object().keys({ dependent: Joi.alternatives().conditional('sibling.driver', { is: Joi.string(), then: Joi.string().lowercase() }), sibling: Joi.object().keys({ driver: Joi.string() }) }); const example = ValueGenerator(schema); expect(example.dependent).to.be.a.string(); ExpectValidation(example, schema); }); it('should return "when.otherwise" alternative', () => { const schema = Joi.object().keys({ dependent: Joi.alternatives().conditional('sibling.driver', { is: Joi.string(), then: Joi.string(), otherwise: Joi.number().integer() }), sibling: Joi.object().keys({ driver: Joi.boolean() }) }); const example = ValueGenerator(schema); expect(example.dependent).to.be.a.number(); ExpectValidation(example, schema); }); it('should return the base value when "when.otherwise" is undefined', () => { const schema = Joi.object().keys({ dependent: Joi.string().when('sibling.driver', { is: Joi.exist(), then: Joi.string().guid() }), sibling: Joi.object() }); const example = ValueGenerator(schema); expect(example.dependent).to.be.a.string(); ExpectValidation(example, schema); }); }); describe('Object', () => { it('should return an object', () => { const schema = Joi.object(); const example = ValueGenerator(schema); expect(example).to.be.an.object(); ExpectValidation(example, schema); }); it('should return an object with specified keys', () => { const schema = Joi.object().keys({ string: Joi.string().required(), number: Joi.number().required(), boolean: Joi.bool().required(), time: Joi.date().required(), buffer: Joi.binary().required(), array: Joi.array().items(Joi.string().required()).required(), innerObj: Joi.object().keys({ innerString: Joi.string().required() }).required() }); const example = ValueGenerator(schema); expect(example).to.be.an.object(); expect(example.string).to.be.a.string(); expect(example.number).to.be.a.number(); expect(example.boolean).to.be.a.boolean(); expect(example.time).to.be.a.date(); expect(example.buffer).to.be.a.buffer(); expect(example.array).to.be.an.array(); expect(example.innerObj).to.be.an.object(); expect(example.innerObj.innerString).to.be.a.string(); ExpectValidation(example, schema); }); it('should return an object with min number of keys', () => { const schema = Joi.object().keys({ child1: Joi.string() }).min(1).options({ allowUnknown: true }); const example = ValueGenerator(schema); expect(Object.keys(example).length).to.be.at.least(1); ExpectValidation(example, schema); }); it('should not get stuck on static key pattern generation', () => { const schema = Joi.object().pattern(/abc/, Joi.string()).min(5).options({ allowUnknown: true }); const example = ValueGenerator(schema); expect(Object.keys(example).length).to.be.at.least(5); ExpectValidation(example, schema); }); it('should return an object with max number of keys', () => { const schema = Joi.object().max(5); const example = ValueGenerator(schema); expect(Object.keys(example).length).to.be.at.most(5).and.at.least(1); ExpectValidation(example, schema); }); it('should return an object with max number of keys that are typed correctly', () => { const schema = Joi.object().keys({ prop: Joi.string(), prop2: Joi.number() }).max(2); const example = ValueGenerator(schema); expect(Object.keys(example).length).to.be.at.most(2).and.at.least(1); expect(example.prop).to.be.a.string(); expect(example.prop2).to.be.a.number(); ExpectValidation(example, schema); }); it('should return an object with exact number of keys', () => { const schema = Joi.object().length(5); const example = ValueGenerator(schema); expect(Object.keys(example).length).to.equal(5); ExpectValidation(example, schema); }); it('should return an object with keys that match the given pattern', () => { const schema = Joi.object().pattern(/^(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}$/, Joi.object().keys({ id: Joi.string().guid().required(), tags: Joi.array().items(Joi.string()).required() })).min(2); const example = ValueGenerator(schema); expect(Object.keys(example).length).to.be.at.least(2); ExpectValidation(example, schema); }); it('should return an object with one of two "nand" keys', () => { const schema = Joi.object() .keys({ a: Joi.string(), b: Joi.string(), c: Joi.string() }) .nand('a', 'b'); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return an object with one of two "xor" keys', () => { const schema = Joi.object() .keys({ a: Joi.string(), b: Joi.string(), c: Joi.string() }) .xor('a', 'b'); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return an ojbect with at least a key or peer', () => { const schema = Joi.object().keys({ password: Joi.string() }).with('username', 'password'); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return an object with alternatives', () => { for (let i = 0; i < 10; ++i) { const schema = Joi.object().keys({ dependent: Joi.alternatives().conditional('sibling.driver', { is: true, then: Joi.string().guid(), otherwise: Joi.number().multiple(4).min(16) }), unrelated: Joi.number(), sibling: Joi.object().keys({ driver: Joi.boolean() }) }); const example = ValueGenerator(schema); ExpectValidation(example, schema); } }); it('should return an object with array-syntax alternatives', () => { const schema = Joi.object().keys({ access_token: [Joi.string(), Joi.number()], birthyear: Joi.number().integer().min(1900).max(2013) }); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return an object without key set as Any.forbidden()', () => { const schema = Joi.object().keys({ allowed: Joi.any(), forbidden: Joi.any().forbidden(), forbidStr: Joi.string().forbidden(), forbidNum: Joi.number().forbidden() }); const example = ValueGenerator(schema); expect(example.forbidden).to.be.undefined(); expect(example.forbidStr).to.be.undefined(); expect(example.forbidNum).to.be.undefined(); ExpectValidation(example, schema); }); it('should return an object without key set as Any.strip()', () => { const schema = Joi.object().keys({ allowed: Joi.any(), private: Joi.any().strip(), privateStr: Joi.string().strip(), privateNum: Joi.number().strip() }); const example = ValueGenerator(schema); expect(example.private).to.be.undefined(); expect(example.privateStr).to.be.undefined(); expect(example.privateNum).to.be.undefined(); ExpectValidation(example, schema); }); it('should return an object with single rename() invocation', () => { const schema = Joi.object().keys({ b: Joi.number() }).rename('a','b', { ignoreUndefined: true }); const example = ValueGenerator(schema); expect(example.b).to.be.a.number(); ExpectValidation(example, schema); }); it('should return an object with double rename() invocation', () => { const schema = Joi.object().keys({ b: Joi.number() }).rename('a','b', { ignoreUndefined: true }).rename('c','b', { multiple: true, ignoreUndefined: true }); const example = ValueGenerator(schema); expect(example.b).to.be.a.number(); ExpectValidation(example, schema); }); it('should return a schema object with schema() invocation', () => { const schema = Joi.object().schema(); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return an object of type Regex', () => { const schema = Joi.object().instance(RegExp); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return an object of type Error', () => { const schema = Joi.object().instance(Error); const example = ValueGenerator(schema); ExpectValidation(example, schema); }); it('should return an object of custom type', () => { const Class1 = function () {}; Class1.prototype.testFunc = function () {}; const schema = Joi.object().instance(Class1); const example = ValueGenerator(schema); expect(example.testFunc).to.be.a.function();