You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					362 lines
				
				5.4 KiB
			
		
		
			
		
	
	
					362 lines
				
				5.4 KiB
			| 
											3 years ago
										 | 'use strict' | ||
|  | 
 | ||
|  | const test = require('tap').test | ||
|  | const validator = require('is-my-json-valid') | ||
|  | const build = require('..') | ||
|  | 
 | ||
|  | function buildTest (schema, toStringify) { | ||
|  |   test(`render a ${schema.title} as JSON`, (t) => { | ||
|  |     t.plan(3) | ||
|  | 
 | ||
|  |     const validate = validator(schema) | ||
|  |     const stringify = build(schema) | ||
|  |     const output = stringify(toStringify) | ||
|  | 
 | ||
|  |     t.same(JSON.parse(output), toStringify) | ||
|  |     t.equal(output, JSON.stringify(toStringify)) | ||
|  |     t.ok(validate(JSON.parse(output)), 'valid schema') | ||
|  |   }) | ||
|  | } | ||
|  | 
 | ||
|  | buildTest({ | ||
|  |   title: 'basic', | ||
|  |   type: 'object', | ||
|  |   properties: { | ||
|  |     firstName: { | ||
|  |       type: 'string' | ||
|  |     }, | ||
|  |     lastName: { | ||
|  |       type: 'string' | ||
|  |     }, | ||
|  |     age: { | ||
|  |       description: 'Age in years', | ||
|  |       type: 'integer', | ||
|  |       minimum: 0 | ||
|  |     }, | ||
|  |     magic: { | ||
|  |       type: 'number' | ||
|  |     } | ||
|  |   }, | ||
|  |   required: ['firstName', 'lastName'] | ||
|  | }, { | ||
|  |   firstName: 'Matteo', | ||
|  |   lastName: 'Collina', | ||
|  |   age: 32, | ||
|  |   magic: 42.42 | ||
|  | }) | ||
|  | 
 | ||
|  | buildTest({ | ||
|  |   title: 'string', | ||
|  |   type: 'string' | ||
|  | }, 'hello world') | ||
|  | 
 | ||
|  | buildTest({ | ||
|  |   title: 'string', | ||
|  |   type: 'string' | ||
|  | }, 'hello\nworld') | ||
|  | 
 | ||
|  | buildTest({ | ||
|  |   title: 'string with quotes', | ||
|  |   type: 'string' | ||
|  | }, 'hello """" world') | ||
|  | 
 | ||
|  | buildTest({ | ||
|  |   title: 'boolean true', | ||
|  |   type: 'boolean' | ||
|  | }, true) | ||
|  | 
 | ||
|  | buildTest({ | ||
|  |   title: 'boolean false', | ||
|  |   type: 'boolean' | ||
|  | }, false) | ||
|  | 
 | ||
|  | buildTest({ | ||
|  |   title: 'an integer', | ||
|  |   type: 'integer' | ||
|  | }, 42) | ||
|  | 
 | ||
|  | buildTest({ | ||
|  |   title: 'a number', | ||
|  |   type: 'number' | ||
|  | }, 42.42) | ||
|  | 
 | ||
