From 5ab306406c5dc574148a13ec00a45de12e88591f Mon Sep 17 00:00:00 2001 From: Josh Justice Date: Thu, 13 Oct 2022 13:24:53 -0400 Subject: [PATCH 1/9] pass object --- src/__tests__/fireEvent.test.tsx | 62 ++++++++++++++++++++++++-------- src/fireEvent.ts | 2 +- 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/__tests__/fireEvent.test.tsx b/src/__tests__/fireEvent.test.tsx index 184ba6067..23610f573 100644 --- a/src/__tests__/fireEvent.test.tsx +++ b/src/__tests__/fireEvent.test.tsx @@ -55,6 +55,13 @@ const CustomEventComponentWithCustomName = ({ ); +// https://callstack.github.io/react-native-testing-library/docs/api/#fireevent + +// function fireEvent( +// element: ReactTestInstance, +// eventName: string, +// ...data: Array +// ) describe('fireEvent', () => { test('should invoke specified event', () => { const onPressMock = jest.fn(); @@ -104,24 +111,46 @@ describe('fireEvent', () => { }); }); -test('fireEvent.press', () => { - const onPressMock = jest.fn(); - const text = 'Fireevent press'; - const eventData = { - nativeEvent: { - pageX: 20, - pageY: 30, - }, - }; - const { getByText } = render( - - ); +// fireEvent.press: ( +// element: ReactTestInstance, +// ...data: Array +// ) +describe('fireEvent.press', () => { + test('should pass along provided event data', () => { + const onPressMock = jest.fn(); + const text = 'Fireevent press'; + const eventData = { + nativeEvent: { + pageX: 20, + pageY: 30, + }, + }; + const { getByText } = render( + + ); + + fireEvent.press(getByText(text), eventData); + + expect(onPressMock).toHaveBeenCalledWith(eventData); + }); + + test.only('should pass a synthetic event object by default', () => { + const onPressMock = jest.fn(); + const text = 'Fireevent press'; + const { getByText } = render( + + ); - fireEvent.press(getByText(text), eventData); + fireEvent.press(getByText(text)); - expect(onPressMock).toHaveBeenCalledWith(eventData); + expect(onPressMock).toHaveBeenCalledWith({ someKey: 'value' }); + }); }); +// fireEvent.scroll: ( +// element: ReactTestInstance, +// ...data: Array +// ) test('fireEvent.scroll', () => { const onScrollMock = jest.fn(); const eventData = { @@ -143,6 +172,11 @@ test('fireEvent.scroll', () => { expect(onScrollMock).toHaveBeenCalledWith(eventData); }); +// fireEvent.changeText: ( +// element: ReactTestInstance, +// ...data: Array +// ) +// (first element of data should be the text. Does RN even pass an event object?) test('fireEvent.changeText', () => { const onChangeTextMock = jest.fn(); const CHANGE_TEXT = 'content'; diff --git a/src/fireEvent.ts b/src/fireEvent.ts index f5ec35f4f..f9eacf2b7 100644 --- a/src/fireEvent.ts +++ b/src/fireEvent.ts @@ -118,7 +118,7 @@ const invokeEvent = ( let returnValue; act(() => { - returnValue = handler(...data); + returnValue = handler({ someKey: 'value' }); }); return returnValue; From 72ef1aae2f79d18cf24280168992a42ccb60cc3d Mon Sep 17 00:00:00 2001 From: Josh Justice Date: Thu, 13 Oct 2022 14:43:30 -0400 Subject: [PATCH 2/9] spike handling press, scroll, and changeText --- src/__tests__/fireEvent.test.tsx | 99 +++++++++++++++++++++----------- src/fireEvent.ts | 26 ++++++++- 2 files changed, 92 insertions(+), 33 deletions(-) diff --git a/src/__tests__/fireEvent.test.tsx b/src/__tests__/fireEvent.test.tsx index 23610f573..34dcdda7d 100644 --- a/src/__tests__/fireEvent.test.tsx +++ b/src/__tests__/fireEvent.test.tsx @@ -116,7 +116,7 @@ describe('fireEvent', () => { // ...data: Array // ) describe('fireEvent.press', () => { - test('should pass along provided event data', () => { + test.only('should pass along provided event data', () => { const onPressMock = jest.fn(); const text = 'Fireevent press'; const eventData = { @@ -151,25 +151,41 @@ describe('fireEvent.press', () => { // element: ReactTestInstance, // ...data: Array // ) -test('fireEvent.scroll', () => { - const onScrollMock = jest.fn(); - const eventData = { - nativeEvent: { - contentOffset: { - y: 200, +describe('fireEvent.scroll', () => { + test.only('should pass along provided event data', () => { + const onScrollMock = jest.fn(); + const eventData = { + nativeEvent: { + contentOffset: { + y: 200, + }, }, - }, - }; + }; - const { getByText } = render( - - XD - - ); + const { getByText } = render( + + XD + + ); + + fireEvent.scroll(getByText('XD'), eventData); - fireEvent.scroll(getByText('XD'), eventData); + expect(onScrollMock).toHaveBeenCalledWith(eventData); + }); + test.only('should pass a synthetic event object by default', () => { + const onScrollMock = jest.fn(); + const eventData = { someKey: 'value' }; - expect(onScrollMock).toHaveBeenCalledWith(eventData); + const { getByText } = render( + + XD + + ); + + fireEvent.scroll(getByText('XD')); + + expect(onScrollMock).toHaveBeenCalledWith(eventData); + }); }); // fireEvent.changeText: ( @@ -177,25 +193,44 @@ test('fireEvent.scroll', () => { // ...data: Array // ) // (first element of data should be the text. Does RN even pass an event object?) -test('fireEvent.changeText', () => { - const onChangeTextMock = jest.fn(); - const CHANGE_TEXT = 'content'; +describe('fireEvent.changeText', () => { + test.only('should pass the provided text', () => { + const onChangeTextMock = jest.fn(); + const CHANGE_TEXT = 'content'; - const { getByPlaceholderText } = render( - - - - ); + const { getByPlaceholderText } = render( + + + + ); - fireEvent.changeText( - getByPlaceholderText('Customer placeholder'), - CHANGE_TEXT - ); + fireEvent.changeText( + getByPlaceholderText('Customer placeholder'), + CHANGE_TEXT + ); - expect(onChangeTextMock).toHaveBeenCalledWith(CHANGE_TEXT); + expect(onChangeTextMock).toHaveBeenCalledWith(CHANGE_TEXT); + }); + + test.only('what if no text is provided', () => { + const onChangeTextMock = jest.fn(); + + const { getByPlaceholderText } = render( + + + + ); + + fireEvent.changeText(getByPlaceholderText('Customer placeholder')); + + expect(onChangeTextMock).toHaveBeenCalledWith(); + }); }); test('custom component with custom event name', () => { diff --git a/src/fireEvent.ts b/src/fireEvent.ts index f9eacf2b7..f6734205f 100644 --- a/src/fireEvent.ts +++ b/src/fireEvent.ts @@ -103,12 +103,35 @@ const getEventHandler = ( return undefined; }; +// should other built-in RN events use the hard coded event object? +// should custom events for third-party components? +// what about when there are other data arguments provided? should they override the hard coded event object? for press? changeText? scroll? etc. + +// what does react native do? ^ +// how does testing library handle ^ + +// one scenario josh has more confidence about: when you have a component/element with an event handler configured, and that is an event that takes an event object (like press, unlike changeText), you should be able to pass a custom event object in your test, and that will be used in place of the test-library-provided event object + const invokeEvent = ( element: ReactTestInstance, eventName: string, callsite?: any, ...data: Array ) => { + // this is here for now: + // if change text, use text, otherwise use hardcodedEventObject + let handlerCallbackValues: Array; + if (eventName === 'changeText') { + const textEntered = data[0]; + handlerCallbackValues = textEntered ? [textEntered] : []; + } else { + const hardCodedEventObject = { someKey: 'value' }; + const customEventObject = data[0]; + handlerCallbackValues = customEventObject + ? [customEventObject] + : [hardCodedEventObject]; + } + const handler = findEventHandler(element, eventName, callsite); if (!handler) { @@ -118,7 +141,8 @@ const invokeEvent = ( let returnValue; act(() => { - returnValue = handler({ someKey: 'value' }); + returnValue = handler(...handlerCallbackValues); + //returnValue = handler(...data); }); return returnValue; From a1f681c0611a366fde4d1a5d88767b12aa89f2a7 Mon Sep 17 00:00:00 2001 From: Josh Justice Date: Thu, 13 Oct 2022 16:04:13 -0400 Subject: [PATCH 3/9] remove duplication in deciding handler callback values --- src/fireEvent.ts | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/fireEvent.ts b/src/fireEvent.ts index f6734205f..bc9e43ee6 100644 --- a/src/fireEvent.ts +++ b/src/fireEvent.ts @@ -120,17 +120,13 @@ const invokeEvent = ( ) => { // this is here for now: // if change text, use text, otherwise use hardcodedEventObject - let handlerCallbackValues: Array; - if (eventName === 'changeText') { - const textEntered = data[0]; - handlerCallbackValues = textEntered ? [textEntered] : []; - } else { - const hardCodedEventObject = { someKey: 'value' }; - const customEventObject = data[0]; - handlerCallbackValues = customEventObject - ? [customEventObject] - : [hardCodedEventObject]; - } + // do we still care about other data values? + // understand other arguments to event handlers... + const hardCodedEventObject = { someKey: 'value' }; + let defaultCallbackValues = + eventName === 'changeText' ? [] : [hardCodedEventObject]; + const handlerCallbackValues = data[0] ? [data[0]] : defaultCallbackValues; + // or maybe it's something like: if there are *any* data arguments, use them; otherwise pass the defaults const handler = findEventHandler(element, eventName, callsite); From e58cff256c7c31954b53a69862b18456a9292fe6 Mon Sep 17 00:00:00 2001 From: Josh Justice Date: Thu, 13 Oct 2022 17:07:42 -0400 Subject: [PATCH 4/9] Pass multiple events along --- src/__tests__/fireEvent.test.tsx | 22 ++++++++++++++++++++++ src/fireEvent.ts | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/__tests__/fireEvent.test.tsx b/src/__tests__/fireEvent.test.tsx index 34dcdda7d..8f4a76bfc 100644 --- a/src/__tests__/fireEvent.test.tsx +++ b/src/__tests__/fireEvent.test.tsx @@ -63,6 +63,28 @@ const CustomEventComponentWithCustomName = ({ // ...data: Array // ) describe('fireEvent', () => { + test('QUESTION: is there a kind of event that takes multiple arguments?', () => { + const handlerMock = jest.fn(); + + const { getByText } = render( + + + + ); + + fireEvent( + getByText('Custom event component'), + 'customEvent', + 'some_argument_1', + 'some_argument_2' + ); + + expect(handlerMock).toHaveBeenCalledWith( + 'some_argument_1', + 'some_argument_2' + ); + }); + test('should invoke specified event', () => { const onPressMock = jest.fn(); const { getByText } = render( diff --git a/src/fireEvent.ts b/src/fireEvent.ts index bc9e43ee6..ddda4ba9b 100644 --- a/src/fireEvent.ts +++ b/src/fireEvent.ts @@ -125,7 +125,7 @@ const invokeEvent = ( const hardCodedEventObject = { someKey: 'value' }; let defaultCallbackValues = eventName === 'changeText' ? [] : [hardCodedEventObject]; - const handlerCallbackValues = data[0] ? [data[0]] : defaultCallbackValues; + const handlerCallbackValues = data.length > 0 ? data : defaultCallbackValues; // or maybe it's something like: if there are *any* data arguments, use them; otherwise pass the defaults const handler = findEventHandler(element, eventName, callsite); From a2afde3d2b03aff25f43df3a366b8076a85b1109 Mon Sep 17 00:00:00 2001 From: Josh Justice Date: Thu, 13 Oct 2022 17:07:52 -0400 Subject: [PATCH 5/9] Unfocus tests --- src/__tests__/fireEvent.test.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/__tests__/fireEvent.test.tsx b/src/__tests__/fireEvent.test.tsx index 8f4a76bfc..d6535969c 100644 --- a/src/__tests__/fireEvent.test.tsx +++ b/src/__tests__/fireEvent.test.tsx @@ -138,7 +138,7 @@ describe('fireEvent', () => { // ...data: Array // ) describe('fireEvent.press', () => { - test.only('should pass along provided event data', () => { + test('should pass along provided event data', () => { const onPressMock = jest.fn(); const text = 'Fireevent press'; const eventData = { @@ -156,7 +156,7 @@ describe('fireEvent.press', () => { expect(onPressMock).toHaveBeenCalledWith(eventData); }); - test.only('should pass a synthetic event object by default', () => { + test('should pass a synthetic event object by default', () => { const onPressMock = jest.fn(); const text = 'Fireevent press'; const { getByText } = render( @@ -174,7 +174,7 @@ describe('fireEvent.press', () => { // ...data: Array // ) describe('fireEvent.scroll', () => { - test.only('should pass along provided event data', () => { + test('should pass along provided event data', () => { const onScrollMock = jest.fn(); const eventData = { nativeEvent: { @@ -194,7 +194,7 @@ describe('fireEvent.scroll', () => { expect(onScrollMock).toHaveBeenCalledWith(eventData); }); - test.only('should pass a synthetic event object by default', () => { + test('should pass a synthetic event object by default', () => { const onScrollMock = jest.fn(); const eventData = { someKey: 'value' }; @@ -216,7 +216,7 @@ describe('fireEvent.scroll', () => { // ) // (first element of data should be the text. Does RN even pass an event object?) describe('fireEvent.changeText', () => { - test.only('should pass the provided text', () => { + test('should pass the provided text', () => { const onChangeTextMock = jest.fn(); const CHANGE_TEXT = 'content'; @@ -237,7 +237,7 @@ describe('fireEvent.changeText', () => { expect(onChangeTextMock).toHaveBeenCalledWith(CHANGE_TEXT); }); - test.only('what if no text is provided', () => { + test('what if no text is provided', () => { const onChangeTextMock = jest.fn(); const { getByPlaceholderText } = render( From 60ffccacf8e7741683d2faa0c9e12a8435948276 Mon Sep 17 00:00:00 2001 From: Josh Justice Date: Thu, 13 Oct 2022 19:50:31 -0400 Subject: [PATCH 6/9] Remove comments --- src/__tests__/fireEvent.test.tsx | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/__tests__/fireEvent.test.tsx b/src/__tests__/fireEvent.test.tsx index d6535969c..c4503493d 100644 --- a/src/__tests__/fireEvent.test.tsx +++ b/src/__tests__/fireEvent.test.tsx @@ -55,13 +55,6 @@ const CustomEventComponentWithCustomName = ({ ); -// https://callstack.github.io/react-native-testing-library/docs/api/#fireevent - -// function fireEvent( -// element: ReactTestInstance, -// eventName: string, -// ...data: Array -// ) describe('fireEvent', () => { test('QUESTION: is there a kind of event that takes multiple arguments?', () => { const handlerMock = jest.fn(); @@ -133,10 +126,6 @@ describe('fireEvent', () => { }); }); -// fireEvent.press: ( -// element: ReactTestInstance, -// ...data: Array -// ) describe('fireEvent.press', () => { test('should pass along provided event data', () => { const onPressMock = jest.fn(); @@ -169,10 +158,6 @@ describe('fireEvent.press', () => { }); }); -// fireEvent.scroll: ( -// element: ReactTestInstance, -// ...data: Array -// ) describe('fireEvent.scroll', () => { test('should pass along provided event data', () => { const onScrollMock = jest.fn(); @@ -210,11 +195,6 @@ describe('fireEvent.scroll', () => { }); }); -// fireEvent.changeText: ( -// element: ReactTestInstance, -// ...data: Array -// ) -// (first element of data should be the text. Does RN even pass an event object?) describe('fireEvent.changeText', () => { test('should pass the provided text', () => { const onChangeTextMock = jest.fn(); From 063c4f5bda45285f0e48702614536f4c92d3c313 Mon Sep 17 00:00:00 2001 From: Josh Justice Date: Thu, 13 Oct 2022 19:51:35 -0400 Subject: [PATCH 7/9] Clarify name of event object in tests --- src/__tests__/fireEvent.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/__tests__/fireEvent.test.tsx b/src/__tests__/fireEvent.test.tsx index c4503493d..f4e947c2e 100644 --- a/src/__tests__/fireEvent.test.tsx +++ b/src/__tests__/fireEvent.test.tsx @@ -145,7 +145,7 @@ describe('fireEvent.press', () => { expect(onPressMock).toHaveBeenCalledWith(eventData); }); - test('should pass a synthetic event object by default', () => { + test('should pass a generated event object by default', () => { const onPressMock = jest.fn(); const text = 'Fireevent press'; const { getByText } = render( @@ -179,7 +179,7 @@ describe('fireEvent.scroll', () => { expect(onScrollMock).toHaveBeenCalledWith(eventData); }); - test('should pass a synthetic event object by default', () => { + test('should pass a generated event object by default', () => { const onScrollMock = jest.fn(); const eventData = { someKey: 'value' }; From 4b908bafd05e01eb8b26cbd6ffacb6f26bc33d7a Mon Sep 17 00:00:00 2001 From: Josh Justice Date: Fri, 14 Oct 2022 06:40:30 -0400 Subject: [PATCH 8/9] Clean up fireEvent --- src/fireEvent.ts | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/src/fireEvent.ts b/src/fireEvent.ts index ddda4ba9b..1fc7c4323 100644 --- a/src/fireEvent.ts +++ b/src/fireEvent.ts @@ -103,42 +103,29 @@ const getEventHandler = ( return undefined; }; -// should other built-in RN events use the hard coded event object? -// should custom events for third-party components? -// what about when there are other data arguments provided? should they override the hard coded event object? for press? changeText? scroll? etc. - -// what does react native do? ^ -// how does testing library handle ^ - -// one scenario josh has more confidence about: when you have a component/element with an event handler configured, and that is an event that takes an event object (like press, unlike changeText), you should be able to pass a custom event object in your test, and that will be used in place of the test-library-provided event object - const invokeEvent = ( element: ReactTestInstance, eventName: string, callsite?: any, ...data: Array ) => { - // this is here for now: - // if change text, use text, otherwise use hardcodedEventObject - // do we still care about other data values? - // understand other arguments to event handlers... - const hardCodedEventObject = { someKey: 'value' }; - let defaultCallbackValues = - eventName === 'changeText' ? [] : [hardCodedEventObject]; - const handlerCallbackValues = data.length > 0 ? data : defaultCallbackValues; - // or maybe it's something like: if there are *any* data arguments, use them; otherwise pass the defaults - const handler = findEventHandler(element, eventName, callsite); if (!handler) { return; } + // this is just a placeholder and needs to be a more realistic object + const generatedEventObject = { someKey: 'value' }; + + let defaultCallbackValues = + eventName === 'changeText' ? [] : [generatedEventObject]; + const handlerCallbackValues = data.length > 0 ? data : defaultCallbackValues; + let returnValue; act(() => { returnValue = handler(...handlerCallbackValues); - //returnValue = handler(...data); }); return returnValue; From 454926a15bf7820bf74c9d7c1f529260c8078a0b Mon Sep 17 00:00:00 2001 From: Andy Mikula Date: Thu, 27 Oct 2022 14:04:34 -0600 Subject: [PATCH 9/9] Only return default events on property syntax --- src/__tests__/fireEvent.test.tsx | 37 +++++++++++++++++++-- src/fireEvent.ts | 56 +++++++++++++++++++------------- 2 files changed, 68 insertions(+), 25 deletions(-) diff --git a/src/__tests__/fireEvent.test.tsx b/src/__tests__/fireEvent.test.tsx index f4e947c2e..0c34e8836 100644 --- a/src/__tests__/fireEvent.test.tsx +++ b/src/__tests__/fireEvent.test.tsx @@ -89,6 +89,37 @@ describe('fireEvent', () => { expect(onPressMock).toHaveBeenCalled(); }); + test('should pass along provided event data', () => { + const onPressMock = jest.fn(); + const text = 'Fireevent press'; + const eventData = { + nativeEvent: { + pageX: 20, + pageY: 30, + }, + }; + const { getByText } = render( + + ); + + fireEvent(getByText(text), 'press', eventData); + + expect(onPressMock).toHaveBeenCalledWith(eventData); + }); + + test('should not pass a generated event object by default with the string syntax', () => { + const onPressMock = jest.fn(); + const text = 'Fireevent press'; + const { getByText } = render( + + ); + + fireEvent(getByText(text), 'press'); + + expect(onPressMock).toHaveBeenCalled(); + expect(onPressMock).not.toHaveBeenCalledWith({ eventName: 'press' }); + }); + test('should invoke specified event on parent element', () => { const onPressMock = jest.fn(); const text = 'New press text'; @@ -145,7 +176,7 @@ describe('fireEvent.press', () => { expect(onPressMock).toHaveBeenCalledWith(eventData); }); - test('should pass a generated event object by default', () => { + test('should pass a generated event object by default with the function syntax', () => { const onPressMock = jest.fn(); const text = 'Fireevent press'; const { getByText } = render( @@ -154,7 +185,7 @@ describe('fireEvent.press', () => { fireEvent.press(getByText(text)); - expect(onPressMock).toHaveBeenCalledWith({ someKey: 'value' }); + expect(onPressMock).toHaveBeenCalledWith({ eventName: 'press' }); }); }); @@ -181,7 +212,7 @@ describe('fireEvent.scroll', () => { }); test('should pass a generated event object by default', () => { const onScrollMock = jest.fn(); - const eventData = { someKey: 'value' }; + const eventData = { eventName: 'scroll' }; const { getByText } = render( diff --git a/src/fireEvent.ts b/src/fireEvent.ts index 1fc7c4323..00e1c3f76 100644 --- a/src/fireEvent.ts +++ b/src/fireEvent.ts @@ -107,7 +107,7 @@ const invokeEvent = ( element: ReactTestInstance, eventName: string, callsite?: any, - ...data: Array + ...callBackValues: Array ) => { const handler = findEventHandler(element, eventName, callsite); @@ -115,17 +115,10 @@ const invokeEvent = ( return; } - // this is just a placeholder and needs to be a more realistic object - const generatedEventObject = { someKey: 'value' }; - - let defaultCallbackValues = - eventName === 'changeText' ? [] : [generatedEventObject]; - const handlerCallbackValues = data.length > 0 ? data : defaultCallbackValues; - let returnValue; act(() => { - returnValue = handler(...handlerCallbackValues); + returnValue = handler(...callBackValues); }); return returnValue; @@ -134,23 +127,42 @@ const invokeEvent = ( const toEventHandlerName = (eventName: string) => `on${eventName.charAt(0).toUpperCase()}${eventName.slice(1)}`; -const pressHandler = (element: ReactTestInstance, ...data: Array): void => - invokeEvent(element, 'press', pressHandler, ...data); const changeTextHandler = ( element: ReactTestInstance, ...data: Array -): void => invokeEvent(element, 'changeText', changeTextHandler, ...data); -const scrollHandler = (element: ReactTestInstance, ...data: Array): void => - invokeEvent(element, 'scroll', scrollHandler, ...data); +): void => { + invokeEvent(element, 'changeText', changeTextHandler, ...data); +}; -const fireEvent = ( - element: ReactTestInstance, - eventName: string, - ...data: Array -): void => invokeEvent(element, eventName, fireEvent, ...data); +const generatedEventObject = (eventName: string) => { + // This should use the (as-yet nonexistent) event map to return a "real" object, just like + // https://github.com/testing-library/dom-testing-library/blob/29a17cb5f14b0f30f08a29172e35e55c3e8ba529/src/event-map.js#L0-L1 + return { eventName: eventName }; +}; + +const addHandler = (eventName: string) => { + return (element: ReactTestInstance, ...data: Array): void => { + const callBackValue = + data.length > 0 ? data : [generatedEventObject(eventName)]; + invokeEvent(element, eventName, addHandler, ...callBackValue); + }; +}; + +type FireEvent = { + (element: ReactTestInstance, eventName: string, ...data: Array): void; + [key: string]: (element: ReactTestInstance, ...data: Array) => void; +}; + +const fireEvent = ( + ((element: ReactTestInstance, eventName: string, ...data: Array) => + invokeEvent(element, eventName, fireEvent, ...data)) +); + +fireEvent['changeText'] = changeTextHandler; -fireEvent.press = pressHandler; -fireEvent.changeText = changeTextHandler; -fireEvent.scroll = scrollHandler; +// map.keys.forEach ... +['press', 'scroll'].forEach((eventName: string) => { + fireEvent[eventName] = addHandler(eventName); +}); export default fireEvent;