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.
		
		
		
		
		
			
		
			
				
					288 lines
				
				7.2 KiB
			
		
		
			
		
	
	
					288 lines
				
				7.2 KiB
			| 
											3 years ago
										 | 'use strict' | ||
|  | 
 | ||
|  | const t = require('tap') | ||
|  | const test = t.test | ||
|  | 
 | ||
|  | const Ajv = require('ajv') | ||
|  | const ajv = new Ajv({ coerceTypes: true }) | ||
|  | 
 | ||
|  | const validation = require('../../lib/validation') | ||
|  | const { normalizeSchema } = require('../../lib/schemas') | ||
|  | const symbols = require('../../lib/validation').symbols | ||
|  | const { kSchemaVisited } = require('../../lib/symbols') | ||
|  | 
 | ||
|  | test('Symbols', t => { | ||
|  |   t.plan(5) | ||
|  |   t.equal(typeof symbols.responseSchema, 'symbol') | ||
|  |   t.equal(typeof symbols.bodySchema, 'symbol') | ||
|  |   t.equal(typeof symbols.querystringSchema, 'symbol') | ||
|  |   t.equal(typeof symbols.paramsSchema, 'symbol') | ||
|  |   t.equal(typeof symbols.headersSchema, 'symbol') | ||
|  | }) | ||
|  | 
 | ||
