Skip to content

Commit

Permalink
improve DecoratorHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
Uzlopak committed Apr 10, 2024
1 parent fe44b9b commit f6f072f
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 8 deletions.
37 changes: 29 additions & 8 deletions lib/handler/decorator-handler.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,56 @@
'use strict'

module.exports = class DecoratorHandler {
#handler = {
onConnect: function () {},
onError: function () {},
onUpgrade: function () {},
onResponseStarted: function () {},
onHeaders: function () {},
onData: function () {},
onComplete: function () {},
onBodySent: function () {}
}

constructor (handler) {
this.handler = handler
if (typeof handler !== 'object' || handler === null) {
throw new TypeError('handler must be an object')
}
this.#handler = {
...this.#handler,
...handler
}
}

onConnect (...args) {
return this.handler.onConnect(...args)
return this.#handler.onConnect(...args)
}

onError (...args) {
return this.handler.onError(...args)
return this.#handler.onError(...args)
}

onUpgrade (...args) {
return this.handler.onUpgrade(...args)
return this.#handler.onUpgrade(...args)
}

onResponseStarted (...args) {
return this.#handler.onResponseStarted(...args)
}

onHeaders (...args) {
return this.handler.onHeaders(...args)
return this.#handler.onHeaders(...args)
}

onData (...args) {
return this.handler.onData(...args)
return this.#handler.onData(...args)
}

onComplete (...args) {
return this.handler.onComplete(...args)
return this.#handler.onComplete(...args)
}

onBodySent (...args) {
return this.handler.onBodySent(...args)
return this.#handler.onBodySent(...args)
}
}
74 changes: 74 additions & 0 deletions test/decorator-handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
'use strict'

const { tspl } = require('@matteo.collina/tspl')
const { describe, test } = require('node:test')
const DecoratorHandler = require('../lib/handler/decorator-handler')

const methods = [
'onConnect',
'onError',
'onUpgrade',
'onHeaders',
'onResponseStarted',
'onData',
'onComplete',
'onBodySent'
]

describe('DecoratorHandler', () => {
test('should throw if provided handler is not an object', (t) => {
t = tspl(t, { plan: 4 })
t.throws(() => new DecoratorHandler(null), new TypeError('handler must be an object'))
t.throws(() => new DecoratorHandler('string'), new TypeError('handler must be an object'))

t.throws(() => new DecoratorHandler(null), new TypeError('handler must be an object'))
t.throws(() => new DecoratorHandler('string'), new TypeError('handler must be an object'))
})

test('should not expose the handler', (t) => {
t = tspl(t, { plan: 1 })
const handler = {}
const decorator = new DecoratorHandler(handler)
t.strictEqual(Object.keys(decorator).length, 0)
})

methods.forEach((method) => {
test(`should have delegate ${method} method`, (t) => {
t = tspl(t, { plan: 1 })
const decorator = new DecoratorHandler({})
t.equal(typeof decorator[method], 'function')
})

test(`should delegate ${method}`, (t) => {
t = tspl(t, { plan: 1 })
const handler = { [method]: () => method }
const decorator = new DecoratorHandler(handler)
t.equal(decorator[method](), method)
})

test(`should delegate ${method} with arguments`, (t) => {
t = tspl(t, { plan: 1 })
const handler = { [method]: (...args) => args }
const decorator = new DecoratorHandler(handler)
t.deepStrictEqual(decorator[method](1, 2, 3), [1, 2, 3])
})

test(`can be extended and should delegate ${method}`, (t) => {
t = tspl(t, { plan: 1 })

class ExtendedHandler extends DecoratorHandler {
[method] () {
return method
}
}
const decorator = new ExtendedHandler({})
t.equal(decorator[method](), method)
})

test('should not throw if method was not set in the handlerObject', (t) => {
t = tspl(t, { plan: 1 })
const decorator = new DecoratorHandler({})
t.equal(decorator[method](), undefined)
})
})
})

0 comments on commit f6f072f

Please sign in to comment.