CoolFace
Apppublic

strong-tie/inbound-calls

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
validation.test.js353 linesDownload Raw Back to internals
1'use strict'2 3const { test } = require('node:test')4 5const Ajv = require('ajv')6const ajv = new Ajv({ coerceTypes: true })7 8const validation = require('../../lib/validation')9const { normalizeSchema } = require('../../lib/schemas')10const symbols = require('../../lib/validation').symbols11const { kSchemaVisited } = require('../../lib/symbols')12 13test('Symbols', t => {14  t.plan(5)15  t.assert.strictEqual(typeof symbols.responseSchema, 'symbol')16  t.assert.strictEqual(typeof symbols.bodySchema, 'symbol')17  t.assert.strictEqual(typeof symbols.querystringSchema, 'symbol')18  t.assert.strictEqual(typeof symbols.paramsSchema, 'symbol')19  t.assert.strictEqual(typeof symbols.headersSchema, 'symbol')20})21 22;['compileSchemasForValidation',23  'compileSchemasForSerialization'].forEach(func => {24  test(`${func} schema - missing schema`, t => {25    t.plan(2)26    const context = {}27    validation[func](context)28    t.assert.strictEqual(typeof context[symbols.bodySchema], 'undefined')29    t.assert.strictEqual(typeof context[symbols.responseSchema], 'undefined')30  })31 32  test(`${func} schema - missing output schema`, t => {33    t.plan(1)34    const context = { schema: {} }35    validation[func](context, null)36    t.assert.strictEqual(typeof context[symbols.responseSchema], 'undefined')37  })38})39 40test('build schema - output schema', t => {41  t.plan(2)42  const opts = {43    schema: {44      response: {45        '2xx': {46          type: 'object',47          properties: {48            hello: { type: 'string' }49          }50        },51        201: {52          type: 'object',53          properties: {54            hello: { type: 'number' }55          }56        }57      }58    }59  }60  validation.compileSchemasForSerialization(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema))61  t.assert.strictEqual(typeof opts[symbols.responseSchema]['2xx'], 'function')62  t.assert.strictEqual(typeof opts[symbols.responseSchema]['201'], 'function')63})64 65test('build schema - body schema', t => {66  t.plan(1)67  const opts = {68    schema: {69      body: {70        type: 'object',71        properties: {72          hello: { type: 'string' }73        }74      }75    }76  }77  validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema))78  t.assert.strictEqual(typeof opts[symbols.bodySchema], 'function')79})80 81test('build schema - body with multiple content type schemas', t => {82  t.plan(2)83  const opts = {84    schema: {85      body: {86        content: {87          'application/json': {88            schema: {89              type: 'object',90              properties: {91                hello: { type: 'string' }92              }93            }94          },95          'text/plain': {96            schema: { type: 'string' }97          }98        }99      }100    }101  }102  validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema))103  t.assert.ok(opts[symbols.bodySchema]['application/json'], 'function')104  t.assert.ok(opts[symbols.bodySchema]['text/plain'], 'function')105})106 107test('build schema - avoid repeated normalize schema', t => {108  t.plan(3)109  const serverConfig = {}110  const opts = {111    schema: {112      query: {113        type: 'object',114        properties: {115          hello: { type: 'string' }116        }117      }118    }119  }120  opts.schema = normalizeSchema(opts.schema, serverConfig)121  t.assert.notStrictEqual(kSchemaVisited, undefined)122  t.assert.strictEqual(opts.schema[kSchemaVisited], true)123  t.assert.strictEqual(opts.schema, normalizeSchema(opts.schema, serverConfig))124})125 126test('build schema - query schema', t => {127  t.plan(2)128  const serverConfig = {}129  const opts = {130    schema: {131      query: {132        type: 'object',133        properties: {134          hello: { type: 'string' }135        }136      }137    }138  }139  opts.schema = normalizeSchema(opts.schema, serverConfig)140  validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema))141  t.assert.ok(typeof opts[symbols.querystringSchema].schema.type === 'string')142  t.assert.strictEqual(typeof opts[symbols.querystringSchema], 'function')143})144 145test('build schema - query schema abbreviated', t => {146  t.plan(2)147  const serverConfig = {}148  const opts = {149    schema: {150      query: {151        type: 'object',152        properties: {153          hello: { type: 'string' }154        }155      }156    }157  }158  opts.schema = normalizeSchema(opts.schema, serverConfig)159  validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema))160  t.assert.ok(typeof opts[symbols.querystringSchema].schema.type === 'string')161  t.assert.strictEqual(typeof opts[symbols.querystringSchema], 'function')162})163 164test('build schema - querystring schema', t => {165  t.plan(2)166  const opts = {167    schema: {168      querystring: {169        type: 'object',170        properties: {171          hello: { type: 'string' }172        }173      }174    }175  }176  validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema))177  t.assert.ok(typeof opts[symbols.querystringSchema].schema.type === 'string')178  t.assert.strictEqual(typeof opts[symbols.querystringSchema], 'function')179})180 181test('build schema - querystring schema abbreviated', t => {182  t.plan(2)183  const serverConfig = {}184  const opts = {185    schema: {186      querystring: {187        type: 'object',188        properties: {189          hello: { type: 'string' }190        }191      }192    }193  }194  opts.schema = normalizeSchema(opts.schema, serverConfig)195  validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema))196  t.assert.ok(typeof opts[symbols.querystringSchema].schema.type === 'string')197  t.assert.strictEqual(typeof opts[symbols.querystringSchema], 'function')198})199 200test('build schema - must throw if querystring and query schema exist', t => {201  t.plan(2)202  try {203    const serverConfig = {}204    const opts = {205      schema: {206        query: {207          type: 'object',208          properties: {209            hello: { type: 'string' }210          }211        },212        querystring: {213          type: 'object',214          properties: {215            hello: { type: 'string' }216          }217        }218      }219    }220    opts.schema = normalizeSchema(opts.schema, serverConfig)221  } catch (err) {222    t.assert.strictEqual(err.code, 'FST_ERR_SCH_DUPLICATE')223    t.assert.strictEqual(err.message, 'Schema with \'querystring\' already present!')224  }225})226 227test('build schema - params schema', t => {228  t.plan(1)229  const opts = {230    schema: {231      params: {232        type: 'object',233        properties: {234          hello: { type: 'string' }235        }236      }237    }238  }239  validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema))240  t.assert.strictEqual(typeof opts[symbols.paramsSchema], 'function')241})242 243test('build schema - headers schema', t => {244  t.plan(1)245  const opts = {246    schema: {247      headers: {248        type: 'object',249        properties: {250          'content-type': { type: 'string' }251        }252      }253    }254  }255  validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => ajv.compile(schema))256  t.assert.strictEqual(typeof opts[symbols.headersSchema], 'function')257})258 259test('build schema - headers are lowercase', t => {260  t.plan(1)261  const opts = {262    schema: {263      headers: {264        type: 'object',265        properties: {266          'Content-Type': { type: 'string' }267        }268      }269    }270  }271  validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => {272    t.assert.ok(schema.properties['content-type'], 'lowercase content-type exists')273    return () => { }274  })275})276 277test('build schema - headers are not lowercased in case of custom object', t => {278  t.plan(1)279 280  class Headers { }281  const opts = {282    schema: {283      headers: new Headers()284    }285  }286  validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => {287    t.assert.ok(schema, Headers)288    return () => { }289  })290})291 292test('build schema - headers are not lowercased in case of custom validator provided', t => {293  t.plan(1)294 295  class Headers { }296  const opts = {297    schema: {298      headers: new Headers()299    }300  }301  validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => {302    t.assert.ok(schema, Headers)303    return () => { }304  }, true)305})306 307test('build schema - uppercased headers are not included', t => {308  t.plan(1)309  const opts = {310    schema: {311      headers: {312        type: 'object',313        properties: {314          'Content-Type': { type: 'string' }315        }316      }317    }318  }319  validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => {320    t.assert.ok(!('Content-Type' in schema.properties), 'uppercase does not exist')321    return () => { }322  })323})324 325test('build schema - mixed schema types are individually skipped or normalized', t => {326  t.plan(2)327 328  class CustomSchemaClass { }329 330  const testCases = [{331    schema: {332      body: new CustomSchemaClass()333    },334    assertions: (schema) => {335      t.assert.ok(schema.body, CustomSchemaClass)336    }337  }, {338    schema: {339      response: {340        200: new CustomSchemaClass()341      }342    },343    assertions: (schema) => {344      t.assert.ok(schema.response[200], CustomSchemaClass)345    }346  }]347 348  testCases.forEach((testCase) => {349    const result = normalizeSchema(testCase.schema, {})350    testCase.assertions(result)351  })352})353