{"action":"closed","issue":{"url":"https://api.github.com/repos/hapijs/discuss/issues/155","repository_url":"https://api.github.com/repos/hapijs/discuss","labels_url":"https://api.github.com/repos/hapijs/discuss/issues/155/labels{/name}","comments_url":"https://api.github.com/repos/hapijs/discuss/issues/155/comments","events_url":"https://api.github.com/repos/hapijs/discuss/issues/155/events","html_url":"https://github.com/hapijs/discuss/issues/155","id":105004472,"number":155,"title":"server.inject error handling with promises surfaces problems with any method besides GET","user":{"login":"nackjicholson","id":365247,"avatar_url":"https://avatars.githubusercontent.com/u/365247?v=3","gravatar_id":"","url":"https://api.github.com/users/nackjicholson","html_url":"https://github.com/nackjicholson","followers_url":"https://api.github.com/users/nackjicholson/followers","following_url":"https://api.github.com/users/nackjicholson/following{/other_user}","gists_url":"https://api.github.com/users/nackjicholson/gists{/gist_id}","starred_url":"https://api.github.com/users/nackjicholson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nackjicholson/subscriptions","organizations_url":"https://api.github.com/users/nackjicholson/orgs","repos_url":"https://api.github.com/users/nackjicholson/repos","events_url":"https://api.github.com/users/nackjicholson/events{/privacy}","received_events_url":"https://api.github.com/users/nackjicholson/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":2,"created_at":"2015-09-05T05:10:05Z","updated_at":"2016-10-05T16:07:36Z","closed_at":"2016-10-05T16:07:36Z","body":"My hapijs 9+ server seems to work just fine when running normally. But during testing I ran into some strange behavior when using promises and `server.inject`\r\n\r\nI have two very similar routes a GET and DELETE. The tests for get work properly, the tests for delete also pass, but `bluebird` reports an `Unhandled rejection`.\r\n\r\n### Abbreviated version\r\n\r\nTwo identical routes, differ in `method` only. One is `GET` one is `DELETE`.\r\n\r\nI verified the same happens for any method other than `GET`\r\n\r\nTests pass, but an `Unhandled Rejection` notice appears for the `DELETE` route.\r\n\r\ncode:\r\n\r\n```javascript\r\n  // Handler for DELETE /{id}\r\n  function handler(request, reply) {\r\n      elasticsearch\r\n        .delete({\r\n          index: 'calculations-001',\r\n          type: 'calculation',\r\n          id: request.params.id\r\n        })\r\n        .then(reply)\r\n        .catch((err) => {\r\n          reply(Boom.wrap(err, err.status));\r\n        });\r\n    }\r\n```\r\n\r\ntest:\r\n\r\n```javascript\r\n    it('should reply with 404 if document already deleted', (done) => {\r\n      const request = { method: 'DELETE', url: '/42' };\r\n      let err = new Error('Not found');\r\n      err.status = 404;\r\n\r\n      elasticsearch.delete.returns(Bluebird.reject(err));\r\n\r\n      server.inject(request, (res) => {\r\n        const actual = res.result;\r\n        const expected = Boom.wrap(err, err.status).output.payload;\r\n        assert.equal(actual, expected, 'responds with boom not found response');\r\n        done();\r\n      });\r\n    });\r\n```\r\n\r\nmocha output:\r\n\r\n```txt\r\n    Destroy DELETE /{id}\r\nUnhandled rejection Error: Not found\r\n      ✓ should reply with 404 if document already deleted\r\n```\r\n\r\n\r\n### FULL CONTENT\r\n\r\nI have my api routes encapsulated by a plugin.\r\n\r\n**lib/api/index.js**\r\n```javascript\r\nimport requireDir from 'require-dir';\r\nimport {Client as ElasticSearchClient} from 'elasticsearch';\r\nconst calculations = requireDir('./calculations');\r\n\r\n/**\r\n * Calculation Service API Plugin\r\n *\r\n * Handles the bootstrapping of anything necessary for this service.\r\n *\r\n * @param server\r\n * @param {object} options\r\n * @param next\r\n */\r\nfunction register(server, { elasticsearchHost }, next) {\r\n  const elasticsearch = new ElasticSearchClient({\r\n    host: elasticsearchHost,\r\n    sniffOnStart: true\r\n  });\r\n\r\n  server.route([\r\n    calculations.destroy(elasticsearch),\r\n    calculations.show(elasticsearch),\r\n  ]);\r\n\r\n  next();\r\n}\r\n\r\nregister.attributes = {\r\n  name: 'api',\r\n  version: '1.0.0'\r\n};\r\n\r\nexport default register;\r\n\r\n```\r\n\r\n**lib/api/calculations/show.js**\r\n```javascript\r\nimport Boom from 'boom';\r\nimport Joi from 'joi';\r\n\r\nfunction show(elasticsearch) {\r\n  return {\r\n    method: 'GET',\r\n    path: '/{id}',\r\n    handler(request, reply) {\r\n      elasticsearch\r\n        .get({\r\n          index: 'calculations-001',\r\n          type: 'calculation',\r\n          id: request.params.id\r\n        })\r\n        .then(reply)\r\n        .catch((err) => {\r\n          reply(Boom.wrap(err, err.status));\r\n        });\r\n    },\r\n    config: {\r\n      description: 'Show resource route for calculation data.',\r\n      tags: ['api'],\r\n      validate: {\r\n        params: {\r\n          id: Joi.string()\r\n        }\r\n      }\r\n    }\r\n  };\r\n}\r\n\r\nexport default show;\r\n\r\n```\r\n\r\n**lib/api/calculations/destroy.js**\r\n```javascript\r\nimport Boom from 'boom';\r\nimport Joi from 'joi';\r\n\r\nfunction destroy(elasticsearch) {\r\n  return {\r\n    method: 'DELETE',\r\n    path: '/{id}',\r\n    handler(request, reply) {\r\n      elasticsearch\r\n        .delete({\r\n          index: 'calculations-001',\r\n          type: 'calculation',\r\n          id: request.params.id\r\n        })\r\n        .then(reply)\r\n        .catch((err) => {\r\n          reply(Boom.wrap(err, err.status));\r\n        });\r\n    },\r\n    config: {\r\n      description: 'Destroy resource route for calculation data.',\r\n      tags: ['api'],\r\n      validate: {\r\n        params: {\r\n          id: Joi.string()\r\n        }\r\n      }\r\n    }\r\n  };\r\n}\r\n\r\nexport default destroy;\r\n\r\n```\r\n\r\nAnd the plugin test **test/lib/api/index.js**\r\n```javascript\r\nimport assert from 'assert';\r\nimport Boom from 'boom';\r\nimport proxyquire from 'proxyquire';\r\nimport Bluebird from 'bluebird';\r\nimport sinon from 'sinon';\r\nimport {Server} from 'hapi';\r\n\r\ndescribe('lib/api', () => {\r\n  let server;\r\n  let elasticsearch;\r\n\r\n  beforeEach(() => {\r\n    elasticsearch = {\r\n      get: sinon.stub(),\r\n      delete: sinon.stub()\r\n    };\r\n\r\n    server = new Server();\r\n    server.connection();\r\n\r\n    const api = proxyquire('../../../lib/api', {\r\n      elasticsearch: { Client: sinon.stub().returns(elasticsearch)}\r\n    });\r\n\r\n    server.register(api, err => err);\r\n  });\r\n\r\n\r\n  describe('Show GET /{id}', () => {\r\n    it('should return calculation document', (done) => {\r\n      const calcObj = { foo: 'bar' };\r\n\r\n      elasticsearch.get.returns(Bluebird.resolve(calcObj));\r\n\r\n      server.inject('/42', (res) => {\r\n        const actual = res.result;\r\n        assert.equal(actual, calcObj, 'calc returned when found');\r\n        done();\r\n      });\r\n    });\r\n\r\n    it('should reply with 404 when calculation document not found', (done) => {\r\n      let err = new Error('Not found');\r\n      err.status = 404;\r\n\r\n      elasticsearch.get.returns(Bluebird.reject(err));\r\n\r\n      server.inject('/42', (res) => {\r\n        const actual = res.result;\r\n        const expected = Boom.wrap(err, err.status).output.payload;\r\n        assert.equal(actual, expected, 'responds with boom not found response');\r\n        done();\r\n      });\r\n    });\r\n  });\r\n\r\n  describe('Destroy DELETE /{id}', () => {\r\n    it('should delete a calculation document', (done) => {\r\n      const request = { method: 'DELETE', url: '/42' };\r\n      const deleteRes = { foo: 'bar' };\r\n\r\n      elasticsearch.delete.returns(Bluebird.resolve(deleteRes));\r\n\r\n      server.inject(request, (res) => {\r\n        const actual = res.result;\r\n        assert.equal(actual, deleteRes, 'successful delete response');\r\n        done();\r\n      });\r\n    });\r\n\r\n    it('should reply with 404 if document already deleted', (done) => {\r\n      const request = { method: 'DELETE', url: '/42' };\r\n      let err = new Error('Not found');\r\n      err.status = 404;\r\n\r\n      elasticsearch.delete.returns(Bluebird.reject(err));\r\n\r\n      server.inject(request, (res) => {\r\n        const actual = res.result;\r\n        const expected = Boom.wrap(err, err.status).output.payload;\r\n        assert.equal(actual, expected, 'responds with boom not found response');\r\n        done();\r\n      });\r\n    });\r\n  });\r\n});\r\n\r\n```\r\n\r\n**final test output**\r\n\r\n```txt\r\n  lib/api\r\n    Show GET /{id}\r\n      ✓ should return calculation document\r\n      ✓ should reply with 404 when calculation document not found\r\n    Destroy DELETE /{id}\r\n      ✓ should delete a calculation document\r\nUnhandled rejection Error: Not found\r\n    at Context.<anonymous> (/Users/nackjicholson/repos/calculations-storage-service/es6/test/lib/api/index.js:73:17)\r\n    at callFnAsync (/Users/nackjicholson/repos/calculations-storage-service/node_modules/mocha/lib/runnable.js:309:8)\r\n    at Test.Runnable.run (/Users/nackjicholson/repos/calculations-storage-service/node_modules/mocha/lib/runnable.js:264:7)\r\n    at Runner.runTest (/Users/nackjicholson/repos/calculations-storage-service/node_modules/mocha/lib/runner.js:419:10)\r\n    at /Users/nackjicholson/repos/calculations-storage-service/node_modules/mocha/lib/runner.js:526:12\r\n    at next (/Users/nackjicholson/repos/calculations-storage-service/node_modules/mocha/lib/runner.js:340:14)\r\n    at /Users/nackjicholson/repos/calculations-storage-service/node_modules/mocha/lib/runner.js:350:7\r\n    at next (/Users/nackjicholson/repos/calculations-storage-service/node_modules/mocha/lib/runner.js:283:14)\r\n    at Immediate._onImmediate (/Users/nackjicholson/repos/calculations-storage-service/node_modules/mocha/lib/runner.js:318:5)\r\n    at processImmediate [as _immediateCallback] (timers.js:371:17)\r\n      ✓ should reply with 404 if document already deleted\r\n\r\n\r\n  4 passing (334ms)\r\n```"}}
{"actor":{"display_login":"nackjicholson"}}