diff --git a/lib/index.js b/lib/index.js index 709b754..df080d9 100755 --- a/lib/index.js +++ b/lib/index.js @@ -71,6 +71,19 @@ exports.Boom = class extends Error { constructor(messageOrError, options = {}) { if (messageOrError instanceof Error) { + // Handle DOMException which has getters that require correct 'this' context + if (messageOrError.constructor.name === 'DOMException') { + // Extract message and name before cloning since Hoek.clone() creates a copy + // that loses the internal structure needed for DOMException getters to work + const message = messageOrError.message; + const name = messageOrError.name; + + // Create a new regular Error instead of cloning the DOMException + const newError = new Error(message); + newError.name = name; + return exports.boomify(newError, options); + } + return exports.boomify(Hoek.clone(messageOrError), options); } diff --git a/test/index.js b/test/index.js index 8c7c5a7..b808233 100755 --- a/test/index.js +++ b/test/index.js @@ -123,6 +123,31 @@ describe('Boom', () => { expect(err.output.payload.error).to.equal('Unknown'); }); + it('handles DOMException from fetch abort', async () => { + + // Create a DOMException from fetch abort + const controller = new AbortController(); + controller.abort(); + + let fetchDOMException; + try { + await fetch('https://example.com', { signal: controller.signal }); + } + catch (err) { + fetchDOMException = err; + } + + expect(fetchDOMException).to.be.instanceof(DOMException); + expect(fetchDOMException.name).to.equal('AbortError'); + + const err = new Boom.Boom(fetchDOMException, { statusCode: 400 }); + + expect(err.isBoom).to.be.true(); + expect(err.output.statusCode).to.equal(400); + expect(err.message).to.equal('This operation was aborted'); + expect(err.name).to.equal('AbortError'); + }); + describe('instanceof', () => { it('identifies a boom object', () => { @@ -926,6 +951,36 @@ describe('Boom', () => { } }); }); + + it('handles DOMException without throwing', () => { + + const domException = new DOMException('Test message', 'TestError'); + const err = Boom.badImplementation(domException); + + expect(err.isDeveloperError).to.equal(true); + expect(err.isServer).to.be.true(); + expect(err.output.statusCode).to.equal(500); + expect(err.message).to.equal('Test message'); + expect(err.name).to.equal('TestError'); + expect(err.output.payload.error).to.equal('Internal Server Error'); + expect(err.output.payload.message).to.equal('An internal server error occurred'); + }); + + it('handles DOMException with custom message and name', () => { + + const domException = new DOMException('Custom error message', 'CustomError'); + const err = Boom.badImplementation(domException); + + expect(err.isDeveloperError).to.equal(true); + expect(err.isServer).to.be.true(); + expect(err.output.statusCode).to.equal(500); + expect(err.message).to.equal('Custom error message'); + expect(err.name).to.equal('CustomError'); + expect(err.output.payload.error).to.equal('Internal Server Error'); + expect(err.output.payload.message).to.equal('An internal server error occurred'); + }); + + }); describe('stack trace', () => {