|  | buildTest({ | ||
|  |   title: 'deep', | ||
|  |   type: 'object', | ||
|  |   properties: { | ||
|  |     firstName: { | ||
|  |       type: 'string' | ||
|  |     }, | ||
|  |     lastName: { | ||
|  |       type: 'string' | ||
|  |     }, | ||
|  |     more: { | ||
|  |       description: 'more properties', | ||
|  |       type: 'object', | ||
|  |       properties: { | ||
|  |         something: { | ||
|  |           type: 'string' | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  | }, { | ||
|  |   firstName: 'Matteo', | ||
|  |   lastName: 'Collina', | ||
|  |   more: { | ||
|  |     something: 'else' | ||
|  |   } | ||
|  | }) | ||
|  | 
 | ||
|  | buildTest({ | ||
|  |   title: 'null', | ||
|  |   type: 'null' | ||
|  | }, null) | ||
|  | 
 | ||
|  | buildTest({ | ||
|  |   title: 'deep object with weird keys', | ||
|  |   type: 'object', | ||
|  |   properties: { | ||
|  |     '@version': { | ||
|  |       type: 'integer' | ||
|  |     } | ||
|  |   } | ||
|  | }, { | ||
|  |   '@version': 1 | ||
|  | }) | ||
|  | 
 | ||
|  | buildTest({ | ||
|  |   title: 'deep object with weird keys of type object', | ||
|  |   type: 'object', | ||
|  |   properties: { | ||
|  |     '@data': { | ||
|  |       type: 'object', | ||
|  |       properties: { | ||
|  |         id: { | ||
|  |           type: 'string' | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  | }, { | ||
|  |   '@data': { | ||
|  |     id: 'string' | ||
|  |   } | ||
|  | }) | ||
|  | 
 | ||
|  | buildTest({ | ||
|  |   title: 'deep object with spaces in key', | ||
|  |   type: 'object', | ||
|  |   properties: { | ||
|  |     'spaces in key': { | ||
|  |       type: 'object', | ||
|  |       properties: { | ||
|  |         something: { | ||
|  |           type: 'integer' | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  | }, { | ||
|  |   'spaces in key': { | ||
|  |     something: 1 | ||
|  |   } | ||
|  | }) | ||
|  | 
 | ||
|  | buildTest({ | ||
|  |   title: 'with null', | ||
|  |   type: 'object', | ||
|  |   properties: { | ||
|  |     firstName: { | ||
|  |       type: 'null' | ||
|  |     } | ||
|  |   } | ||
|  | }, { | ||
|  |   firstName: null | ||
|  | }) | ||
|  | 
 | ||
|  | buildTest({ | ||
|  |   title: 'array with objects', | ||
|  |   type: 'array', | ||
|  |   items: { | ||
|  |     type: 'object', | ||
|  |     properties: { | ||
|  |       name: { | ||
|  |         type: 'string' | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  | }, [{ | ||
|  |   name: 'Matteo' | ||
|  | }, { | ||
|  |   name: 'Dave' | ||
|  | }]) | ||
|  | 
 | ||
|  | buildTest({ | ||
|  |   title: 'array with strings', | ||
|  |   type: 'array', | ||
|  |   items: { | ||
|  |     type: 'string' | ||
|  |   } | ||
|  | }, [ | ||
|  |   'Matteo', | ||
|  |   'Dave' | ||
|  | ]) | ||
|  | 
 | ||
|  | buildTest({ | ||
|  |   title: 'array with numbers', | ||
|  |   type: 'array', | ||
|  |   items: { | ||
|  |     type: 'number' | ||
|  |   } | ||
|  | }, [ | ||
|  |   42.42, | ||
|  |   24 | ||
|  | ]) | ||
|  | 
 | ||
|  | buildTest({ | ||
|  |   title: 'array with integers', | ||
|  |   type: 'array', | ||
|  |   items: { | ||
|  |     type: 'number' | ||
|  |   } | ||
|  | }, [ | ||
|  |   42, | ||
|  |   24 | ||
|  | ]) | ||
|  | 
 | ||
|  | buildTest({ | ||
|  |   title: 'nested array with objects', | ||
|  |   type: 'object', | ||
|  |   properties: { | ||
|  |     data: { | ||
|  |       type: 'array', | ||
|  |       items: { | ||
|  |         type: 'object', | ||
|  |         properties: { | ||
|  |           name: { | ||
|  |             type: 'string' | ||
|  |           } | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  | }, { | ||
|  |   data: [{ | ||
|  |     name: 'Matteo' | ||
|  |   }, { | ||
|  |     name: 'Dave' | ||
|  |   }] | ||
|  | }) | ||
|  | 
 | ||
|  | buildTest({ | ||
|  |   title: 'object with boolean', | ||
|  |   type: 'object', | ||
|  |   properties: { | ||
|  |     readonly: { | ||
|  |       type: 'boolean' | ||
|  |     } | ||
|  |   } | ||
|  | }, { | ||
|  |   readonly: true | ||
|  | }) | ||
|  | 
 | ||
|  | test('skip or coerce numbers and integers that are not numbers', (t) => { | ||
|  |   const stringify = build({ | ||
|  |     title: 'basic', | ||
|  |     type: 'object', | ||
|  |     properties: { | ||
|  |       age: { | ||
|  |         type: 'number' | ||
|  |       }, | ||
|  |       distance: { | ||
|  |         type: 'integer' | ||
|  |       } | ||
|  |     } | ||
|  |   }) | ||
|  | 
 | ||
|  |   let result = stringify({ | ||
|  |     age: 'hello  ', | ||
|  |     distance: 'long' | ||
|  |   }) | ||
|  | 
 | ||
|  |   t.same(JSON.parse(result), {}) | ||
|  | 
 | ||
|  |   result = stringify({ | ||
|  |     age: '42', | ||
|  |     distance: true | ||
|  |   }) | ||
|  | 
 | ||
|  |   t.same(JSON.parse(result), { age: 42, distance: 1 }) | ||
|  |   t.end() | ||
|  | }) | ||
|  | 
 | ||
|  | test('Should throw on invalid schema', t => { | ||
|  |   t.plan(1) | ||
|  |   try { | ||
|  |     build({ | ||
|  |       type: 'Dinosaur', | ||
|  |       properties: { | ||
|  |         claws: { type: 'sharp' } | ||
|  |       } | ||
|  |     }) | ||
|  |     t.fail('should be an invalid schema') | ||
|  |   } catch (err) { | ||
|  |     t.ok(err) | ||
|  |   } | ||
|  | }) | ||
|  | 
 | ||
|  | test('additionalProperties - throw on unknown type', (t) => { | ||
|  |   t.plan(1) | ||
|  | 
 | ||
|  |   try { | ||
|  |     build({ | ||
|  |       title: 'check array coerce', | ||
|  |       type: 'object', | ||
|  |       properties: {}, | ||
|  |       additionalProperties: { | ||
|  |         type: 'strangetype' | ||
|  |       } | ||
|  |     }) | ||
|  |     t.fail('should be an invalid schema') | ||
|  |   } catch (err) { | ||
|  |     t.ok(err) | ||
|  |   } | ||
|  | }) | ||
|  | 
 | ||
|  | test('patternProperties - throw on unknown type', (t) => { | ||
|  |   t.plan(1) | ||
|  | 
 | ||
|  |   try { | ||
|  |     build({ | ||
|  |       title: 'check array coerce', | ||
|  |       type: 'object', | ||
|  |       properties: {}, | ||
|  |       patternProperties: { | ||
|  |         foo: { | ||
|  |           type: 'strangetype' | ||
|  |         } | ||
|  |       } | ||
|  |     }) | ||
|  |     t.fail('should be an invalid schema') | ||
|  |   } catch (err) { | ||
|  |     t.ok(err) | ||
|  |   } | ||
|  | }) | ||
|  | 
 | ||
|  | test('render a single quote as JSON', (t) => { | ||
|  |   t.plan(2) | ||
|  | 
 | ||
|  |   const schema = { | ||
|  |     type: 'string' | ||
|  |   } | ||
|  |   const toStringify = '" double quote' | ||
|  | 
 | ||
|  |   const validate = validator(schema) | ||
|  |   const stringify = build(schema) | ||
|  |   const output = stringify(toStringify) | ||
|  | 
 | ||
|  |   t.equal(output, JSON.stringify(toStringify)) | ||
|  |   t.ok(validate(JSON.parse(output)), 'valid schema') | ||
|  | }) |