CoolFace
Apppublic

strong-tie/inbound-calls

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
schema-serialization.test.js1149 linesDownload Raw Back to test
1'use strict'2 3const t = require('tap')4const Fastify = require('..')5const test = t.test6 7const echoBody = (req, reply) => { reply.send(req.body) }8 9test('basic test', t => {10  t.plan(3)11 12  const fastify = Fastify()13  fastify.get('/', {14    schema: {15      response: {16        '2xx': {17          type: 'object',18          properties: {19            name: { type: 'string' },20            work: { type: 'string' }21          }22        }23      }24    }25  }, function (req, reply) {26    reply.code(200).send({ name: 'Foo', work: 'Bar', nick: 'Boo' })27  })28 29  fastify.inject('/', (err, res) => {30    t.error(err)31    t.same(res.json(), { name: 'Foo', work: 'Bar' })32    t.equal(res.statusCode, 200)33  })34})35 36test('custom serializer options', t => {37  t.plan(3)38 39  const fastify = Fastify({40    serializerOpts: {41      rounding: 'ceil'42    }43  })44  fastify.get('/', {45    schema: {46      response: {47        '2xx': {48          type: 'integer'49        }50      }51    }52  }, function (req, reply) {53    reply.send(4.2)54  })55 56  fastify.inject('/', (err, res) => {57    t.error(err)58    t.equal(res.payload, '5', 'it must use the ceil rounding')59    t.equal(res.statusCode, 200)60  })61})62 63test('Different content types', t => {64  t.plan(46)65 66  const fastify = Fastify()67  fastify.addSchema({68    $id: 'test',69    type: 'object',70    properties: {71      name: { type: 'string' },72      age: { type: 'number' },73      verified: { type: 'boolean' }74    }75  })76 77  fastify.get('/', {78    schema: {79      response: {80        200: {81          content: {82            'application/json': {83              schema: {84                type: 'object',85                properties: {86                  name: { type: 'string' },87                  image: { type: 'string' },88                  address: { type: 'string' }89                }90              }91            },92            'application/vnd.v1+json': {93              schema: {94                type: 'array',95                items: { $ref: 'test' }96              }97            }98          }99        },100        201: {101          content: {102            '*/*': {103              schema: { type: 'string' }104            }105          }106        },107        202: {108          content: {109            '*/*': {110              schema: { const: 'Processing exclusive content' }111            }112          }113        },114        '3xx': {115          content: {116            'application/vnd.v2+json': {117              schema: {118                type: 'object',119                properties: {120                  fullName: { type: 'string' },121                  phone: { type: 'string' }122                }123              }124            }125          }126        },127        '4xx': {128          content: {129            '*/*': {130              schema: {131                type: 'object',132                properties: {133                  details: { type: 'string' }134                }135              }136            }137          }138        },139        default: {140          content: {141            'application/json': {142              schema: {143                type: 'object',144                properties: {145                  details: { type: 'string' }146                }147              }148            },149            '*/*': {150              schema: {151                type: 'object',152                properties: {153                  desc: { type: 'string' },154                  details: { type: 'string' }155                }156              }157            }158          }159        }160      }161    }162  }, function (req, reply) {163    switch (req.headers.accept) {164      case 'application/json':165        reply.header('Content-Type', 'application/json')166        reply.send({ id: 1, name: 'Foo', image: 'profile picture', address: 'New Node' })167        break168      case 'application/vnd.v1+json':169        reply.header('Content-Type', 'application/vnd.v1+json')170        reply.send([{ id: 2, name: 'Boo', age: 18, verified: false }, { id: 3, name: 'Woo', age: 30, verified: true }])171        break172      case 'application/vnd.v2+json':173        reply.header('Content-Type', 'application/vnd.v2+json')174        reply.code(300)175        reply.send({ fullName: 'Jhon Smith', phone: '01090000000', authMethod: 'google' })176        break177      case 'application/vnd.v3+json':178        reply.header('Content-Type', 'application/vnd.v3+json')179        reply.code(300)180        reply.send({ firstName: 'New', lastName: 'Hoo', country: 'eg', city: 'node' })181        break182      case 'application/vnd.v4+json':183        reply.header('Content-Type', 'application/vnd.v4+json')184        reply.code(201)185        reply.send({ boxId: 1, content: 'Games' })186        break187      case 'application/vnd.v5+json':188        reply.header('Content-Type', 'application/vnd.v5+json')189        reply.code(202)190        reply.send({ content: 'interesting content' })191        break192      case 'application/vnd.v6+json':193        reply.header('Content-Type', 'application/vnd.v6+json')194        reply.code(400)195        reply.send({ desc: 'age is missing', details: 'validation error' })196        break197      case 'application/vnd.v7+json':198        reply.code(400)199        reply.send({ details: 'validation error' })200        break201      case 'application/vnd.v8+json':202        reply.header('Content-Type', 'application/vnd.v8+json')203        reply.code(500)204        reply.send({ desc: 'age is missing', details: 'validation error' })205        break206      case 'application/vnd.v9+json':207        reply.code(500)208        reply.send({ details: 'validation error' })209        break210      default:211        // to test if schema not found212        reply.header('Content-Type', 'application/vnd.v3+json')213        reply.code(200)214        reply.send([{ type: 'student', grade: 6 }, { type: 'student', grade: 9 }])215    }216  })217 218  fastify.get('/test', {219    serializerCompiler: ({ contentType }) => {220      t.equal(contentType, 'application/json')221      return data => JSON.stringify(data)222    },223    schema: {224      response: {225        200: {226          content: {227            'application/json': {228              schema: {229                type: 'object',230                properties: {231                  name: { type: 'string' },232                  image: { type: 'string' },233                  address: { type: 'string' }234                }235              }236            }237          }238        },239        default: {240          content: {241            'application/json': {242              schema: {243                type: 'object',244                properties: {245                  details: { type: 'string' }246                }247              }248            }249          }250        }251      }252    }253  }, function (req, reply) {254    switch (req.headers['code']) {255      case '200': {256        reply.header('Content-Type', 'application/json')257        reply.code(200).send({ age: 18, city: 'AU' })258        break259      }260      case '201': {261        reply.header('Content-Type', 'application/json')262        reply.code(201).send({ details: 'validation error' })263        break264      }265      default: {266        reply.header('Content-Type', 'application/vnd.v1+json')267        reply.code(201).send({ created: true })268        break269      }270    }271  })272 273  fastify.inject({ method: 'GET', url: '/', headers: { Accept: 'application/json' } }, (err, res) => {274    t.error(err)275    t.equal(res.payload, JSON.stringify({ name: 'Foo', image: 'profile picture', address: 'New Node' }))276    t.equal(res.statusCode, 200)277  })278 279  fastify.inject({ method: 'GET', url: '/', headers: { Accept: 'application/vnd.v1+json' } }, (err, res) => {280    t.error(err)281    t.equal(res.payload, JSON.stringify([{ name: 'Boo', age: 18, verified: false }, { name: 'Woo', age: 30, verified: true }]))282    t.equal(res.statusCode, 200)283  })284 285  fastify.inject({ method: 'GET', url: '/' }, (err, res) => {286    t.error(err)287    t.equal(res.payload, JSON.stringify([{ type: 'student', grade: 6 }, { type: 'student', grade: 9 }]))288    t.equal(res.statusCode, 200)289  })290 291  fastify.inject({ method: 'GET', url: '/', headers: { Accept: 'application/vnd.v2+json' } }, (err, res) => {292    t.error(err)293    t.equal(res.payload, JSON.stringify({ fullName: 'Jhon Smith', phone: '01090000000' }))294    t.equal(res.statusCode, 300)295  })296 297  fastify.inject({ method: 'GET', url: '/', headers: { Accept: 'application/vnd.v3+json' } }, (err, res) => {298    t.error(err)299    t.equal(res.payload, JSON.stringify({ firstName: 'New', lastName: 'Hoo', country: 'eg', city: 'node' }))300    t.equal(res.statusCode, 300)301  })302 303  fastify.inject({ method: 'GET', url: '/', headers: { Accept: 'application/vnd.v4+json' } }, (err, res) => {304    t.error(err)305    t.equal(res.payload, '"[object Object]"')306    t.equal(res.statusCode, 201)307  })308 309  fastify.inject({ method: 'GET', url: '/', headers: { Accept: 'application/vnd.v5+json' } }, (err, res) => {310    t.error(err)311    t.equal(res.payload, '"Processing exclusive content"')312    t.equal(res.statusCode, 202)313  })314 315  fastify.inject({ method: 'GET', url: '/', headers: { Accept: 'application/vnd.v6+json' } }, (err, res) => {316    t.error(err)317    t.equal(res.payload, JSON.stringify({ details: 'validation error' }))318    t.equal(res.statusCode, 400)319  })320 321  fastify.inject({ method: 'GET', url: '/', headers: { Accept: 'application/vnd.v7+json' } }, (err, res) => {322    t.error(err)323    t.equal(res.payload, JSON.stringify({ details: 'validation error' }))324    t.equal(res.statusCode, 400)325  })326 327  fastify.inject({ method: 'GET', url: '/', headers: { Accept: 'application/vnd.v8+json' } }, (err, res) => {328    t.error(err)329    t.equal(res.payload, JSON.stringify({ desc: 'age is missing', details: 'validation error' }))330    t.equal(res.statusCode, 500)331  })332 333  fastify.inject({ method: 'GET', url: '/', headers: { Accept: 'application/vnd.v9+json' } }, (err, res) => {334    t.error(err)335    t.equal(res.payload, JSON.stringify({ details: 'validation error' }))336    t.equal(res.statusCode, 500)337  })338 339  fastify.inject({ method: 'GET', url: '/test', headers: { Code: '200' } }, (err, res) => {340    t.error(err)341    t.equal(res.payload, JSON.stringify({ age: 18, city: 'AU' }))342    t.equal(res.statusCode, 200)343  })344 345  fastify.inject({ method: 'GET', url: '/test', headers: { Code: '201' } }, (err, res) => {346    t.error(err)347    t.equal(res.payload, JSON.stringify({ details: 'validation error' }))348    t.equal(res.statusCode, 201)349  })350 351  fastify.inject({ method: 'GET', url: '/test', headers: { Accept: 'application/vnd.v1+json' } }, (err, res) => {352    t.error(err)353    t.equal(res.payload, JSON.stringify({ created: true }))354    t.equal(res.statusCode, 201)355  })356})357 358test('Invalid multiple content schema, throw FST_ERR_SCH_CONTENT_MISSING_SCHEMA error', t => {359  t.plan(3)360  const fastify = Fastify()361 362  fastify.get('/testInvalid', {363    schema: {364      response: {365        200: {366          content: {367            'application/json': {368              schema: {369                type: 'object',370                properties: {371                  fullName: { type: 'string' },372                  phone: { type: 'string' }373                }374              },375              example: {376                fullName: 'John Doe',377                phone: '201090243795'378              }379            },380            type: 'string'381          }382        }383      }384    }385  }, function (req, reply) {386    reply.header('Content-Type', 'application/json')387    reply.send({ fullName: 'Any name', phone: '0109001010' })388  })389 390  fastify.ready((err) => {391    t.equal(err.message, "Schema is missing for the content type 'type'")392    t.equal(err.statusCode, 500)393    t.equal(err.code, 'FST_ERR_SCH_CONTENT_MISSING_SCHEMA')394  })395})396 397test('Use the same schema id in different places', t => {398  t.plan(2)399  const fastify = Fastify()400 401  fastify.addSchema({402    $id: 'test',403    type: 'object',404    properties: {405      id: { type: 'number' }406    }407  })408 409  fastify.get('/:id', {410    handler (req, reply) {411      reply.send([{ id: 1 }, { id: 2 }, { what: 'is this' }])412    },413    schema: {414      response: {415        200: {416          type: 'array',417          items: { $ref: 'test' }418        }419      }420    }421  })422 423  fastify.inject({424    method: 'GET',425    url: '/123'426  }, (err, res) => {427    t.error(err)428    t.same(res.json(), [{ id: 1 }, { id: 2 }, {}])429  })430})431 432test('Use shared schema and $ref with $id in response ($ref to $id)', t => {433  t.plan(5)434  const fastify = Fastify()435 436  fastify.addSchema({437    $id: 'http://foo/test',438    type: 'object',439    properties: {440      id: { type: 'number' }441    }442  })443 444  const complexSchema = {445    $schema: 'http://json-schema.org/draft-07/schema#',446    $id: 'http://foo/user',447    type: 'object',448    definitions: {449      address: {450        $id: '#address',451        type: 'object',452        properties: {453          city: { type: 'string' }454        }455      }456    },457    properties: {458      test: { $ref: 'http://foo/test#' },459      address: { $ref: '#address' }460    },461    required: ['address', 'test']462  }463 464  fastify.post('/', {465    schema: {466      body: complexSchema,467      response: {468        200: complexSchema469      }470    },471    handler: (req, reply) => {472      req.body.removeThis = 'it should not be serialized'473      reply.send(req.body)474    }475  })476 477  const payload = {478    address: { city: 'New Node' },479    test: { id: Date.now() }480  }481 482  fastify.inject({483    method: 'POST',484    url: '/',485    payload486  }, (err, res) => {487    t.error(err)488    t.same(res.json(), payload)489  })490 491  fastify.inject({492    method: 'POST',493    url: '/',494    payload: { test: { id: Date.now() } }495  }, (err, res) => {496    t.error(err)497    t.equal(res.statusCode, 400)498    t.same(res.json(), {499      error: 'Bad Request',500      message: "body must have required property 'address'",501      statusCode: 400,502      code: 'FST_ERR_VALIDATION'503    })504  })505})506 507test('Shared schema should be pass to serializer and validator ($ref to shared schema /definitions)', t => {508  t.plan(5)509  const fastify = Fastify()510 511  fastify.addSchema({512    $id: 'http://example.com/asset.json',513    $schema: 'http://json-schema.org/draft-07/schema#',514    title: 'Physical Asset',515    description: 'A generic representation of a physical asset',516    type: 'object',517    required: [518      'id',519      'model',520      'location'521    ],522    properties: {523      id: {524        type: 'string',525        format: 'uuid'526      },527      model: {528        type: 'string'529      },530      location: { $ref: 'http://example.com/point.json#' }531    },532    definitions: {533      inner: {534        $id: '#innerId',535        type: 'string',536        format: 'email'537      }538    }539  })540 541  fastify.addSchema({542    $id: 'http://example.com/point.json',543    $schema: 'http://json-schema.org/draft-07/schema#',544    title: 'Longitude and Latitude Values',545    description: 'A geographical coordinate.',546    type: 'object',547    required: [548      'latitude',549      'longitude'550    ],551    properties: {552      email: { $ref: 'http://example.com/asset.json#/definitions/inner' },553      latitude: {554        type: 'number',555        minimum: -90,556        maximum: 90557      },558      longitude: {559        type: 'number',560        minimum: -180,561        maximum: 180562      },563      altitude: {564        type: 'number'565      }566    }567  })568 569  const schemaLocations = {570    $id: 'http://example.com/locations.json',571    $schema: 'http://json-schema.org/draft-07/schema#',572    title: 'List of Asset locations',573    type: 'array',574    items: { $ref: 'http://example.com/asset.json#' }575  }576 577  fastify.post('/', {578    schema: {579      body: schemaLocations,580      response: { 200: schemaLocations }581    }582  }, (req, reply) => {583    reply.send(locations.map(_ => Object.assign({ serializer: 'remove me' }, _)))584  })585 586  const locations = [587    { id: '550e8400-e29b-41d4-a716-446655440000', model: 'mod', location: { latitude: 10, longitude: 10, email: 'foo@bar.it' } },588    { id: '550e8400-e29b-41d4-a716-446655440000', model: 'mod', location: { latitude: 10, longitude: 10, email: 'foo@bar.it' } }589  ]590  fastify.inject({591    method: 'POST',592    url: '/',593    payload: locations594  }, (err, res) => {595    t.error(err)596    t.same(res.json(), locations)597 598    fastify.inject({599      method: 'POST',600      url: '/',601      payload: locations.map(_ => {602        _.location.email = 'not an email'603        return _604      })605    }, (err, res) => {606      t.error(err)607      t.equal(res.statusCode, 400)608      t.same(res.json(), {609        error: 'Bad Request',610        message: 'body/0/location/email must match format "email"',611        statusCode: 400,612        code: 'FST_ERR_VALIDATION'613      })614    })615  })616})617 618test('Custom setSerializerCompiler', t => {619  t.plan(7)620  const fastify = Fastify({ exposeHeadRoutes: false })621 622  const outSchema = {623    $id: 'test',624    type: 'object',625    whatever: 'need to be parsed by the custom serializer'626  }627 628  fastify.setSerializerCompiler(({ schema, method, url, httpStatus }) => {629    t.equal(method, 'GET')630    t.equal(url, '/foo/:id')631    t.equal(httpStatus, '200')632    t.same(schema, outSchema)633    return data => JSON.stringify(data)634  })635 636  fastify.register((instance, opts, done) => {637    instance.get('/:id', {638      handler (req, reply) {639        reply.send({ id: 1 })640      },641      schema: {642        response: {643          200: outSchema644        }645      }646    })647    t.ok(instance.serializerCompiler, 'the serializer is set by the parent')648    done()649  }, { prefix: '/foo' })650 651  fastify.inject({652    method: 'GET',653    url: '/foo/123'654  }, (err, res) => {655    t.error(err)656    t.equal(res.payload, JSON.stringify({ id: 1 }))657  })658})659 660test('Custom setSerializerCompiler returns bad serialized output', t => {661  t.plan(4)662  const fastify = Fastify()663 664  const outSchema = {665    $id: 'test',666    type: 'object',667    whatever: 'need to be parsed by the custom serializer'668  }669 670  fastify.setSerializerCompiler(({ schema, method, url, httpStatus }) => {671    return data => {672      t.pass('returning an invalid serialization')673      return { not: 'a string' }674    }675  })676 677  fastify.get('/:id', {678    handler (req, reply) { throw new Error('ops') },679    schema: {680      response: {681        500: outSchema682      }683    }684  })685 686  fastify.inject({687    method: 'GET',688    url: '/123'689  }, (err, res) => {690    t.error(err)691    t.equal(res.statusCode, 500)692    t.strictSame(res.json(), {693      code: 'FST_ERR_REP_INVALID_PAYLOAD_TYPE',694      message: 'Attempted to send payload of invalid type \'object\'. Expected a string or Buffer.',695      statusCode: 500696    })697  })698})699 700test('Custom setSerializerCompiler with addSchema', t => {701  t.plan(6)702  const fastify = Fastify({ exposeHeadRoutes: false })703 704  const outSchema = {705    $id: 'test',706    type: 'object',707    whatever: 'need to be parsed by the custom serializer'708  }709 710  fastify.setSerializerCompiler(({ schema, method, url, httpStatus }) => {711    t.equal(method, 'GET')712    t.equal(url, '/foo/:id')713    t.equal(httpStatus, '200')714    t.same(schema, outSchema)715    return _data => JSON.stringify({ id: 2 })716  })717 718  // provoke re-creation of serialization compiler in setupSerializer719  fastify.addSchema({ $id: 'dummy', type: 'object' })720 721  fastify.get('/foo/:id', {722    handler (_req, reply) {723      reply.send({ id: 1 })724    },725    schema: {726      response: {727        200: outSchema728      }729    }730  })731 732  fastify.inject({733    method: 'GET',734    url: '/foo/123'735  }, (err, res) => {736    t.error(err)737    t.equal(res.payload, JSON.stringify({ id: 2 }))738  })739})740 741test('Custom serializer per route', async t => {742  const fastify = Fastify()743 744  const outSchema = {745    $id: 'test',746    type: 'object',747    properties: {748      mean: { type: 'string' }749    }750  }751 752  fastify.get('/default', {753    handler (req, reply) { reply.send({ mean: 'default' }) },754    schema: { response: { 200: outSchema } }755  })756 757  let hit = 0758  fastify.register((instance, opts, done) => {759    instance.setSerializerCompiler(({ schema, method, url, httpStatus }) => {760      hit++761      return data => JSON.stringify({ mean: 'custom' })762    })763    instance.get('/custom', {764      handler (req, reply) { reply.send({}) },765      schema: { response: { 200: outSchema } }766    })767    instance.get('/route', {768      handler (req, reply) { reply.send({}) },769      serializerCompiler: ({ schema, method, url, httpPart }) => {770        hit++771        return data => JSON.stringify({ mean: 'route' })772      },773      schema: { response: { 200: outSchema } }774    })775 776    done()777  })778 779  let res = await fastify.inject('/default')780  t.equal(res.json().mean, 'default')781 782  res = await fastify.inject('/custom')783  t.equal(res.json().mean, 'custom')784 785  res = await fastify.inject('/route')786  t.equal(res.json().mean, 'route')787 788  t.equal(hit, 4, 'the custom and route serializer has been called')789})790 791test('Reply serializer win over serializer ', t => {792  t.plan(6)793 794  const fastify = Fastify()795  fastify.setReplySerializer(function (payload, statusCode) {796    t.same(payload, { name: 'Foo', work: 'Bar', nick: 'Boo' })797    return 'instance serializator'798  })799 800  fastify.get('/', {801    schema: {802      response: {803        '2xx': {804          type: 'object',805          properties: {806            name: { type: 'string' },807            work: { type: 'string' }808          }809        }810      }811    },812    serializerCompiler: ({ schema, method, url, httpPart }) => {813      t.ok(method, 'the custom compiler has been created')814      return () => {815        t.fail('the serializer must not be called when there is a reply serializer')816        return 'fail'817      }818    }819  }, function (req, reply) {820    reply.code(200).send({ name: 'Foo', work: 'Bar', nick: 'Boo' })821  })822 823  fastify.inject('/', (err, res) => {824    t.error(err)825    t.same(res.payload, 'instance serializator')826    t.equal(res.statusCode, 200)827  })828})829 830test('Reply serializer win over serializer ', t => {831  t.plan(6)832 833  const fastify = Fastify()834  fastify.setReplySerializer(function (payload, statusCode) {835    t.same(payload, { name: 'Foo', work: 'Bar', nick: 'Boo' })836    return 'instance serializator'837  })838 839  fastify.get('/', {840    schema: {841      response: {842        '2xx': {843          type: 'object',844          properties: {845            name: { type: 'string' },846            work: { type: 'string' }847          }848        }849      }850    },851    serializerCompiler: ({ schema, method, url, httpPart }) => {852      t.ok(method, 'the custom compiler has been created')853      return () => {854        t.fail('the serializer must not be called when there is a reply serializer')855        return 'fail'856      }857    }858  }, function (req, reply) {859    reply.code(200).send({ name: 'Foo', work: 'Bar', nick: 'Boo' })860  })861 862  fastify.inject('/', (err, res) => {863    t.error(err)864    t.same(res.payload, 'instance serializator')865    t.equal(res.statusCode, 200)866  })867})868 869test('The schema compiler recreate itself if needed', t => {870  t.plan(1)871  const fastify = Fastify()872 873  fastify.options('/', {874    schema: {875      response: { '2xx': { hello: { type: 'string' } } }876    }877  }, echoBody)878 879  fastify.register(function (fastify, options, done) {880    fastify.addSchema({881      $id: 'identifier',882      type: 'string',883      format: 'uuid'884    })885 886    fastify.get('/', {887      schema: {888        response: {889          '2xx': {890            foobarId: { $ref: 'identifier#' }891          }892        }893      }894    }, echoBody)895 896    done()897  })898 899  fastify.ready(err => { t.error(err) })900})901 902test('The schema changes the default error handler output', async t => {903  t.plan(4)904  const fastify = Fastify()905 906  fastify.get('/:code', {907    schema: {908      response: {909        '2xx': { hello: { type: 'string' } },910        501: {911          type: 'object',912          properties: {913            message: { type: 'string' }914          }915        },916        '5xx': {917          type: 'object',918          properties: {919            customId: { type: 'number' },920            error: { type: 'string' },921            message: { type: 'string' }922          }923        }924      }925    }926  }, (request, reply) => {927    if (request.params.code === '501') {928      return reply.code(501).send(new Error('501 message'))929    }930    const error = new Error('500 message')931    error.customId = 42932    reply.send(error)933  })934 935  let res = await fastify.inject('/501')936  t.equal(res.statusCode, 501)937  t.same(res.json(), { message: '501 message' })938 939  res = await fastify.inject('/500')940  t.equal(res.statusCode, 500)941  t.same(res.json(), { error: 'Internal Server Error', message: '500 message', customId: 42 })942})943 944test('do not crash if status code serializer errors', async t => {945  const fastify = Fastify()946 947  const requiresFoo = {948    type: 'object',949    properties: { foo: { type: 'string' } },950    required: ['foo']951  }952 953  const someUserErrorType2 = {954    type: 'object',955    properties: {956      customCode: { type: 'number' }957    },958    required: ['customCode']959  }960 961  fastify.get(962    '/',963    {964      schema: {965        query: requiresFoo,966        response: { 400: someUserErrorType2 }967      }968    },969    (request, reply) => {970      t.fail('handler, should not be called')971    }972  )973 974  const res = await fastify.inject({975    path: '/',976    query: {977      notfoo: true978    }979  })980  t.equal(res.statusCode, 500)981  t.same(res.json(), {982    statusCode: 500,983    code: 'FST_ERR_FAILED_ERROR_SERIALIZATION',984    message: 'Failed to serialize an error. Error: "customCode" is required!. ' +985      'Original error: querystring must have required property \'foo\''986  })987})988 989test('custom schema serializer error, empty message', async t => {990  t.plan(2)991  const fastify = Fastify()992 993  fastify.get('/:code', {994    schema: {995      response: {996        '2xx': { hello: { type: 'string' } },997        501: {998          type: 'object',999          properties: {1000            message: { type: 'string' }1001          }1002        }1003      }1004    }1005  }, (request, reply) => {1006    if (request.params.code === '501') {1007      return reply.code(501).send(new Error(''))1008    }1009  })1010 1011  const res = await fastify.inject('/501')1012  t.equal(res.statusCode, 501)1013  t.same(res.json(), { message: '' })1014})1015 1016test('error in custom schema serialize compiler, throw FST_ERR_SCH_SERIALIZATION_BUILD error', t => {1017  t.plan(3)1018 1019  const fastify = Fastify()1020 1021  fastify.get('/', {1022    schema: {1023      response: {1024        '2xx': {1025          type: 'object',1026          properties: {1027            some: { type: 'string' }1028          }1029        },1030        500: {1031          type: 'object',1032          properties: {1033            message: { type: 'string' }1034          }1035        }1036      }1037    },1038    serializerCompiler: () => {1039      throw new Error('CUSTOM_ERROR')1040    }1041  }, function (req, reply) {1042    reply.code(200).send({ some: 'thing' })1043  })1044 1045  fastify.ready((err) => {1046    t.equal(err.message, 'Failed building the serialization schema for GET: /, due to error CUSTOM_ERROR')1047    t.equal(err.statusCode, 500)1048    t.equal(err.code, 'FST_ERR_SCH_SERIALIZATION_BUILD')1049  })1050})1051 1052test('Errors in serializer send to errorHandler', async t => {1053  let savedError1054 1055  const fastify = Fastify()1056  fastify.get('/', {1057    schema: {1058      response: {1059        200: {1060          type: 'object',1061          properties: {1062            name: { type: 'string' },1063            power: { type: 'string' }1064          },1065          required: ['name']1066        }1067      }1068    }1069 1070  }, function (req, reply) {1071    reply.code(200).send({ no: 'thing' })1072  })1073  fastify.setErrorHandler((error, request, reply) => {1074    savedError = error1075    reply.code(500).send(error)1076  })1077 1078  const res = await fastify.inject('/')1079 1080  t.equal(res.statusCode, 500)1081 1082  // t.same(savedError, new Error('"name" is required!'));1083  t.same(res.json(), {1084    statusCode: 500,1085    error: 'Internal Server Error',1086    message: '"name" is required!'1087  })1088  t.ok(savedError, 'error presents')1089  t.ok(savedError.serialization, 'Serialization sign presents')1090  t.end()1091})1092 1093test('capital X', t => {1094  t.plan(3)1095 1096  const fastify = Fastify()1097  fastify.get('/', {1098    schema: {1099      response: {1100        '2XX': {1101          type: 'object',1102          properties: {1103            name: { type: 'string' },1104            work: { type: 'string' }1105          }1106        }1107      }1108    }1109  }, function (req, reply) {1110    reply.code(200).send({ name: 'Foo', work: 'Bar', nick: 'Boo' })1111  })1112 1113  fastify.inject('/', (err, res) => {1114    t.error(err)1115    t.same(res.json(), { name: 'Foo', work: 'Bar' })1116    t.equal(res.statusCode, 200)1117  })1118})1119 1120test('allow default as status code and used as last fallback', t => {1121  t.plan(3)1122  const fastify = Fastify()1123 1124  fastify.route({1125    url: '/',1126    method: 'GET',1127    schema: {1128      response: {1129        default: {1130          type: 'object',1131          properties: {1132            name: { type: 'string' },1133            work: { type: 'string' }1134          }1135        }1136      }1137    },1138    handler: (req, reply) => {1139      reply.code(200).send({ name: 'Foo', work: 'Bar', nick: 'Boo' })1140    }1141  })1142 1143  fastify.inject('/', (err, res) => {1144    t.error(err)1145    t.same(res.json(), { name: 'Foo', work: 'Bar' })1146    t.equal(res.statusCode, 200)1147  })1148})1149