|  | ;['compileSchemasForValidation', | ||
|  |   'compileSchemasForSerialization'].forEach(func => { | ||
|  |   test(`${func} schema - missing schema`, t => { | ||
|  |     t.plan(2) | ||
|  |     const context = {} | ||
|  |     validation[func](context) | ||
|  |     t.equal(typeof context[symbols.bodySchema], 'undefined') | ||
|  |     t.equal(typeof context[symbols.responseSchema], 'undefined') | ||
|  |   }) | ||
|  | 
 | ||
|  |   test(`${func} schema - missing output schema`, t => { | ||
|  |     t.plan(1) | ||
|  |     const context = { schema: {} } | ||
|  |     validation[func](context, null) | ||
|  |     t.equal(typeof context[symbols.responseSchema], 'undefined') | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | test('build schema - output schema', t => { | ||
|  |   t.plan(2) | ||
|  |   const opts = { | ||
|  |     schema: { | ||
|  |       response: { | ||
|  |         '2xx': { | ||
|  |           type: 'object', | ||
|  |           properties: { | ||
|  |             hello: { type: 'string' } | ||
|  |           } | ||
|  |         }, | ||
|  |         201: { | ||
|  |           type: 'object', | ||
|  |           properties: { | ||
|  |             hello: { type: 'number' } | ||
|  |           } | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   validation.compileSchemasForSerialization(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema)) | ||
|  |   t.equal(typeof opts[symbols.responseSchema]['2xx'], 'function') | ||
|  |   t.equal(typeof opts[symbols.responseSchema]['201'], 'function') | ||
|  | }) | ||
|  | 
 | ||
|  | test('build schema - payload schema', t => { | ||
|  |   t.plan(1) | ||
|  |   const opts = { | ||
|  |     schema: { | ||
|  |       body: { | ||
|  |         type: 'object', | ||
|  |         properties: { | ||
|  |           hello: { type: 'string' } | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema)) | ||
|  |   t.equal(typeof opts[symbols.bodySchema], 'function') | ||
|  | }) | ||
|  | 
 | ||
|  | test('build schema - avoid repeated normalize schema', t => { | ||
|  |   t.plan(3) | ||
|  |   const serverConfig = { | ||
|  |     jsonShorthand: true | ||
|  |   } | ||
|  |   const opts = { | ||
|  |     schema: { | ||
|  |       query: { | ||
|  |         type: 'object', | ||
|  |         properties: { | ||
|  |           hello: { type: 'string' } | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   opts.schema = normalizeSchema(opts.schema, serverConfig) | ||
|  |   t.not(kSchemaVisited, undefined) | ||
|  |   t.equal(opts.schema[kSchemaVisited], true) | ||
|  |   t.equal(opts.schema, normalizeSchema(opts.schema, serverConfig)) | ||
|  | }) | ||
|  | 
 | ||
|  | test('build schema - query schema', t => { | ||
|  |   t.plan(2) | ||
|  |   const serverConfig = { | ||
|  |     jsonShorthand: true | ||
|  |   } | ||
|  |   const opts = { | ||
|  |     schema: { | ||
|  |       query: { | ||
|  |         type: 'object', | ||
|  |         properties: { | ||
|  |           hello: { type: 'string' } | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   opts.schema = normalizeSchema(opts.schema, serverConfig) | ||
|  |   validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema)) | ||
|  |   t.type(opts[symbols.querystringSchema].schema.type, 'string') | ||
|  |   t.equal(typeof opts[symbols.querystringSchema], 'function') | ||
|  | }) | ||
|  | 
 | ||
|  | test('build schema - query schema abbreviated', t => { | ||
|  |   t.plan(2) | ||
|  |   const serverConfig = { | ||
|  |     jsonShorthand: true | ||
|  |   } | ||
|  |   const opts = { | ||
|  |     schema: { | ||
|  |       query: { | ||
|  |         hello: { type: 'string' } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   opts.schema = normalizeSchema(opts.schema, serverConfig) | ||
|  |   validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema)) | ||
|  |   t.type(opts[symbols.querystringSchema].schema.type, 'string') | ||
|  |   t.equal(typeof opts[symbols.querystringSchema], 'function') | ||
|  | }) | ||
|  | 
 | ||
|  | test('build schema - querystring schema', t => { | ||
|  |   t.plan(2) | ||
|  |   const opts = { | ||
|  |     schema: { | ||
|  |       querystring: { | ||
|  |         type: 'object', | ||
|  |         properties: { | ||
|  |           hello: { type: 'string' } | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema)) | ||
|  |   t.type(opts[symbols.querystringSchema].schema.type, 'string') | ||
|  |   t.equal(typeof opts[symbols.querystringSchema], 'function') | ||
|  | }) | ||
|  | 
 | ||
|  | test('build schema - querystring schema abbreviated', t => { | ||
|  |   t.plan(2) | ||
|  |   const serverConfig = { | ||
|  |     jsonShorthand: true | ||
|  |   } | ||
|  |   const opts = { | ||
|  |     schema: { | ||
|  |       querystring: { | ||
|  |         hello: { type: 'string' } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   opts.schema = normalizeSchema(opts.schema, serverConfig) | ||
|  |   validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema)) | ||
|  |   t.type(opts[symbols.querystringSchema].schema.type, 'string') | ||
|  |   t.equal(typeof opts[symbols.querystringSchema], 'function') | ||
|  | }) | ||
|  | 
 | ||
|  | test('build schema - must throw if querystring and query schema exist', t => { | ||
|  |   t.plan(2) | ||
|  |   try { | ||
|  |     const serverConfig = { | ||
|  |       jsonShorthand: true | ||
|  |     } | ||
|  |     const opts = { | ||
|  |       schema: { | ||
|  |         query: { | ||
|  |           type: 'object', | ||
|  |           properties: { | ||
|  |             hello: { type: 'string' } | ||
|  |           } | ||
|  |         }, | ||
|  |         querystring: { | ||
|  |           type: 'object', | ||
|  |           properties: { | ||
|  |             hello: { type: 'string' } | ||
|  |           } | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |     opts.schema = normalizeSchema(opts.schema, serverConfig) | ||
|  |   } catch (err) { | ||
|  |     t.equal(err.code, 'FST_ERR_SCH_DUPLICATE') | ||
|  |     t.equal(err.message, 'Schema with \'querystring\' already present!') | ||
|  |   } | ||
|  | }) | ||
|  | 
 | ||
|  | test('build schema - params schema', t => { | ||
|  |   t.plan(1) | ||
|  |   const opts = { | ||
|  |     schema: { | ||
|  |       params: { | ||
|  |         type: 'object', | ||
|  |         properties: { | ||
|  |           hello: { type: 'string' } | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema)) | ||
|  |   t.equal(typeof opts[symbols.paramsSchema], 'function') | ||
|  | }) | ||
|  | 
 | ||
|  | test('build schema - headers schema', t => { | ||
|  |   t.plan(1) | ||
|  |   const opts = { | ||
|  |     schema: { | ||
|  |       headers: { | ||
|  |         type: 'object', | ||
|  |         properties: { | ||
|  |           'content-type': { type: 'string' } | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema)) | ||
|  |   t.equal(typeof opts[symbols.headersSchema], 'function') | ||
|  | }) | ||
|  | 
 | ||
|  | test('build schema - headers are lowercase', t => { | ||
|  |   t.plan(1) | ||
|  |   const opts = { | ||
|  |     schema: { | ||
|  |       headers: { | ||
|  |         type: 'object', | ||
|  |         properties: { | ||
|  |           'Content-Type': { type: 'string' } | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => { | ||
|  |     t.ok(schema.properties['content-type'], 'lowercase content-type exists') | ||
|  |     return () => {} | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | test('build schema - headers are not lowercased in case of custom object', t => { | ||
|  |   t.plan(1) | ||
|  | 
 | ||
|  |   class Headers {} | ||
|  |   const opts = { | ||
|  |     schema: { | ||
|  |       headers: new Headers() | ||
|  |     } | ||
|  |   } | ||
|  |   validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => { | ||
|  |     t.type(schema, Headers) | ||
|  |     return () => {} | ||
|  |   }) | ||
|  | }) | ||
|  | 
 | ||
|  | test('build schema - uppercased headers are not included', t => { | ||
|  |   t.plan(1) | ||
|  |   const opts = { | ||
|  |     schema: { | ||
|  |       headers: { | ||
|  |         type: 'object', | ||
|  |         properties: { | ||
|  |           'Content-Type': { type: 'string' } | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  |   validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => { | ||
|  |     t.notOk('Content-Type' in schema.properties, 'uppercase does not exist') | ||
|  |     return () => {} | ||
|  |   }) | ||
|  | }) |