Skip to content

Commit

Permalink
feat(BatchInterceptor): map "once", "off", and "removeAllListeners" m…
Browse files Browse the repository at this point in the history
…ethods
  • Loading branch information
kettanaito committed Sep 18, 2023
1 parent a32813a commit 6aa2c8b
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 13 deletions.
132 changes: 132 additions & 0 deletions src/BatchInterceptor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,135 @@ it('disposes of child interceptors', async () => {
expect(primaryDisposeSpy).toHaveBeenCalledTimes(1)
expect(secondaryDisposeSpy).toHaveBeenCalledTimes(1)
})

it('forwards listeners added via "on()"', () => {
class FirstInterceptor extends Interceptor<any> {
constructor() {
super(Symbol('first'))
}
}
class SecondaryInterceptor extends Interceptor<any> {
constructor() {
super(Symbol('second'))
}
}

const firstInterceptor = new FirstInterceptor()
const secondInterceptor = new SecondaryInterceptor()

const interceptor = new BatchInterceptor({
name: 'batch',
interceptors: [firstInterceptor, secondInterceptor],
})

const listener = vi.fn()
interceptor.on('foo', listener)

expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(1)
expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(1)
expect(interceptor['emitter'].listenerCount('foo')).toBe(0)
})

it('forwards listeners removal via "off()"', () => {
class FirstInterceptor extends Interceptor<any> {
constructor() {
super(Symbol('first'))
}
}
class SecondaryInterceptor extends Interceptor<any> {
constructor() {
super(Symbol('second'))
}
}

const firstInterceptor = new FirstInterceptor()
const secondInterceptor = new SecondaryInterceptor()

const interceptor = new BatchInterceptor({
name: 'batch',
interceptors: [firstInterceptor, secondInterceptor],
})

const listener = vi.fn()
interceptor.on('foo', listener)
interceptor.off('foo', listener)

expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(0)
expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(0)
})

it('forwards removal of all listeners by name via ".removeAllListeners()"', () => {
class FirstInterceptor extends Interceptor<any> {
constructor() {
super(Symbol('first'))
}
}
class SecondaryInterceptor extends Interceptor<any> {
constructor() {
super(Symbol('second'))
}
}

const firstInterceptor = new FirstInterceptor()
const secondInterceptor = new SecondaryInterceptor()

const interceptor = new BatchInterceptor({
name: 'batch',
interceptors: [firstInterceptor, secondInterceptor],
})

const listener = vi.fn()
interceptor.on('foo', listener)
interceptor.on('foo', listener)
interceptor.on('bar', listener)

expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(2)
expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(2)
expect(firstInterceptor['emitter'].listenerCount('bar')).toBe(1)
expect(secondInterceptor['emitter'].listenerCount('bar')).toBe(1)

interceptor.removeAllListeners('foo')

expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(0)
expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(0)
expect(firstInterceptor['emitter'].listenerCount('bar')).toBe(1)
expect(secondInterceptor['emitter'].listenerCount('bar')).toBe(1)
})

it('forwards removal of all listeners via ".removeAllListeners()"', () => {
class FirstInterceptor extends Interceptor<any> {
constructor() {
super(Symbol('first'))
}
}
class SecondaryInterceptor extends Interceptor<any> {
constructor() {
super(Symbol('second'))
}
}

const firstInterceptor = new FirstInterceptor()
const secondInterceptor = new SecondaryInterceptor()

const interceptor = new BatchInterceptor({
name: 'batch',
interceptors: [firstInterceptor, secondInterceptor],
})

const listener = vi.fn()
interceptor.on('foo', listener)
interceptor.on('foo', listener)
interceptor.on('bar', listener)

expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(2)
expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(2)
expect(firstInterceptor['emitter'].listenerCount('bar')).toBe(1)
expect(secondInterceptor['emitter'].listenerCount('bar')).toBe(1)

interceptor.removeAllListeners()

expect(firstInterceptor['emitter'].listenerCount('foo')).toBe(0)
expect(secondInterceptor['emitter'].listenerCount('foo')).toBe(0)
expect(firstInterceptor['emitter'].listenerCount('bar')).toBe(0)
expect(secondInterceptor['emitter'].listenerCount('bar')).toBe(0)
})
10 changes: 10 additions & 0 deletions src/BatchInterceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,14 @@ export class BatchInterceptor<

return this
}

public removeAllListeners<EventName extends ExtractEventNames<Events>>(
event?: EventName | undefined
): this {
for (const interceptors of this.interceptors) {
interceptors.removeAllListeners(event)
}

return this
}
}
29 changes: 16 additions & 13 deletions src/Interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export class Interceptor<Events extends InterceptorEventMap> {
* Listen to the interceptor's public events.
*/
public on<EventName extends ExtractEventNames<Events>>(
eventName: EventName,
event: EventName,
listener: Listener<Events[EventName]>
): this {
const logger = this.logger.extend('on')
Expand All @@ -156,35 +156,38 @@ export class Interceptor<Events extends InterceptorEventMap> {
return this
}

logger.info('adding "%s" event listener:', eventName, listener.name)
logger.info('adding "%s" event listener:', event, listener.name)

this.emitter.on(eventName, listener)
this.emitter.on(event, listener)
return this
}

public once<EventName extends ExtractEventNames<Events>>(
eventName: EventName,
event: EventName,
listener: Listener<Events[EventName]>
): this {
const logger = this.logger.extend('once')
logger.info(
'adding a one-time "%s" event listener:',
eventName,
listener.name
)
logger.info('adding a one-time "%s" event listener:', event, listener.name)

this.emitter.once(eventName, listener)
this.emitter.once(event, listener)
return this
}

public off<EventName extends ExtractEventNames<Events>>(
eventName: EventName,
event: EventName,
listener: Listener<Events[EventName]>
): this {
const logger = this.logger.extend('off')
logger.info('removing "%s" event listener:', eventName, listener.name)
logger.info('removing "%s" event listener:', event, listener.name)

this.emitter.off(eventName, listener)
this.emitter.off(event, listener)
return this
}

public removeAllListeners<EventName extends ExtractEventNames<Events>>(
event?: EventName
): this {
this.emitter.removeAllListeners(event)
return this
}

Expand Down

0 comments on commit 6aa2c8b

Please sign in to comment.