strong-tie/inbound-calls
0
1'use strict'2 3const { test } = require('node:test')4const Ajv = require('ajv')5const { kRequestCacheValidateFns, kRouteContext } = require('../../lib/symbols')6const Fastify = require('../../fastify')7 8const defaultSchema = {9 type: 'object',10 required: ['hello'],11 properties: {12 hello: { type: 'string' },13 world: { type: 'string' }14 }15}16 17const requestSchema = {18 params: {19 type: 'object',20 properties: {21 id: {22 type: 'integer',23 minimum: 124 }25 }26 },27 querystring: {28 type: 'object',29 properties: {30 foo: {31 type: 'string',32 enum: ['bar']33 }34 }35 },36 body: defaultSchema,37 headers: {38 type: 'object',39 properties: {40 'x-foo': {41 type: 'string'42 }43 }44 }45}46 47test('#compileValidationSchema', async subtest => {48 subtest.plan(7)49 50 await subtest.test('Should return a function - Route without schema', async t => {51 const fastify = Fastify()52 53 t.plan(3)54 55 fastify.get('/', (req, reply) => {56 const validate = req.compileValidationSchema(defaultSchema)57 58 t.assert.ok(validate instanceof Function)59 t.assert.ok(validate({ hello: 'world' }))60 t.assert.ok(!validate({ world: 'foo' }))61 62 reply.send({ hello: 'world' })63 })64 65 await fastify.inject({66 path: '/',67 method: 'GET'68 })69 })70 71 await subtest.test('Validate function errors property should be null after validation when input is valid', async t => {72 const fastify = Fastify()73 74 t.plan(3)75 76 fastify.get('/', (req, reply) => {77 const validate = req.compileValidationSchema(defaultSchema)78 79 t.assert.ok(validate({ hello: 'world' }))80 t.assert.ok(Object.hasOwn(validate, 'errors'))81 t.assert.strictEqual(validate.errors, null)82 83 reply.send({ hello: 'world' })84 })85 86 await fastify.inject({87 path: '/',88 method: 'GET'89 })90 })91 92 await subtest.test('Validate function errors property should be an array of errors after validation when input is valid', async t => {93 const fastify = Fastify()94 95 t.plan(4)96 97 fastify.get('/', (req, reply) => {98 const validate = req.compileValidationSchema(defaultSchema)99 100 t.assert.ok(!validate({ world: 'foo' }))101 t.assert.ok(Object.hasOwn(validate, 'errors'))102 t.assert.ok(Array.isArray(validate.errors))103 t.assert.ok(validate.errors.length > 0)104 105 reply.send({ hello: 'world' })106 })107 108 await fastify.inject({109 path: '/',110 method: 'GET'111 })112 })113 114 await subtest.test(115 'Should reuse the validate fn across multiple invocations - Route without schema',116 async t => {117 const fastify = Fastify()118 let validate = null119 let counter = 0120 121 t.plan(16)122 123 fastify.get('/', (req, reply) => {124 counter++125 if (counter > 1) {126 const newValidate = req.compileValidationSchema(defaultSchema)127 t.assert.strictEqual(validate, newValidate, 'Are the same validate function')128 validate = newValidate129 } else {130 validate = req.compileValidationSchema(defaultSchema)131 }132 133 t.assert.ok(validate instanceof Function)134 t.assert.ok(validate({ hello: 'world' }))135 t.assert.ok(!validate({ world: 'foo' }))136 137 reply.send({ hello: 'world' })138 })139 140 await Promise.all([141 fastify.inject({142 path: '/',143 method: 'GET'144 }),145 fastify.inject({146 path: '/',147 method: 'GET'148 }),149 fastify.inject({150 path: '/',151 method: 'GET'152 }),153 fastify.inject({154 path: '/',155 method: 'GET'156 })157 ])158 159 t.assert.strictEqual(counter, 4)160 }161 )162 163 await subtest.test('Should return a function - Route with schema', async t => {164 const fastify = Fastify()165 166 t.plan(3)167 168 fastify.post(169 '/',170 {171 schema: {172 body: defaultSchema173 }174 },175 (req, reply) => {176 const validate = req.compileValidationSchema(defaultSchema)177 178 t.assert.ok(validate instanceof Function)179 t.assert.ok(validate({ hello: 'world' }))180 t.assert.ok(!validate({ world: 'foo' }))181 182 reply.send({ hello: 'world' })183 }184 )185 186 await fastify.inject({187 path: '/',188 method: 'POST',189 payload: {190 hello: 'world',191 world: 'foo'192 }193 })194 })195 196 await subtest.test(197 'Should use the custom validator compiler for the route',198 async t => {199 const fastify = Fastify()200 let called = 0201 const custom = ({ schema, httpPart, url, method }) => {202 t.assert.strictEqual(schema, defaultSchema)203 t.assert.strictEqual(url, '/')204 t.assert.strictEqual(method, 'GET')205 t.assert.strictEqual(httpPart, 'querystring')206 207 return input => {208 called++209 t.assert.deepStrictEqual(input, { hello: 'world' })210 return true211 }212 }213 214 t.plan(10)215 216 fastify.get('/', { validatorCompiler: custom }, (req, reply) => {217 const first = req.compileValidationSchema(defaultSchema, 'querystring')218 const second = req.compileValidationSchema(defaultSchema, 'querystring')219 220 t.assert.strictEqual(first, second)221 t.assert.ok(first({ hello: 'world' }))222 t.assert.ok(second({ hello: 'world' }))223 t.assert.strictEqual(called, 2)224 225 reply.send({ hello: 'world' })226 })227 228 await fastify.inject({229 path: '/',230 method: 'GET'231 })232 }233 )234 235 await subtest.test(236 'Should instantiate a WeakMap when executed for first time',237 async t => {238 const fastify = Fastify()239 240 t.plan(5)241 242 fastify.get('/', (req, reply) => {243 t.assert.strictEqual(req[kRouteContext][kRequestCacheValidateFns], null)244 t.assert.ok(req.compileValidationSchema(defaultSchema) instanceof Function)245 t.assert.ok(req[kRouteContext][kRequestCacheValidateFns] instanceof WeakMap)246 t.assert.ok(req.compileValidationSchema(Object.assign({}, defaultSchema)) instanceof Function)247 t.assert.ok(req[kRouteContext][kRequestCacheValidateFns] instanceof WeakMap)248 249 reply.send({ hello: 'world' })250 })251 252 await fastify.inject({253 path: '/',254 method: 'GET'255 })256 }257 )258})259 260test('#getValidationFunction', async subtest => {261 subtest.plan(6)262 263 await subtest.test('Should return a validation function', async t => {264 const fastify = Fastify()265 266 t.plan(1)267 268 fastify.get('/', (req, reply) => {269 const original = req.compileValidationSchema(defaultSchema)270 const referenced = req.getValidationFunction(defaultSchema)271 272 t.assert.strictEqual(original, referenced)273 274 reply.send({ hello: 'world' })275 })276 277 await fastify.inject({278 path: '/',279 method: 'GET'280 })281 })282 283 await subtest.test('Validate function errors property should be null after validation when input is valid', async t => {284 const fastify = Fastify()285 286 t.plan(3)287 288 fastify.get('/', (req, reply) => {289 req.compileValidationSchema(defaultSchema)290 const validate = req.getValidationFunction(defaultSchema)291 292 t.assert.ok(validate({ hello: 'world' }))293 t.assert.ok(Object.hasOwn(validate, 'errors'))294 t.assert.strictEqual(validate.errors, null)295 296 reply.send({ hello: 'world' })297 })298 299 await fastify.inject({300 path: '/',301 method: 'GET'302 })303 })304 305 await subtest.test('Validate function errors property should be an array of errors after validation when input is valid', async t => {306 const fastify = Fastify()307 308 t.plan(4)309 310 fastify.get('/', (req, reply) => {311 req.compileValidationSchema(defaultSchema)312 const validate = req.getValidationFunction(defaultSchema)313 314 t.assert.ok(!validate({ world: 'foo' }))315 t.assert.ok(Object.hasOwn(validate, 'errors'))316 t.assert.ok(Array.isArray(validate.errors))317 t.assert.ok(validate.errors.length > 0)318 319 reply.send({ hello: 'world' })320 })321 322 await fastify.inject({323 path: '/',324 method: 'GET'325 })326 })327 328 await subtest.test('Should return undefined if no schema compiled', async t => {329 const fastify = Fastify()330 331 t.plan(2)332 333 fastify.get('/', (req, reply) => {334 const validate = req.getValidationFunction(defaultSchema)335 t.assert.ok(!validate)336 337 const validateFn = req.getValidationFunction(42)338 t.assert.ok(!validateFn)339 340 reply.send({ hello: 'world' })341 })342 343 await fastify.inject('/')344 })345 346 await subtest.test(347 'Should return the validation function from each HTTP part',348 async t => {349 const fastify = Fastify()350 let headerValidation = null351 let customValidation = null352 353 t.plan(15)354 355 fastify.post(356 '/:id',357 {358 schema: requestSchema359 },360 (req, reply) => {361 const { params } = req362 363 switch (params.id) {364 case 1:365 customValidation = req.compileValidationSchema(defaultSchema)366 t.assert.ok(req.getValidationFunction('body'))367 t.assert.ok(req.getValidationFunction('body')({ hello: 'world' }))368 t.assert.ok(!req.getValidationFunction('body')({ world: 'hello' }))369 break370 case 2:371 headerValidation = req.getValidationFunction('headers')372 t.assert.ok(headerValidation)373 t.assert.ok(headerValidation({ 'x-foo': 'world' }))374 t.assert.ok(!headerValidation({ 'x-foo': [] }))375 break376 case 3:377 t.assert.ok(req.getValidationFunction('params'))378 t.assert.ok(req.getValidationFunction('params')({ id: 123 }))379 t.assert.ok(!req.getValidationFunction('params'({ id: 1.2 })))380 break381 case 4:382 t.assert.ok(req.getValidationFunction('querystring'))383 t.assert.ok(req.getValidationFunction('querystring')({ foo: 'bar' }))384 t.assert.ok(!req.getValidationFunction('querystring')({ foo: 'not-bar' })385 )386 break387 case 5:388 t.assert.strictEqual(389 customValidation,390 req.getValidationFunction(defaultSchema)391 )392 t.assert.ok(customValidation({ hello: 'world' }))393 t.assert.ok(!customValidation({}))394 t.assert.strictEqual(headerValidation, req.getValidationFunction('headers'))395 break396 default:397 t.assert.fail('Invalid id')398 }399 400 reply.send({ hello: 'world' })401 }402 )403 404 const promises = []405 406 for (let i = 1; i < 6; i++) {407 promises.push(408 fastify.inject({409 path: `/${i}`,410 method: 'post',411 query: { foo: 'bar' },412 payload: {413 hello: 'world'414 },415 headers: {416 'x-foo': 'x-bar'417 }418 })419 )420 }421 422 await Promise.all(promises)423 }424 )425 426 await subtest.test('Should not set a WeakMap if there is no schema', async t => {427 const fastify = Fastify()428 429 t.plan(1)430 431 fastify.get('/', (req, reply) => {432 req.getValidationFunction(defaultSchema)433 req.getValidationFunction('body')434 435 t.assert.strictEqual(req[kRouteContext][kRequestCacheValidateFns], null)436 reply.send({ hello: 'world' })437 })438 439 await fastify.inject({440 path: '/',441 method: 'GET'442 })443 })444})445 446test('#validate', async subtest => {447 subtest.plan(7)448 449 await subtest.test(450 'Should return true/false if input valid - Route without schema',451 async t => {452 const fastify = Fastify()453 454 t.plan(2)455 456 fastify.get('/', (req, reply) => {457 const isNotValid = req.validateInput({ world: 'string' }, defaultSchema)458 const isValid = req.validateInput({ hello: 'string' }, defaultSchema)459 460 t.assert.ok(!isNotValid)461 t.assert.ok(isValid)462 463 reply.send({ hello: 'world' })464 })465 466 await fastify.inject({467 path: '/',468 method: 'GET'469 })470 }471 )472 473 await subtest.test(474 'Should use the custom validator compiler for the route',475 async t => {476 const fastify = Fastify()477 let called = 0478 const custom = ({ schema, httpPart, url, method }) => {479 t.assert.strictEqual(schema, defaultSchema)480 t.assert.strictEqual(url, '/')481 t.assert.strictEqual(method, 'GET')482 t.assert.strictEqual(httpPart, 'querystring')483 484 return input => {485 called++486 t.assert.deepStrictEqual(input, { hello: 'world' })487 return true488 }489 }490 491 t.plan(9)492 493 fastify.get('/', { validatorCompiler: custom }, (req, reply) => {494 const ok = req.validateInput(495 { hello: 'world' },496 defaultSchema,497 'querystring'498 )499 const ok2 = req.validateInput({ hello: 'world' }, defaultSchema)500 501 t.assert.ok(ok)502 t.assert.ok(ok2)503 t.assert.strictEqual(called, 2)504 505 reply.send({ hello: 'world' })506 })507 508 await fastify.inject({509 path: '/',510 method: 'GET'511 })512 }513 )514 515 await subtest.test(516 'Should return true/false if input valid - With Schema for Route defined',517 async t => {518 const fastify = Fastify()519 520 t.plan(8)521 522 fastify.post(523 '/:id',524 {525 schema: requestSchema526 },527 (req, reply) => {528 const { params } = req529 530 switch (params.id) {531 case 1:532 t.assert.ok(req.validateInput({ hello: 'world' }, 'body'))533 t.assert.ok(!req.validateInput({ hello: [], world: 'foo' }, 'body'))534 break535 case 2:536 t.assert.ok(!req.validateInput({ foo: 'something' }, 'querystring'))537 t.assert.ok(req.validateInput({ foo: 'bar' }, 'querystring'))538 break539 case 3:540 t.assert.ok(!req.validateInput({ 'x-foo': [] }, 'headers'))541 t.assert.ok(req.validateInput({ 'x-foo': 'something' }, 'headers'))542 break543 case 4:544 t.assert.ok(req.validateInput({ id: params.id }, 'params'))545 t.assert.ok(!req.validateInput({ id: 0 }, 'params'))546 break547 default:548 t.assert.fail('Invalid id')549 }550 551 reply.send({ hello: 'world' })552 }553 )554 555 const promises = []556 557 for (let i = 1; i < 5; i++) {558 promises.push(559 fastify.inject({560 path: `/${i}`,561 method: 'post',562 query: { foo: 'bar' },563 payload: {564 hello: 'world'565 },566 headers: {567 'x-foo': 'x-bar'568 }569 })570 )571 }572 573 await Promise.all(promises)574 }575 )576 577 await subtest.test(578 'Should throw if missing validation fn for HTTP part and not schema provided',579 async t => {580 const fastify = Fastify()581 582 t.plan(10)583 584 fastify.get('/:id', (req, reply) => {585 const { params } = req586 587 switch (parseInt(params.id)) {588 case 1:589 req.validateInput({}, 'body')590 break591 case 2:592 req.validateInput({}, 'querystring')593 break594 case 3:595 req.validateInput({}, 'query')596 break597 case 4:598 req.validateInput({ 'x-foo': [] }, 'headers')599 break600 case 5:601 req.validateInput({ id: 0 }, 'params')602 break603 default:604 t.assert.fail('Invalid id')605 }606 })607 608 const promises = []609 610 for (let i = 1; i < 6; i++) {611 promises.push(612 (async j => {613 const response = await fastify.inject(`/${j}`)614 615 const result = response.json()616 t.assert.strictEqual(result.statusCode, 500)617 t.assert.strictEqual(result.code, 'FST_ERR_REQ_INVALID_VALIDATION_INVOCATION')618 })(i)619 )620 }621 622 await Promise.all(promises)623 }624 )625 626 await subtest.test(627 'Should throw if missing validation fn for HTTP part and not valid schema provided',628 async t => {629 const fastify = Fastify()630 631 t.plan(10)632 633 fastify.get('/:id', (req, reply) => {634 const { params } = req635 636 switch (parseInt(params.id)) {637 case 1:638 req.validateInput({}, 1, 'body')639 break640 case 2:641 req.validateInput({}, [], 'querystring')642 break643 case 3:644 req.validateInput({}, '', 'query')645 break646 case 4:647 req.validateInput({ 'x-foo': [] }, null, 'headers')648 break649 case 5:650 req.validateInput({ id: 0 }, () => {}, 'params')651 break652 default:653 t.assert.fail('Invalid id')654 }655 })656 657 const promises = []658 659 for (let i = 1; i < 6; i++) {660 promises.push(661 (async j => {662 const response = await fastify.inject({663 path: `/${j}`,664 method: 'GET'665 })666 667 const result = response.json()668 t.assert.strictEqual(result.statusCode, 500)669 t.assert.strictEqual(result.code, 'FST_ERR_REQ_INVALID_VALIDATION_INVOCATION')670 })(i)671 )672 }673 674 await Promise.all(promises)675 }676 )677 678 await subtest.test('Should throw if invalid schema passed', async t => {679 const fastify = Fastify()680 681 t.plan(10)682 683 fastify.get('/:id', (req, reply) => {684 const { params } = req685 686 switch (parseInt(params.id)) {687 case 1:688 req.validateInput({}, 1)689 break690 case 2:691 req.validateInput({}, '')692 break693 case 3:694 req.validateInput({}, [])695 break696 case 4:697 req.validateInput({ 'x-foo': [] }, null)698 break699 case 5:700 req.validateInput({ id: 0 }, () => {})701 break702 default:703 t.assert.fail('Invalid id')704 }705 })706 707 const promises = []708 709 for (let i = 1; i < 6; i++) {710 promises.push(711 (async j => {712 const response = await fastify.inject({713 path: `/${j}`,714 method: 'GET'715 })716 717 const result = response.json()718 t.assert.strictEqual(result.statusCode, 500)719 t.assert.strictEqual(result.code, 'FST_ERR_REQ_INVALID_VALIDATION_INVOCATION')720 })(i)721 )722 }723 724 await Promise.all(promises)725 })726 727 await subtest.test(728 'Should set a WeakMap if compiling the very first schema',729 async t => {730 const fastify = Fastify()731 732 t.plan(3)733 734 fastify.get('/', (req, reply) => {735 t.assert.strictEqual(req[kRouteContext][kRequestCacheValidateFns], null)736 t.assert.strictEqual(req.validateInput({ hello: 'world' }, defaultSchema), true)737 t.assert.ok(req[kRouteContext][kRequestCacheValidateFns] instanceof WeakMap)738 739 reply.send({ hello: 'world' })740 })741 742 await fastify.inject({743 path: '/',744 method: 'GET'745 })746 }747 )748})749 750test('Nested Context', async subtest => {751 subtest.plan(1)752 753 await subtest.test('Level_1', async tst => {754 tst.plan(3)755 await tst.test('#compileValidationSchema', async ntst => {756 ntst.plan(5)757 758 await ntst.test('Should return a function - Route without schema', async t => {759 const fastify = Fastify()760 761 fastify.register((instance, opts, next) => {762 instance.get('/', (req, reply) => {763 const validate = req.compileValidationSchema(defaultSchema)764 765 t.assert.ok(validate, Function)766 t.assert.ok(validate({ hello: 'world' }))767 t.assert.ok(!validate({ world: 'foo' }))768 769 reply.send({ hello: 'world' })770 })771 772 next()773 })774 775 t.plan(3)776 777 await fastify.inject({778 path: '/',779 method: 'GET'780 })781 })782 783 await ntst.test(784 'Should reuse the validate fn across multiple invocations - Route without schema',785 async t => {786 const fastify = Fastify()787 let validate = null788 let counter = 0789 790 t.plan(16)791 792 fastify.register((instance, opts, next) => {793 instance.get('/', (req, reply) => {794 counter++795 if (counter > 1) {796 const newValidate = req.compileValidationSchema(defaultSchema)797 t.assert.strictEqual(validate, newValidate, 'Are the same validate function')798 validate = newValidate799 } else {800 validate = req.compileValidationSchema(defaultSchema)801 }802 803 t.assert.ok(validate, Function)804 t.assert.ok(validate({ hello: 'world' }))805 t.assert.ok(!validate({ world: 'foo' }))806 807 reply.send({ hello: 'world' })808 })809 810 next()811 })812 813 await Promise.all([814 fastify.inject('/'),815 fastify.inject('/'),816 fastify.inject('/'),817 fastify.inject('/')818 ])819 820 t.assert.strictEqual(counter, 4)821 }822 )823 824 await ntst.test('Should return a function - Route with schema', async t => {825 const fastify = Fastify()826 827 t.plan(3)828 829 fastify.register((instance, opts, next) => {830 instance.post(831 '/',832 {833 schema: {834 body: defaultSchema835 }836 },837 (req, reply) => {838 const validate = req.compileValidationSchema(defaultSchema)839 840 t.assert.ok(validate, Function)841 t.assert.ok(validate({ hello: 'world' }))842 t.assert.ok(!validate({ world: 'foo' }))843 844 reply.send({ hello: 'world' })845 }846 )847 848 next()849 })850 851 await fastify.inject({852 path: '/',853 method: 'POST',854 payload: {855 hello: 'world',856 world: 'foo'857 }858 })859 })860 861 await ntst.test(862 'Should use the custom validator compiler for the route',863 async t => {864 const fastify = Fastify()865 let called = 0866 867 t.plan(10)868 869 fastify.register((instance, opts, next) => {870 const custom = ({ schema, httpPart, url, method }) => {871 t.assert.strictEqual(schema, defaultSchema)872 t.assert.strictEqual(url, '/')873 t.assert.strictEqual(method, 'GET')874 t.assert.strictEqual(httpPart, 'querystring')875 876 return input => {877 called++878 t.assert.deepStrictEqual(input, { hello: 'world' })879 return true880 }881 }882 883 fastify.get('/', { validatorCompiler: custom }, (req, reply) => {884 const first = req.compileValidationSchema(885 defaultSchema,886 'querystring'887 )888 const second = req.compileValidationSchema(889 defaultSchema,890 'querystring'891 )892 893 t.assert.strictEqual(first, second)894 t.assert.ok(first({ hello: 'world' }))895 t.assert.ok(second({ hello: 'world' }))896 t.assert.strictEqual(called, 2)897 898 reply.send({ hello: 'world' })899 })900 901 next()902 })903 904 await fastify.inject('/')905 }906 )907 908 await ntst.test('Should compile the custom validation - nested with schema.headers', async t => {909 const fastify = Fastify()910 let called = false911 912 const schemaWithHeaders = {913 headers: {914 'x-foo': {915 type: 'string'916 }917 }918 }919 920 const custom = ({ schema, httpPart, url, method }) => {921 if (called) return () => true922 // only custom validators keep the same headers object923 t.assert.strictEqual(schema, schemaWithHeaders.headers)924 t.assert.strictEqual(url, '/')925 t.assert.strictEqual(httpPart, 'headers')926 called = true927 return () => true928 }929 930 t.plan(4)931 932 fastify.setValidatorCompiler(custom)933 934 fastify.register((instance, opts, next) => {935 instance.get('/', { schema: schemaWithHeaders }, (req, reply) => {936 t.assert.strictEqual(called, true)937 938 reply.send({ hello: 'world' })939 })940 941 next()942 })943 944 await fastify.inject('/')945 })946 })947 948 await tst.test('#getValidationFunction', async ntst => {949 ntst.plan(6)950 951 await ntst.test('Should return a validation function', async t => {952 const fastify = Fastify()953 954 t.plan(1)955 956 fastify.register((instance, opts, next) => {957 instance.get('/', (req, reply) => {958 const original = req.compileValidationSchema(defaultSchema)959 const referenced = req.getValidationFunction(defaultSchema)960 961 t.assert.strictEqual(original, referenced)962 963 reply.send({ hello: 'world' })964 })965 966 next()967 })968 969 await fastify.inject('/')970 })971 972 await ntst.test('Should return undefined if no schema compiled', async t => {973 const fastify = Fastify()974 975 t.plan(1)976 977 fastify.register((instance, opts, next) => {978 instance.get('/', (req, reply) => {979 const validate = req.getValidationFunction(defaultSchema)980 981 t.assert.ok(!validate)982 983 reply.send({ hello: 'world' })984 })985 986 next()987 })988 989 await fastify.inject('/')990 })991 992 await ntst.test(993 'Should return the validation function from each HTTP part',994 async t => {995 const fastify = Fastify()996 let headerValidation = null997 let customValidation = null998 999 t.plan(15)1000 1001 fastify.register((instance, opts, next) => {1002 instance.post(1003 '/:id',1004 {1005 schema: requestSchema1006 },1007 (req, reply) => {1008 const { params } = req1009 1010 switch (params.id) {1011 case 1:1012 customValidation = req.compileValidationSchema(1013 defaultSchema1014 )1015 t.assert.ok(req.getValidationFunction('body'))1016 t.assert.ok(req.getValidationFunction('body')({ hello: 'world' }))1017 t.assert.ok(!req.getValidationFunction('body')({ world: 'hello' })1018 )1019 break1020 case 2:1021 headerValidation = req.getValidationFunction('headers')1022 t.assert.ok(headerValidation)1023 t.assert.ok(headerValidation({ 'x-foo': 'world' }))1024 t.assert.ok(!headerValidation({ 'x-foo': [] }))1025 break1026 case 3:1027 t.assert.ok(req.getValidationFunction('params'))1028 t.assert.ok(req.getValidationFunction('params')({ id: 123 }))1029 t.assert.ok(!req.getValidationFunction('params'({ id: 1.2 })))1030 break1031 case 4:1032 t.assert.ok(req.getValidationFunction('querystring'))1033 t.assert.ok(1034 req.getValidationFunction('querystring')({ foo: 'bar' })1035 )1036 t.assert.ok(!req.getValidationFunction('querystring')({1037 foo: 'not-bar'1038 })1039 )1040 break1041 case 5:1042 t.assert.strictEqual(1043 customValidation,1044 req.getValidationFunction(defaultSchema)1045 )1046 t.assert.ok(customValidation({ hello: 'world' }))1047 t.assert.ok(!customValidation({}))1048 t.assert.strictEqual(1049 headerValidation,1050 req.getValidationFunction('headers')1051 )1052 break1053 default:1054 t.assert.fail('Invalid id')1055 }1056 1057 reply.send({ hello: 'world' })1058 }1059 )1060 1061 next()1062 })1063 const promises = []1064 1065 for (let i = 1; i < 6; i++) {1066 promises.push(1067 fastify.inject({1068 path: `/${i}`,1069 method: 'post',1070 query: { foo: 'bar' },1071 payload: {1072 hello: 'world'1073 },1074 headers: {1075 'x-foo': 'x-bar'1076 }1077 })1078 )1079 }1080 1081 await Promise.all(promises)1082 }1083 )1084 1085 await ntst.test('Should return a validation function - nested', async t => {1086 const fastify = Fastify()1087 let called = false1088 const custom = ({ schema, httpPart, url, method }) => {1089 t.assert.strictEqual(schema, defaultSchema)1090 t.assert.strictEqual(url, '/')1091 t.assert.strictEqual(method, 'GET')1092 t.assert.ok(!httpPart)1093 1094 called = true1095 return () => true1096 }1097 1098 t.plan(6)1099 1100 fastify.setValidatorCompiler(custom)1101 1102 fastify.register((instance, opts, next) => {1103 instance.get('/', (req, reply) => {1104 const original = req.compileValidationSchema(defaultSchema)1105 const referenced = req.getValidationFunction(defaultSchema)1106 1107 t.assert.strictEqual(original, referenced)1108 t.assert.strictEqual(called, true)1109 1110 reply.send({ hello: 'world' })1111 })1112 1113 next()1114 })1115 1116 await fastify.inject('/')1117 })1118 1119 await ntst.test(1120 'Should return undefined if no schema compiled - nested',1121 async t => {1122 const fastify = Fastify()1123 let called = 01124 const custom = ({ schema, httpPart, url, method }) => {1125 called++1126 return () => true1127 }1128 1129 t.plan(3)1130 1131 fastify.setValidatorCompiler(custom)1132 1133 fastify.get('/', (req, reply) => {1134 const validate = req.compileValidationSchema(defaultSchema)1135 1136 t.assert.strictEqual(typeof validate, 'function')1137 1138 reply.send({ hello: 'world' })1139 })1140 1141 fastify.register(1142 (instance, opts, next) => {1143 instance.get('/', (req, reply) => {1144 const validate = req.getValidationFunction(defaultSchema)1145 1146 t.assert.ok(!validate)1147 t.assert.strictEqual(called, 1)1148 1149 reply.send({ hello: 'world' })1150 })1151 1152 next()1153 },1154 { prefix: '/nested' }1155 )1156 1157 await fastify.inject('/')1158 await fastify.inject('/nested')1159 }1160 )1161 1162 await ntst.test('Should per-route defined validation compiler', async t => {1163 const fastify = Fastify()1164 let validateParent1165 let validateChild1166 let calledParent = 01167 let calledChild = 01168 const customParent = ({ schema, httpPart, url, method }) => {1169 calledParent++1170 return () => true1171 }1172 1173 const customChild = ({ schema, httpPart, url, method }) => {1174 calledChild++1175 return () => true1176 }1177 1178 t.plan(5)1179 1180 fastify.setValidatorCompiler(customParent)1181 1182 fastify.get('/', (req, reply) => {1183 validateParent = req.compileValidationSchema(defaultSchema)1184 1185 t.assert.strictEqual(typeof validateParent, 'function')1186 1187 reply.send({ hello: 'world' })1188 })1189 1190 fastify.register(1191 (instance, opts, next) => {1192 instance.get(1193 '/',1194 {1195 validatorCompiler: customChild1196 },1197 (req, reply) => {1198 const validate1 = req.compileValidationSchema(defaultSchema)1199 validateChild = req.getValidationFunction(defaultSchema)1200 