From f5b01fdd69de13233f9e08ef76979e7c07b1759c Mon Sep 17 00:00:00 2001 From: Mike Bender Date: Tue, 20 Aug 2024 16:12:37 -0400 Subject: [PATCH] fix: makeEventFunctions take an array of parameters (#2186) - Previously every emit required exactly one parameter, which is not the case - Allow zero or more parameters --- packages/dashboard/src/PanelEvent.ts | 2 +- .../src/utils/EventUtils.test.ts | 103 ++++++++++++++---- .../golden-layout/src/utils/EventUtils.ts | 53 +++++---- 3 files changed, 113 insertions(+), 45 deletions(-) diff --git a/packages/dashboard/src/PanelEvent.ts b/packages/dashboard/src/PanelEvent.ts index c15eb98f5..82e735418 100644 --- a/packages/dashboard/src/PanelEvent.ts +++ b/packages/dashboard/src/PanelEvent.ts @@ -76,7 +76,7 @@ export const { listen: listenForPanelOpen, emit: emitPanelOpen, useListener: usePanelOpenListener, -} = makeEventFunctions(PanelEvent.OPEN); +} = makeEventFunctions<[detail: PanelOpenEventDetail]>(PanelEvent.OPEN); // TODO (#2147): Add the rest of the event functions here. Need to create the correct types for all of them. diff --git a/packages/golden-layout/src/utils/EventUtils.test.ts b/packages/golden-layout/src/utils/EventUtils.test.ts index 956a87d68..f0638fa2f 100644 --- a/packages/golden-layout/src/utils/EventUtils.test.ts +++ b/packages/golden-layout/src/utils/EventUtils.test.ts @@ -45,7 +45,7 @@ describe('EventUtils', () => { it('makeEmitFunction', () => { const event = 'test'; - const emit = makeEmitFunction(event); + const emit = makeEmitFunction(event); const payload = { test: 'test' }; emit(eventEmitter, payload); expect(eventEmitter.emit).toHaveBeenCalledWith(event, payload); @@ -109,30 +109,93 @@ describe('EventUtils', () => { }); describe('makeEventFunctions', () => { - const event = 'test'; - const { listen, emit, useListener } = makeEventFunctions(event); - const handler = jest.fn(); + describe('makeEventFunctions without payload', () => { + const event = 'test'; + const { listen, emit, useListener } = makeEventFunctions(event); + const handler = jest.fn(); - it('listen', () => { - listen(eventEmitter, handler); - expect(eventEmitter.on).toHaveBeenCalledWith(event, handler); - expect(eventEmitter.off).not.toHaveBeenCalled(); + it('listen', () => { + listen(eventEmitter, handler); + expect(eventEmitter.on).toHaveBeenCalledWith(event, handler); + expect(eventEmitter.off).not.toHaveBeenCalled(); + }); + + it('emit', () => { + emit(eventEmitter); + expect(eventEmitter.emit).toHaveBeenCalledWith(event); + }); + + it('useListener', () => { + const { unmount } = renderHook(() => + useListener(eventEmitter, handler) + ); + expect(eventEmitter.on).toHaveBeenCalledWith(event, handler); + expect(eventEmitter.off).not.toHaveBeenCalled(); + jest.clearAllMocks(); + unmount(); + expect(eventEmitter.on).not.toHaveBeenCalledWith(event, handler); + expect(eventEmitter.off).toHaveBeenCalledWith(event, handler); + }); }); + describe('makeEventFunctions with payload', () => { + type Payload = { test: string }; + const event = 'test'; + const { listen, emit, useListener } = makeEventFunctions(event); + const handler = jest.fn(); + + it('listen', () => { + listen(eventEmitter, handler); + expect(eventEmitter.on).toHaveBeenCalledWith(event, handler); + expect(eventEmitter.off).not.toHaveBeenCalled(); + }); + + it('emit', () => { + const payload: Payload = { test: 'test' }; + emit(eventEmitter, payload); + expect(eventEmitter.emit).toHaveBeenCalledWith(event, payload); + }); - it('emit', () => { - const payload = { test: 'test' }; - emit(eventEmitter, payload); - expect(eventEmitter.emit).toHaveBeenCalledWith(event, payload); + it('useListener', () => { + const { unmount } = renderHook(() => + useListener(eventEmitter, handler) + ); + expect(eventEmitter.on).toHaveBeenCalledWith(event, handler); + expect(eventEmitter.off).not.toHaveBeenCalled(); + jest.clearAllMocks(); + unmount(); + expect(eventEmitter.on).not.toHaveBeenCalledWith(event, handler); + expect(eventEmitter.off).toHaveBeenCalledWith(event, handler); + }); }); + describe('makeEventFunctions with multiple parameters', () => { + type Payload = [number, string]; + const event = 'test'; + const { listen, emit, useListener } = makeEventFunctions(event); + const handler = jest.fn(); - it('useListener', () => { - const { unmount } = renderHook(() => useListener(eventEmitter, handler)); - expect(eventEmitter.on).toHaveBeenCalledWith(event, handler); - expect(eventEmitter.off).not.toHaveBeenCalled(); - jest.clearAllMocks(); - unmount(); - expect(eventEmitter.on).not.toHaveBeenCalledWith(event, handler); - expect(eventEmitter.off).toHaveBeenCalledWith(event, handler); + it('listen', () => { + listen(eventEmitter, handler); + expect(eventEmitter.on).toHaveBeenCalledWith(event, handler); + expect(eventEmitter.off).not.toHaveBeenCalled(); + }); + + it('emit', () => { + const payload: Payload = [1, 'test']; + emit(eventEmitter, ...payload); + expect(eventEmitter.emit).toHaveBeenCalledWith(event, ...payload); + }); + + it('useListener', () => { + const { unmount } = renderHook(() => + useListener(eventEmitter, handler) + ); + expect(eventEmitter.on).toHaveBeenCalledWith(event, handler); + expect(eventEmitter.off).not.toHaveBeenCalled(); + jest.clearAllMocks(); + unmount(); + expect(eventEmitter.on).not.toHaveBeenCalledWith(event, handler); + expect(eventEmitter.off).toHaveBeenCalledWith(event, handler); + }); }); }); }); diff --git a/packages/golden-layout/src/utils/EventUtils.ts b/packages/golden-layout/src/utils/EventUtils.ts index 9ae97437b..7862d7727 100644 --- a/packages/golden-layout/src/utils/EventUtils.ts +++ b/packages/golden-layout/src/utils/EventUtils.ts @@ -1,20 +1,23 @@ -import EventEmitter from './EventEmitter'; import { useEffect } from 'react'; +import EventEmitter from './EventEmitter'; +type AsArray

= P extends unknown[] ? P : [P]; + +export type EventHandlerFunction

= (...parameters: AsArray

) => void; export type EventListenerRemover = () => void; -export type EventListenFunction = ( +export type EventListenFunction = ( eventEmitter: EventEmitter, - handler: (p: TPayload) => void + handler: EventHandlerFunction ) => EventListenerRemover; -export type EventEmitFunction = ( +export type EventEmitFunction = ( eventEmitter: EventEmitter, - payload: TPayload + ...parameters: AsArray ) => void; -export type EventListenerHook = ( +export type EventListenerHook = ( eventEmitter: EventEmitter, - handler: (p: TPayload) => void + handler: EventHandlerFunction ) => void; /** @@ -24,10 +27,10 @@ export type EventListenerHook = ( * @param handler The handler to call when the event is emitted * @returns A function to stop listening for the event */ -export function listenForEvent( +export function listenForEvent( eventEmitter: EventEmitter, event: string, - handler: (p: TPayload) => void + handler: EventHandlerFunction ): EventListenerRemover { eventEmitter.on(event, handler); return () => { @@ -35,24 +38,24 @@ export function listenForEvent( }; } -export function makeListenFunction( +export function makeListenFunction( event: string -): EventListenFunction { +): EventListenFunction { return (eventEmitter, handler) => listenForEvent(eventEmitter, event, handler); } -export function makeEmitFunction( +export function makeEmitFunction( event: string -): EventEmitFunction { - return (eventEmitter, payload) => { - eventEmitter.emit(event, payload); +): EventEmitFunction { + return (eventEmitter, ...parameters) => { + eventEmitter.emit(event, ...parameters); }; } -export function makeUseListenerFunction( +export function makeUseListenerFunction( event: string -): EventListenerHook { +): EventListenerHook { return (eventEmitter, handler) => { useEffect( () => listenForEvent(eventEmitter, event, handler), @@ -66,14 +69,16 @@ export function makeUseListenerFunction( * @param event Name of the event to create functions for * @returns Listener, Emitter, and Hook functions for the event */ -export function makeEventFunctions(event: string): { - listen: EventListenFunction; - emit: EventEmitFunction; - useListener: EventListenerHook; +export function makeEventFunctions( + event: string +): { + listen: EventListenFunction; + emit: EventEmitFunction; + useListener: EventListenerHook; } { return { - listen: makeListenFunction(event), - emit: makeEmitFunction(event), - useListener: makeUseListenerFunction(event), + listen: makeListenFunction(event), + emit: makeEmitFunction(event), + useListener: makeUseListenerFunction(event), }; }