CoolFace
Apppublic

strong-tie/inbound-calls

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
encapsulated-error-handler.test.js238 linesDownload Raw Back to test
1'use strict'2 3const { test } = require('node:test')4const Fastify = require('..')5 6// Because of how error handlers wrap things, following the control flow can be tricky7// In this test file numbered comments indicate the order statements are expected to execute8 9test('encapsulates an asynchronous error handler', async t => {10  t.plan(3)11 12  const fastify = Fastify()13  fastify.register(async function (fastify) {14    fastify.setErrorHandler(async function a (err) {15      // 3. the inner error handler catches the error, and throws a new error16      t.assert.strictEqual(err.message, 'from_endpoint')17      throw new Error('from_inner')18    })19    fastify.get('/encapsulated', async () => {20      // 2. the endpoint throws an error21      throw new Error('from_endpoint')22    })23  })24 25  fastify.setErrorHandler(async function b (err) {26    // 4. the outer error handler catches the error thrown by the inner error handler27    t.assert.strictEqual(err.message, 'from_inner')28    // 5. the outer error handler throws a new error29    throw new Error('from_outer')30  })31 32  // 1. the endpoint is called33  const res = await fastify.inject('/encapsulated')34  // 6. the default error handler returns the error from the outer error handler35  t.assert.strictEqual(res.json().message, 'from_outer')36})37 38// See discussion in https://github.com/fastify/fastify/pull/5222#discussion_r143257365539test('encapsulates a synchronous error handler', async t => {40  t.plan(3)41 42  const fastify = Fastify()43  fastify.register(async function (fastify) {44    fastify.setErrorHandler(function a (err) {45      // 3. the inner error handler catches the error, and throws a new error46      t.assert.strictEqual(err.message, 'from_endpoint')47      throw new Error('from_inner')48    })49    fastify.get('/encapsulated', async () => {50      // 2. the endpoint throws an error51      throw new Error('from_endpoint')52    })53  })54 55  fastify.setErrorHandler(async function b (err) {56    // 4. the outer error handler catches the error thrown by the inner error handler57    t.assert.strictEqual(err.message, 'from_inner')58    // 5. the outer error handler throws a new error59    throw new Error('from_outer')60  })61 62  // 1. the endpoint is called63  const res = await fastify.inject('/encapsulated')64  // 6. the default error handler returns the error from the outer error handler65  t.assert.strictEqual(res.json().message, 'from_outer')66})67 68test('onError hook nested', async t => {69  t.plan(4)70 71  const fastify = Fastify()72  fastify.register(async function (fastify) {73    fastify.setErrorHandler(async function a (err) {74      // 4. the inner error handler catches the error, and throws a new error75      t.assert.strictEqual(err.message, 'from_endpoint')76      throw new Error('from_inner')77    })78    fastify.get('/encapsulated', async () => {79      // 2. the endpoint throws an error80      throw new Error('from_endpoint')81    })82  })83 84  fastify.setErrorHandler(async function b (err) {85    // 5. the outer error handler catches the error thrown by the inner error handler86    t.assert.strictEqual(err.message, 'from_inner')87    // 6. the outer error handler throws a new error88    throw new Error('from_outer')89  })90 91  fastify.addHook('onError', async function (request, reply, err) {92    // 3. the hook receives the error93    t.assert.strictEqual(err.message, 'from_endpoint')94  })95 96  // 1. the endpoint is called97  const res = await fastify.inject('/encapsulated')98  // 7. the default error handler returns the error from the outer error handler99  t.assert.strictEqual(res.json().message, 'from_outer')100})101 102// See https://github.com/fastify/fastify/issues/5220103test('encapuslates an error handler, for errors thrown in hooks', async t => {104  t.plan(3)105 106  const fastify = Fastify()107  fastify.register(async function (fastify) {108    fastify.setErrorHandler(function a (err) {109      // 3. the inner error handler catches the error, and throws a new error110      t.assert.strictEqual(err.message, 'from_hook')111      throw new Error('from_inner')112    })113    fastify.addHook('onRequest', async () => {114      // 2. the hook throws an error115      throw new Error('from_hook')116    })117    fastify.get('/encapsulated', async () => {})118  })119 120  fastify.setErrorHandler(function b (err) {121    // 4. the outer error handler catches the error thrown by the inner error handler122    t.assert.strictEqual(err.message, 'from_inner')123    // 5. the outer error handler throws a new error124    throw new Error('from_outer')125  })126 127  // 1. the endpoint is called128  const res = await fastify.inject('/encapsulated')129  // 6. the default error handler returns the error from the outer error handler130  t.assert.strictEqual(res.json().message, 'from_outer')131})132 133// See https://github.com/fastify/fastify/issues/5220134test('encapuslates many synchronous error handlers that rethrow errors', async t => {135  const DEPTH = 100136  t.plan(DEPTH + 2)137 138  /**139   * This creates a very nested set of error handlers, that looks like:140   * plugin141   * - error handler142   * - plugin143   *   - error handler144   *   - plugin145   *     ... {to DEPTH levels}146   *       - plugin147   *           - error handler148   *           - GET /encapsulated149   */150  const createNestedRoutes = (fastify, depth) => {151    if (depth < 0) {152      throw new Error('Expected depth >= 0')153    } else if (depth === 0) {154      fastify.setErrorHandler(function a (err) {155        // 3. innermost error handler catches the error, and throws a new error156        t.assert.strictEqual(err.message, 'from_route')157        throw new Error(`from_handler_${depth}`)158      })159      fastify.get('/encapsulated', async () => {160        // 2. the endpoint throws an error161        throw new Error('from_route')162      })163    } else {164      fastify.setErrorHandler(function d (err) {165        // 4 to {DEPTH+4}. error handlers each catch errors, and then throws a new error166        t.assert.strictEqual(err.message, `from_handler_${depth - 1}`)167        throw new Error(`from_handler_${depth}`)168      })169 170      fastify.register(async function (fastify) {171        createNestedRoutes(fastify, depth - 1)172      })173    }174  }175 176  const fastify = Fastify()177  createNestedRoutes(fastify, DEPTH)178 179  // 1. the endpoint is called180  const res = await fastify.inject('/encapsulated')181  // {DEPTH+5}. the default error handler returns the error from the outermost error handler182  t.assert.strictEqual(res.json().message, `from_handler_${DEPTH}`)183})184 185// See https://github.com/fastify/fastify/issues/5220186// This was not failing previously, but we want to make sure the behavior continues to work in the same way across async and sync handlers187// Plus, the current setup is somewhat fragile to tweaks to wrapThenable as that's what retries (by calling res.send(err) again)188test('encapuslates many asynchronous error handlers that rethrow errors', async t => {189  const DEPTH = 100190  t.plan(DEPTH + 2)191 192  /**193   * This creates a very nested set of error handlers, that looks like:194   * plugin195   * - error handler196   * - plugin197   *   - error handler198   *   - plugin199   *     ... {to DEPTH levels}200   *       - plugin201   *           - error handler202   *           - GET /encapsulated203   */204  const createNestedRoutes = (fastify, depth) => {205    if (depth < 0) {206      throw new Error('Expected depth >= 0')207    } else if (depth === 0) {208      fastify.setErrorHandler(async function a (err) {209        // 3. innermost error handler catches the error, and throws a new error210        t.assert.strictEqual(err.message, 'from_route')211        throw new Error(`from_handler_${depth}`)212      })213      fastify.get('/encapsulated', async () => {214        // 2. the endpoint throws an error215        throw new Error('from_route')216      })217    } else {218      fastify.setErrorHandler(async function m (err) {219        // 4 to {DEPTH+4}. error handlers each catch errors, and then throws a new error220        t.assert.strictEqual(err.message, `from_handler_${depth - 1}`)221        throw new Error(`from_handler_${depth}`)222      })223 224      fastify.register(async function (fastify) {225        createNestedRoutes(fastify, depth - 1)226      })227    }228  }229 230  const fastify = Fastify()231  createNestedRoutes(fastify, DEPTH)232 233  // 1. the endpoint is called234  const res = await fastify.inject('/encapsulated')235  // {DEPTH+5}. the default error handler returns the error from the outermost error handler236  t.assert.strictEqual(res.json().message, `from_handler_${DEPTH}`)237})238