strong-tie/inbound-calls
0
1'use strict'2 3const { test } = require('node:test')4const fp = require('fastify-plugin')5const sget = require('simple-get').concat6const errors = require('http-errors')7const split = require('split2')8const Fastify = require('..')9const { getServerUrl } = require('./helper')10 11test('default 404', async t => {12 t.plan(4)13 14 const fastify = Fastify()15 16 fastify.get('/', function (req, reply) {17 reply.send({ hello: 'world' })18 })19 20 t.after(() => { fastify.close() })21 22 await fastify.listen({ port: 0 })23 24 await t.test('unsupported method', (t, done) => {25 t.plan(3)26 sget({27 method: 'PUT',28 url: getServerUrl(fastify),29 body: {},30 json: true31 }, (err, response, body) => {32 t.assert.ifError(err)33 t.assert.strictEqual(response.statusCode, 404)34 t.assert.strictEqual(response.headers['content-type'], 'application/json; charset=utf-8')35 done()36 })37 })38 39 // Return 404 instead of 405 see https://github.com/fastify/fastify/pull/862 for discussion40 await t.test('framework-unsupported method', (t, done) => {41 t.plan(3)42 sget({43 method: 'PROPFIND',44 url: getServerUrl(fastify),45 body: {},46 json: true47 }, (err, response, body) => {48 t.assert.ifError(err)49 t.assert.strictEqual(response.statusCode, 404)50 t.assert.strictEqual(response.headers['content-type'], 'application/json; charset=utf-8')51 done()52 })53 })54 55 await t.test('unsupported route', (t, done) => {56 t.plan(3)57 sget({58 method: 'GET',59 url: getServerUrl(fastify) + '/notSupported',60 body: {},61 json: true62 }, (err, response, body) => {63 t.assert.ifError(err)64 t.assert.strictEqual(response.statusCode, 404)65 t.assert.strictEqual(response.headers['content-type'], 'application/json; charset=utf-8')66 done()67 })68 })69 70 await t.test('using post method and multipart/formdata', async t => {71 t.plan(3)72 const form = new FormData()73 form.set('test-field', 'just some field')74 75 const response = await fetch(getServerUrl(fastify) + '/notSupported', {76 method: 'POST',77 body: form78 })79 t.assert.strictEqual(response.status, 404)80 t.assert.strictEqual(response.statusText, 'Not Found')81 t.assert.strictEqual(response.headers.get('content-type'), 'application/json; charset=utf-8')82 })83})84 85test('customized 404', async t => {86 t.plan(5)87 88 const fastify = Fastify()89 90 fastify.get('/', function (req, reply) {91 reply.send({ hello: 'world' })92 })93 94 fastify.get('/with-error', function (req, reply) {95 reply.send(new errors.NotFound())96 })97 98 fastify.get('/with-error-custom-header', function (req, reply) {99 const err = new errors.NotFound()100 err.headers = { 'x-foo': 'bar' }101 reply.send(err)102 })103 104 fastify.setNotFoundHandler(function (req, reply) {105 reply.code(404).send('this was not found')106 })107 108 t.after(() => { fastify.close() })109 110 await fastify.listen({ port: 0 })111 112 await t.test('unsupported method', (t, done) => {113 t.plan(3)114 sget({115 method: 'PUT',116 url: getServerUrl(fastify),117 body: JSON.stringify({ hello: 'world' }),118 headers: { 'Content-Type': 'application/json' }119 }, (err, response, body) => {120 t.assert.ifError(err)121 t.assert.strictEqual(response.statusCode, 404)122 t.assert.strictEqual(body.toString(), 'this was not found')123 done()124 })125 })126 127 await t.test('framework-unsupported method', (t, done) => {128 t.plan(3)129 sget({130 method: 'PROPFIND',131 url: getServerUrl(fastify),132 body: JSON.stringify({ hello: 'world' }),133 headers: { 'Content-Type': 'application/json' }134 }, (err, response, body) => {135 t.assert.ifError(err)136 t.assert.strictEqual(response.statusCode, 404)137 t.assert.strictEqual(body.toString(), 'this was not found')138 done()139 })140 })141 142 await t.test('unsupported route', (t, done) => {143 t.plan(3)144 sget({145 method: 'GET',146 url: getServerUrl(fastify) + '/notSupported'147 }, (err, response, body) => {148 t.assert.ifError(err)149 t.assert.strictEqual(response.statusCode, 404)150 t.assert.strictEqual(body.toString(), 'this was not found')151 done()152 })153 })154 155 await t.test('with error object', (t, done) => {156 t.plan(3)157 sget({158 method: 'GET',159 url: getServerUrl(fastify) + '/with-error'160 }, (err, response, body) => {161 t.assert.ifError(err)162 t.assert.strictEqual(response.statusCode, 404)163 t.assert.deepStrictEqual(JSON.parse(body), {164 error: 'Not Found',165 message: 'Not Found',166 statusCode: 404167 })168 done()169 })170 })171 172 await t.test('error object with headers property', (t, done) => {173 t.plan(4)174 sget({175 method: 'GET',176 url: getServerUrl(fastify) + '/with-error-custom-header'177 }, (err, response, body) => {178 t.assert.ifError(err)179 t.assert.strictEqual(response.statusCode, 404)180 t.assert.strictEqual(response.headers['x-foo'], 'bar')181 t.assert.deepStrictEqual(JSON.parse(body), {182 error: 'Not Found',183 message: 'Not Found',184 statusCode: 404185 })186 done()187 })188 })189})190 191test('custom header in notFound handler', async t => {192 t.plan(1)193 194 const fastify = Fastify()195 196 fastify.setNotFoundHandler(function (req, reply) {197 reply.code(404).header('x-foo', 'bar').send('this was not found')198 })199 200 t.after(() => { fastify.close() })201 202 await fastify.listen({ port: 0 })203 204 await t.test('not found with custom header', (t, done) => {205 t.plan(4)206 sget({207 method: 'GET',208 url: getServerUrl(fastify) + '/notSupported'209 }, (err, response, body) => {210 t.assert.ifError(err)211 t.assert.strictEqual(response.statusCode, 404)212 t.assert.strictEqual(response.headers['x-foo'], 'bar')213 t.assert.strictEqual(body.toString(), 'this was not found')214 done()215 })216 })217})218 219test('setting a custom 404 handler multiple times is an error', async t => {220 t.plan(5)221 222 await t.test('at the root level', t => {223 t.plan(2)224 225 const fastify = Fastify()226 227 fastify.setNotFoundHandler(() => {})228 229 try {230 fastify.setNotFoundHandler(() => {})231 t.assert.fail('setting multiple 404 handlers at the same prefix encapsulation level should throw')232 } catch (err) {233 t.assert.ok(err instanceof Error)234 t.assert.strictEqual(err.message, 'Not found handler already set for Fastify instance with prefix: \'/\'')235 }236 })237 238 await t.test('at the plugin level', (t, done) => {239 t.plan(3)240 241 const fastify = Fastify()242 243 fastify.register((instance, options, done) => {244 instance.setNotFoundHandler(() => {})245 246 try {247 instance.setNotFoundHandler(() => {})248 t.assert.fail('setting multiple 404 handlers at the same prefix encapsulation level should throw')249 } catch (err) {250 t.assert.ok(err instanceof Error)251 t.assert.strictEqual(err.message, 'Not found handler already set for Fastify instance with prefix: \'/prefix\'')252 }253 254 done()255 }, { prefix: '/prefix' })256 257 fastify.listen({ port: 0 }, err => {258 t.assert.ifError(err)259 fastify.close()260 done()261 })262 })263 264 await t.test('at multiple levels', (t, done) => {265 t.plan(3)266 267 const fastify = Fastify()268 269 fastify.register((instance, options, done) => {270 try {271 instance.setNotFoundHandler(() => {})272 t.assert.fail('setting multiple 404 handlers at the same prefix encapsulation level should throw')273 } catch (err) {274 t.assert.ok(err instanceof Error)275 t.assert.strictEqual(err.message, 'Not found handler already set for Fastify instance with prefix: \'/\'')276 }277 done()278 })279 280 fastify.setNotFoundHandler(() => {})281 282 fastify.listen({ port: 0 }, err => {283 t.assert.ifError(err)284 fastify.close()285 done()286 })287 })288 289 await t.test('at multiple levels / 2', (t, done) => {290 t.plan(3)291 292 const fastify = Fastify()293 294 fastify.register((instance, options, done) => {295 instance.setNotFoundHandler(() => {})296 297 instance.register((instance2, options, done) => {298 try {299 instance2.setNotFoundHandler(() => {})300 t.assert.fail('setting multiple 404 handlers at the same prefix encapsulation level should throw')301 } catch (err) {302 t.assert.ok(err instanceof Error)303 t.assert.strictEqual(err.message, 'Not found handler already set for Fastify instance with prefix: \'/prefix\'')304 }305 done()306 })307 308 done()309 }, { prefix: '/prefix' })310 311 fastify.setNotFoundHandler(() => {})312 313 fastify.listen({ port: 0 }, err => {314 t.assert.ifError(err)315 fastify.close()316 done()317 })318 })319 320 await t.test('in separate plugins at the same level', (t, done) => {321 t.plan(3)322 323 const fastify = Fastify()324 325 fastify.register((instance, options, done) => {326 instance.register((instance2A, options, done) => {327 instance2A.setNotFoundHandler(() => {})328 done()329 })330 331 instance.register((instance2B, options, done) => {332 try {333 instance2B.setNotFoundHandler(() => {})334 t.assert.fail('setting multiple 404 handlers at the same prefix encapsulation level should throw')335 } catch (err) {336 t.assert.ok(err instanceof Error)337 t.assert.strictEqual(err.message, 'Not found handler already set for Fastify instance with prefix: \'/prefix\'')338 }339 done()340 })341 342 done()343 }, { prefix: '/prefix' })344 345 fastify.setNotFoundHandler(() => {})346 347 fastify.listen({ port: 0 }, err => {348 t.assert.ifError(err)349 fastify.close()350 done()351 })352 })353})354 355test('encapsulated 404', async t => {356 t.plan(12)357 358 const fastify = Fastify()359 360 fastify.get('/', function (req, reply) {361 reply.send({ hello: 'world' })362 })363 364 fastify.setNotFoundHandler(function (req, reply) {365 reply.code(404).send('this was not found')366 })367 368 fastify.register(function (f, opts, done) {369 f.setNotFoundHandler(function (req, reply) {370 reply.code(404).send('this was not found 2')371 })372 done()373 }, { prefix: '/test' })374 375 fastify.register(function (f, opts, done) {376 f.setNotFoundHandler(function (req, reply) {377 reply.code(404).send('this was not found 3')378 })379 done()380 }, { prefix: '/test2' })381 382 fastify.register(function (f, opts, done) {383 f.setNotFoundHandler(function (request, reply) {384 reply.code(404).send('this was not found 4')385 })386 done()387 }, { prefix: '/test3/' })388 389 t.after(() => { fastify.close() })390 391 await fastify.listen({ port: 0 })392 393 await t.test('root unsupported method', (t, done) => {394 t.plan(3)395 sget({396 method: 'PUT',397 url: getServerUrl(fastify),398 body: JSON.stringify({ hello: 'world' }),399 headers: { 'Content-Type': 'application/json' }400 }, (err, response, body) => {401 t.assert.ifError(err)402 t.assert.strictEqual(response.statusCode, 404)403 t.assert.strictEqual(body.toString(), 'this was not found')404 done()405 })406 })407 408 await t.test('root framework-unsupported method', (t, done) => {409 t.plan(3)410 sget({411 method: 'PROPFIND',412 url: getServerUrl(fastify),413 body: JSON.stringify({ hello: 'world' }),414 headers: { 'Content-Type': 'application/json' }415 }, (err, response, body) => {416 t.assert.ifError(err)417 t.assert.strictEqual(response.statusCode, 404)418 t.assert.strictEqual(body.toString(), 'this was not found')419 done()420 })421 })422 423 await t.test('root unsupported route', (t, done) => {424 t.plan(3)425 sget({426 method: 'GET',427 url: getServerUrl(fastify) + '/notSupported'428 }, (err, response, body) => {429 t.assert.ifError(err)430 t.assert.strictEqual(response.statusCode, 404)431 t.assert.strictEqual(body.toString(), 'this was not found')432 done()433 })434 })435 436 await t.test('unsupported method', (t, done) => {437 t.plan(3)438 sget({439 method: 'PUT',440 url: getServerUrl(fastify) + '/test',441 body: JSON.stringify({ hello: 'world' }),442 headers: { 'Content-Type': 'application/json' }443 }, (err, response, body) => {444 t.assert.ifError(err)445 t.assert.strictEqual(response.statusCode, 404)446 t.assert.strictEqual(body.toString(), 'this was not found 2')447 done()448 })449 })450 451 await t.test('framework-unsupported method', (t, done) => {452 t.plan(3)453 sget({454 method: 'PROPFIND',455 url: getServerUrl(fastify) + '/test',456 body: JSON.stringify({ hello: 'world' }),457 headers: { 'Content-Type': 'application/json' }458 }, (err, response, body) => {459 t.assert.ifError(err)460 t.assert.strictEqual(response.statusCode, 404)461 t.assert.strictEqual(body.toString(), 'this was not found 2')462 done()463 })464 })465 466 await t.test('unsupported route', (t, done) => {467 t.plan(3)468 sget({469 method: 'GET',470 url: getServerUrl(fastify) + '/test/notSupported'471 }, (err, response, body) => {472 t.assert.ifError(err)473 t.assert.strictEqual(response.statusCode, 404)474 t.assert.strictEqual(body.toString(), 'this was not found 2')475 done()476 })477 })478 479 await t.test('unsupported method 2', (t, done) => {480 t.plan(3)481 sget({482 method: 'PUT',483 url: getServerUrl(fastify) + '/test2',484 body: JSON.stringify({ hello: 'world' }),485 headers: { 'Content-Type': 'application/json' }486 }, (err, response, body) => {487 t.assert.ifError(err)488 t.assert.strictEqual(response.statusCode, 404)489 t.assert.strictEqual(body.toString(), 'this was not found 3')490 done()491 })492 })493 494 await t.test('framework-unsupported method 2', (t, done) => {495 t.plan(3)496 sget({497 method: 'PROPFIND',498 url: getServerUrl(fastify) + '/test2',499 body: JSON.stringify({ hello: 'world' }),500 headers: { 'Content-Type': 'application/json' }501 }, (err, response, body) => {502 t.assert.ifError(err)503 t.assert.strictEqual(response.statusCode, 404)504 t.assert.strictEqual(body.toString(), 'this was not found 3')505 done()506 })507 })508 509 await t.test('unsupported route 2', (t, done) => {510 t.plan(3)511 sget({512 method: 'GET',513 url: getServerUrl(fastify) + '/test2/notSupported'514 }, (err, response, body) => {515 t.assert.ifError(err)516 t.assert.strictEqual(response.statusCode, 404)517 t.assert.strictEqual(body.toString(), 'this was not found 3')518 done()519 })520 })521 522 await t.test('unsupported method 3', (t, done) => {523 t.plan(3)524 sget({525 method: 'PUT',526 url: getServerUrl(fastify) + '/test3/',527 body: JSON.stringify({ hello: 'world' }),528 headers: { 'Content-Type': 'application/json' }529 }, (err, response, body) => {530 t.assert.ifError(err)531 t.assert.strictEqual(response.statusCode, 404)532 t.assert.strictEqual(body.toString(), 'this was not found 4')533 done()534 })535 })536 537 await t.test('framework-unsupported method 3', (t, done) => {538 t.plan(3)539 sget({540 method: 'PROPFIND',541 url: getServerUrl(fastify) + '/test3/',542 body: JSON.stringify({ hello: 'world' }),543 headers: { 'Content-Type': 'application/json' }544 }, (err, response, body) => {545 t.assert.ifError(err)546 t.assert.strictEqual(response.statusCode, 404)547 t.assert.strictEqual(body.toString(), 'this was not found 4')548 done()549 })550 })551 552 await t.test('unsupported route 3', (t, done) => {553 t.plan(3)554 sget({555 method: 'GET',556 url: getServerUrl(fastify) + '/test3/notSupported'557 }, (err, response, body) => {558 t.assert.ifError(err)559 t.assert.strictEqual(response.statusCode, 404)560 t.assert.strictEqual(body.toString(), 'this was not found 4')561 done()562 })563 })564})565 566test('custom 404 hook and handler context', async t => {567 t.plan(19)568 569 const fastify = Fastify()570 571 fastify.decorate('foo', 42)572 573 fastify.addHook('onRequest', function (req, res, done) {574 t.assert.strictEqual(this.foo, 42)575 done()576 })577 fastify.addHook('preHandler', function (request, reply, done) {578 t.assert.strictEqual(this.foo, 42)579 done()580 })581 fastify.addHook('onSend', function (request, reply, payload, done) {582 t.assert.strictEqual(this.foo, 42)583 done()584 })585 fastify.addHook('onResponse', function (request, reply, done) {586 t.assert.strictEqual(this.foo, 42)587 done()588 })589 590 fastify.setNotFoundHandler(function (req, reply) {591 t.assert.strictEqual(this.foo, 42)592 reply.code(404).send('this was not found')593 })594 595 fastify.register(function (instance, opts, done) {596 instance.decorate('bar', 84)597 598 instance.addHook('onRequest', function (req, res, done) {599 t.assert.strictEqual(this.bar, 84)600 done()601 })602 instance.addHook('preHandler', function (request, reply, done) {603 t.assert.strictEqual(this.bar, 84)604 done()605 })606 instance.addHook('onSend', function (request, reply, payload, done) {607 t.assert.strictEqual(this.bar, 84)608 done()609 })610 instance.addHook('onResponse', function (request, reply, done) {611 t.assert.strictEqual(this.bar, 84)612 done()613 })614 615 instance.setNotFoundHandler(function (req, reply) {616 t.assert.strictEqual(this.foo, 42)617 t.assert.strictEqual(this.bar, 84)618 reply.code(404).send('encapsulated was not found')619 })620 621 done()622 }, { prefix: '/encapsulated' })623 624 {625 const res = await fastify.inject('/not-found')626 t.assert.strictEqual(res.statusCode, 404)627 t.assert.strictEqual(res.payload, 'this was not found')628 }629 630 {631 const res = await fastify.inject('/encapsulated/not-found')632 t.assert.strictEqual(res.statusCode, 404)633 t.assert.strictEqual(res.payload, 'encapsulated was not found')634 }635})636 637test('encapsulated custom 404 without - prefix hook and handler context', (t, done) => {638 t.plan(13)639 640 const fastify = Fastify()641 642 fastify.decorate('foo', 42)643 644 fastify.register(function (instance, opts, done) {645 instance.decorate('bar', 84)646 647 instance.addHook('onRequest', function (req, res, done) {648 t.assert.strictEqual(this.foo, 42)649 t.assert.strictEqual(this.bar, 84)650 done()651 })652 instance.addHook('preHandler', function (request, reply, done) {653 t.assert.strictEqual(this.foo, 42)654 t.assert.strictEqual(this.bar, 84)655 done()656 })657 instance.addHook('onSend', function (request, reply, payload, done) {658 t.assert.strictEqual(this.foo, 42)659 t.assert.strictEqual(this.bar, 84)660 done()661 })662 instance.addHook('onResponse', function (request, reply, done) {663 t.assert.strictEqual(this.foo, 42)664 t.assert.strictEqual(this.bar, 84)665 done()666 })667 668 instance.setNotFoundHandler(function (request, reply) {669 t.assert.strictEqual(this.foo, 42)670 t.assert.strictEqual(this.bar, 84)671 reply.code(404).send('custom not found')672 })673 674 done()675 })676 677 fastify.inject('/not-found', (err, res) => {678 t.assert.ifError(err)679 t.assert.strictEqual(res.statusCode, 404)680 t.assert.strictEqual(res.payload, 'custom not found')681 done()682 })683})684 685test('run hooks on default 404', (t, done) => {686 t.plan(7)687 688 const fastify = Fastify()689 690 fastify.addHook('onRequest', function (req, res, done) {691 t.assert.ok(true, 'onRequest called')692 done()693 })694 695 fastify.addHook('preHandler', function (request, reply, done) {696 t.assert.ok(true, 'preHandler called')697 done()698 })699 700 fastify.addHook('onSend', function (request, reply, payload, done) {701 t.assert.ok(true, 'onSend called')702 done()703 })704 705 fastify.addHook('onResponse', function (request, reply, done) {706 t.assert.ok(true, 'onResponse called')707 done()708 })709 710 fastify.get('/', function (req, reply) {711 reply.send({ hello: 'world' })712 })713 714 t.after(() => { fastify.close() })715 716 fastify.listen({ port: 0 }, err => {717 t.assert.ifError(err)718 719 sget({720 method: 'PUT',721 url: getServerUrl(fastify),722 body: JSON.stringify({ hello: 'world' }),723 headers: { 'Content-Type': 'application/json' }724 }, (err, response, body) => {725 t.assert.ifError(err)726 t.assert.strictEqual(response.statusCode, 404)727 done()728 })729 })730})731 732test('run non-encapsulated plugin hooks on default 404', (t, done) => {733 t.plan(6)734 735 const fastify = Fastify()736 737 fastify.register(fp(function (instance, options, done) {738 instance.addHook('onRequest', function (req, res, done) {739 t.assert.ok(true, 'onRequest called')740 done()741 })742 743 instance.addHook('preHandler', function (request, reply, done) {744 t.assert.ok(true, 'preHandler called')745 done()746 })747 748 instance.addHook('onSend', function (request, reply, payload, done) {749 t.assert.ok(true, 'onSend called')750 done()751 })752 753 instance.addHook('onResponse', function (request, reply, done) {754 t.assert.ok(true, 'onResponse called')755 done()756 })757 758 done()759 }))760 761 fastify.get('/', function (req, reply) {762 reply.send({ hello: 'world' })763 })764 765 fastify.inject({766 method: 'POST',767 url: '/',768 payload: { hello: 'world' }769 }, (err, res) => {770 t.assert.ifError(err)771 t.assert.strictEqual(res.statusCode, 404)772 done()773 })774})775 776test('run non-encapsulated plugin hooks on custom 404', (t, done) => {777 t.plan(11)778 779 const fastify = Fastify()780 781 const plugin = fp((instance, opts, done) => {782 instance.addHook('onRequest', function (req, res, done) {783 t.assert.ok(true, 'onRequest called')784 done()785 })786 787 instance.addHook('preHandler', function (request, reply, done) {788 t.assert.ok(true, 'preHandler called')789 done()790 })791 792 instance.addHook('onSend', function (request, reply, payload, done) {793 t.assert.ok(true, 'onSend called')794 done()795 })796 797 instance.addHook('onResponse', function (request, reply, done) {798 t.assert.ok(true, 'onResponse called')799 done()800 })801 802 done()803 })804 805 fastify.register(plugin)806 807 fastify.get('/', function (req, reply) {808 reply.send({ hello: 'world' })809 })810 811 fastify.setNotFoundHandler(function (req, reply) {812 reply.code(404).send('this was not found')813 })814 815 fastify.register(plugin) // Registering plugin after handler also works816 817 fastify.inject({ url: '/not-found' }, (err, res) => {818 t.assert.ifError(err)819 t.assert.strictEqual(res.statusCode, 404)820 t.assert.strictEqual(res.payload, 'this was not found')821 done()822 })823})824 825test('run hook with encapsulated 404', (t, done) => {826 t.plan(11)827 828 const fastify = Fastify()829 830 fastify.addHook('onRequest', function (req, res, done) {831 t.assert.ok(true, 'onRequest called')832 done()833 })834 835 fastify.addHook('preHandler', function (request, reply, done) {836 t.assert.ok(true, 'preHandler called')837 done()838 })839 840 fastify.addHook('onSend', function (request, reply, payload, done) {841 t.assert.ok(true, 'onSend called')842 done()843 })844 845 fastify.addHook('onResponse', function (request, reply, done) {846 t.assert.ok(true, 'onResponse called')847 done()848 })849 850 fastify.register(function (f, opts, done) {851 f.setNotFoundHandler(function (req, reply) {852 reply.code(404).send('this was not found 2')853 })854 855 f.addHook('onRequest', function (req, res, done) {856 t.assert.ok(true, 'onRequest 2 called')857 done()858 })859 860 f.addHook('preHandler', function (request, reply, done) {861 t.assert.ok(true, 'preHandler 2 called')862 done()863 })864 865 f.addHook('onSend', function (request, reply, payload, done) {866 t.assert.ok(true, 'onSend 2 called')867 done()868 })869 870 f.addHook('onResponse', function (request, reply, done) {871 t.assert.ok(true, 'onResponse 2 called')872 done()873 })874 875 done()876 }, { prefix: '/test' })877 878 t.after(() => { fastify.close() })879 880 fastify.listen({ port: 0 }, err => {881 t.assert.ifError(err)882 883 sget({884 method: 'PUT',885 url: getServerUrl(fastify) + '/test',886 body: JSON.stringify({ hello: 'world' }),887 headers: { 'Content-Type': 'application/json' }888 }, (err, response, body) => {889 t.assert.ifError(err)890 t.assert.strictEqual(response.statusCode, 404)891 done()892 })893 })894})895 896test('run hook with encapsulated 404 and framework-unsupported method', (t, done) => {897 t.plan(11)898 899 const fastify = Fastify()900 901 fastify.addHook('onRequest', function (req, res, done) {902 t.assert.ok(true, 'onRequest called')903 done()904 })905 906 fastify.addHook('preHandler', function (request, reply, done) {907 t.assert.ok(true, 'preHandler called')908 done()909 })910 911 fastify.addHook('onSend', function (request, reply, payload, done) {912 t.assert.ok(true, 'onSend called')913 done()914 })915 916 fastify.addHook('onResponse', function (request, reply, done) {917 t.assert.ok(true, 'onResponse called')918 done()919 })920 921 fastify.register(function (f, opts, done) {922 f.setNotFoundHandler(function (req, reply) {923 reply.code(404).send('this was not found 2')924 })925 926 f.addHook('onRequest', function (req, res, done) {927 t.assert.ok(true, 'onRequest 2 called')928 done()929 })930 931 f.addHook('preHandler', function (request, reply, done) {932 t.assert.ok(true, 'preHandler 2 called')933 done()934 })935 936 f.addHook('onSend', function (request, reply, payload, done) {937 t.assert.ok(true, 'onSend 2 called')938 done()939 })940 941 f.addHook('onResponse', function (request, reply, done) {942 t.assert.ok(true, 'onResponse 2 called')943 done()944 })945 946 done()947 }, { prefix: '/test' })948 949 t.after(() => { fastify.close() })950 951 fastify.listen({ port: 0 }, err => {952 t.assert.ifError(err)953 954 sget({955 method: 'PROPFIND',956 url: getServerUrl(fastify) + '/test',957 body: JSON.stringify({ hello: 'world' }),958 headers: { 'Content-Type': 'application/json' }959 }, (err, response, body) => {960 t.assert.ifError(err)961 t.assert.strictEqual(response.statusCode, 404)962 done()963 })964 })965})966 967test('hooks check 404', (t, done) => {968 t.plan(13)969 970 const fastify = Fastify()971 972 fastify.get('/', function (req, reply) {973 reply.send({ hello: 'world' })974 })975 976 fastify.addHook('onSend', (req, reply, payload, done) => {977 t.assert.deepStrictEqual(req.query, { foo: 'asd' })978 t.assert.ok(true, 'called onSend')979 done()980 })981 fastify.addHook('onRequest', (req, res, done) => {982 t.assert.ok(true, 'called onRequest')983 done()984 })985 fastify.addHook('onResponse', (request, reply, done) => {986 t.assert.ok(true, 'calledonResponse')987 done()988 })989 990 t.after(() => { fastify.close() })991 992 fastify.listen({ port: 0 }, err => {993 t.assert.ifError(err)994 995 sget({996 method: 'PUT',997 url: getServerUrl(fastify) + '?foo=asd',998 body: JSON.stringify({ hello: 'world' }),999 headers: { 'Content-Type': 'application/json' }1000 }, (err, response, body) => {1001 t.assert.ifError(err)1002 t.assert.strictEqual(response.statusCode, 404)1003 })1004 1005 sget({1006 method: 'GET',1007 url: getServerUrl(fastify) + '/notSupported?foo=asd'1008 }, (err, response, body) => {1009 t.assert.ifError(err)1010 t.assert.strictEqual(response.statusCode, 404)1011 done()1012 })1013 })1014})1015 1016test('setNotFoundHandler should not suppress duplicated routes checking', t => {1017 t.plan(1)1018 1019 const fastify = Fastify()1020 1021 try {1022 fastify.get('/', function (req, reply) {1023 reply.send({ hello: 'world' })1024 })1025 fastify.get('/', function (req, reply) {1026 reply.send({ hello: 'world' })1027 })1028 fastify.setNotFoundHandler(function (req, reply) {1029 reply.code(404).send('this was not found')1030 })1031 1032 t.assert.fail('setNotFoundHandler should not interfere duplicated route error')1033 } catch (error) {1034 t.assert.ok(error)1035 }1036})1037 1038test('log debug for 404', async t => {1039 t.plan(1)1040 1041 const Writable = require('node:stream').Writable1042 1043 const logStream = new Writable()1044 logStream.logs = []1045 logStream._write = function (chunk, encoding, callback) {1046 this.logs.push(chunk.toString())1047 callback()1048 }1049 1050 const fastify = Fastify({1051 logger: {1052 level: 'trace',1053 stream: logStream1054 }1055 })1056 1057 fastify.get('/', function (req, reply) {1058 reply.send({ hello: 'world' })1059 })1060 1061 t.after(() => { fastify.close() })1062 1063 await t.test('log debug', (t, done) => {1064 t.plan(7)1065 fastify.inject({1066 method: 'GET',1067 url: '/not-found'1068 }, (err, response) => {1069 t.assert.ifError(err)1070 t.assert.strictEqual(response.statusCode, 404)1071 1072 const INFO_LEVEL = 301073 t.assert.strictEqual(JSON.parse(logStream.logs[0]).msg, 'incoming request')1074 t.assert.strictEqual(JSON.parse(logStream.logs[1]).msg, 'Route GET:/not-found not found')1075 t.assert.strictEqual(JSON.parse(logStream.logs[1]).level, INFO_LEVEL)1076 t.assert.strictEqual(JSON.parse(logStream.logs[2]).msg, 'request completed')1077 t.assert.strictEqual(logStream.logs.length, 3)1078 done()1079 })1080 })1081})1082 1083test('Unknown method', (t, done) => {1084 t.plan(5)1085 1086 const fastify = Fastify()1087 1088 fastify.get('/', function (req, reply) {1089 reply.send({ hello: 'world' })1090 })1091 1092 t.after(() => { fastify.close() })1093 1094 fastify.listen({ port: 0 }, err => {1095 t.assert.ifError(err)1096 1097 const handler = () => {}1098 // See https://github.com/fastify/light-my-request/pull/201099 t.assert.throws(() => fastify.inject({1100 method: 'UNKNOWN_METHOD',1101 url: '/'1102 }, handler), Error)1103 1104 sget({1105 method: 'UNKNOWN_METHOD',1106 url: getServerUrl(fastify)1107 }, (err, response, body) => {1108 t.assert.ifError(err)1109 t.assert.strictEqual(response.statusCode, 400)1110 t.assert.deepStrictEqual(JSON.parse(body), {1111 error: 'Bad Request',1112 message: 'Client Error',1113 statusCode: 4001114 })1115 done()1116 })1117 })1118})1119 1120test('recognizes errors from the http-errors module', (t, done) => {1121 t.plan(5)1122 1123 const fastify = Fastify()1124 1125 fastify.get('/', function (req, reply) {1126 reply.send(new errors.NotFound())1127 })1128 1129 t.after(() => { fastify.close() })1130 1131 fastify.listen({ port: 0 }, err => {1132 t.assert.ifError(err)1133 1134 fastify.inject({1135 method: 'GET',1136 url: '/'1137 }, (err, res) => {1138 t.assert.ifError(err)1139 t.assert.strictEqual(res.statusCode, 404)1140 1141 sget(getServerUrl(fastify), (err, response, body) => {1142 t.assert.ifError(err)1143 const obj = JSON.parse(body.toString())1144 t.assert.deepStrictEqual(obj, {1145 error: 'Not Found',1146 message: 'Not Found',1147 statusCode: 4041148 })1149 done()1150 })1151 })1152 })1153})1154 1155test('the default 404 handler can be invoked inside a prefixed plugin', (t, done) => {1156 t.plan(3)1157 1158 const fastify = Fastify()1159 1160 fastify.register(function (instance, opts, done) {1161 instance.get('/path', function (request, reply) {1162 reply.send(new errors.NotFound())1163 })1164 1165 done()1166 }, { prefix: '/v1' })1167 1168 fastify.inject('/v1/path', (err, res) => {1169 t.assert.ifError(err)1170 t.assert.strictEqual(res.statusCode, 404)1171 t.assert.deepStrictEqual(JSON.parse(res.payload), {1172 error: 'Not Found',1173 message: 'Not Found',1174 statusCode: 4041175 })1176 done()1177 })1178})1179 1180test('an inherited custom 404 handler can be invoked inside a prefixed plugin', (t, done) => {1181 t.plan(3)1182 1183 const fastify = Fastify()1184 1185 fastify.setNotFoundHandler(function (request, reply) {1186 reply.code(404).send('custom handler')1187 })1188 1189 fastify.register(function (instance, opts, done) {1190 instance.get('/path', function (request, reply) {1191 reply.send(new errors.NotFound())1192 })1193 1194 done()1195 }, { prefix: '/v1' })1196 1197 fastify.inject('/v1/path', (err, res) => {1198 t.assert.ifError(err)1199 t.assert.strictEqual(res.statusCode, 404)1200 t.assert.deepStrictEqual(JSON.parse(res.payload), {