Skip to content

Commit

Permalink
fix: makeEventFunctions take an array of parameters (#2186)
Browse files Browse the repository at this point in the history
- Previously every emit required exactly one parameter, which is not the
case
- Allow zero or more parameters
  • Loading branch information
mofojed committed Aug 20, 2024
1 parent d409e96 commit f5b01fd
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 45 deletions.
2 changes: 1 addition & 1 deletion packages/dashboard/src/PanelEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export const {
listen: listenForPanelOpen,
emit: emitPanelOpen,
useListener: usePanelOpenListener,
} = makeEventFunctions<PanelOpenEventDetail>(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.

Expand Down
103 changes: 83 additions & 20 deletions packages/golden-layout/src/utils/EventUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe('EventUtils', () => {

it('makeEmitFunction', () => {
const event = 'test';
const emit = makeEmitFunction(event);
const emit = makeEmitFunction<unknown>(event);
const payload = { test: 'test' };
emit(eventEmitter, payload);
expect(eventEmitter.emit).toHaveBeenCalledWith(event, payload);
Expand Down Expand Up @@ -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<Payload>(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<Payload>(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);
});
});
});
});
53 changes: 29 additions & 24 deletions packages/golden-layout/src/utils/EventUtils.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import EventEmitter from './EventEmitter';
import { useEffect } from 'react';
import EventEmitter from './EventEmitter';

type AsArray<P> = P extends unknown[] ? P : [P];

export type EventHandlerFunction<P = []> = (...parameters: AsArray<P>) => void;
export type EventListenerRemover = () => void;
export type EventListenFunction<TPayload = unknown> = (
export type EventListenFunction<TParameters = []> = (
eventEmitter: EventEmitter,
handler: (p: TPayload) => void
handler: EventHandlerFunction<TParameters>
) => EventListenerRemover;

export type EventEmitFunction<TPayload = unknown> = (
export type EventEmitFunction<TParameters = []> = (
eventEmitter: EventEmitter,
payload: TPayload
...parameters: AsArray<TParameters>
) => void;

export type EventListenerHook<TPayload = unknown> = (
export type EventListenerHook<TParameters = []> = (
eventEmitter: EventEmitter,
handler: (p: TPayload) => void
handler: EventHandlerFunction<TParameters>
) => void;

/**
Expand All @@ -24,35 +27,35 @@ export type EventListenerHook<TPayload = unknown> = (
* @param handler The handler to call when the event is emitted
* @returns A function to stop listening for the event
*/
export function listenForEvent<TPayload>(
export function listenForEvent<TParameters = []>(
eventEmitter: EventEmitter,
event: string,
handler: (p: TPayload) => void
handler: EventHandlerFunction<TParameters>
): EventListenerRemover {
eventEmitter.on(event, handler);
return () => {
eventEmitter.off(event, handler);
};
}

export function makeListenFunction<TPayload>(
export function makeListenFunction<TParameters = []>(
event: string
): EventListenFunction<TPayload> {
): EventListenFunction<TParameters> {
return (eventEmitter, handler) =>
listenForEvent(eventEmitter, event, handler);
}

export function makeEmitFunction<TPayload>(
export function makeEmitFunction<TParameters = []>(
event: string
): EventEmitFunction<TPayload> {
return (eventEmitter, payload) => {
eventEmitter.emit(event, payload);
): EventEmitFunction<TParameters> {
return (eventEmitter, ...parameters) => {
eventEmitter.emit(event, ...parameters);
};
}

export function makeUseListenerFunction<TPayload>(
export function makeUseListenerFunction<TParameters = []>(
event: string
): EventListenerHook<TPayload> {
): EventListenerHook<TParameters> {
return (eventEmitter, handler) => {
useEffect(
() => listenForEvent(eventEmitter, event, handler),
Expand All @@ -66,14 +69,16 @@ export function makeUseListenerFunction<TPayload>(
* @param event Name of the event to create functions for
* @returns Listener, Emitter, and Hook functions for the event
*/
export function makeEventFunctions<TPayload>(event: string): {
listen: EventListenFunction<TPayload>;
emit: EventEmitFunction<TPayload>;
useListener: EventListenerHook<TPayload>;
export function makeEventFunctions<TParameters = []>(
event: string
): {
listen: EventListenFunction<TParameters>;
emit: EventEmitFunction<TParameters>;
useListener: EventListenerHook<TParameters>;
} {
return {
listen: makeListenFunction<TPayload>(event),
emit: makeEmitFunction<TPayload>(event),
useListener: makeUseListenerFunction<TPayload>(event),
listen: makeListenFunction<TParameters>(event),
emit: makeEmitFunction<TParameters>(event),
useListener: makeUseListenerFunction<TParameters>(event),
};
}

0 comments on commit f5b01fd

Please sign in to comment.