feat: fireEvent API (#11)

Implementation of fireEvent API.

Fixes #7
This commit is contained in:
Kacper Wiszczuk
2018-10-07 08:23:21 +02:00
committed by Michał Pierzchała
parent 9d14406832
commit d66255d482
6 changed files with 318 additions and 20 deletions
+6
View File
@@ -0,0 +1,6 @@
// @flow
export const View = (props: *) => props.children;
export const ScrollView = (props: *) => props.children;
export const Text = (props: *) => props.children;
export const TextInput = () => null;
export const TouchableOpacity = (props: *) => props.children;
+132
View File
@@ -0,0 +1,132 @@
import React from 'react';
import {
View,
TouchableOpacity,
Text,
ScrollView,
TextInput,
} from '../__mocks__/reactNativeMock';
import fireEvent from '../fireEvent';
import { render } from '..';
const OnPressComponent = ({ onPress }) => (
<View>
<TouchableOpacity onPress={onPress} testID="button">
<Text testID="text-button">Press me</Text>
</TouchableOpacity>
</View>
);
const WithoutEventComponent = () => (
<View>
<Text testID="text">Content</Text>
</View>
);
const CustomEventComponent = ({ onCustomEvent }) => (
<TouchableOpacity onPress={onCustomEvent}>
<Text>Click me</Text>
</TouchableOpacity>
);
describe('fireEvent', () => {
test('should invoke specified event', () => {
const onPressMock = jest.fn();
const { getByTestId } = render(<OnPressComponent onPress={onPressMock} />);
fireEvent(getByTestId('button'), 'press');
expect(onPressMock).toHaveBeenCalled();
});
test('should invoke specified event on parent element', () => {
const onPressMock = jest.fn();
const { getByTestId } = render(<OnPressComponent onPress={onPressMock} />);
fireEvent(getByTestId('text-button'), 'press');
expect(onPressMock).toHaveBeenCalled();
});
test('should throw an Error when event handler was not found', () => {
const { getByTestId } = render(<WithoutEventComponent />);
expect(() => fireEvent(getByTestId('text'), 'press')).toThrowError(
'No handler function found for event: press'
);
});
test('should invoke event with custom name', () => {
const handlerMock = jest.fn();
const EVENT_DATA = 'event data';
const { getByTestId } = render(
<View>
<CustomEventComponent testID="custom" onCustomEvent={handlerMock} />
</View>
);
fireEvent(getByTestId('custom'), 'customEvent', EVENT_DATA);
expect(handlerMock).toHaveBeenCalledWith(EVENT_DATA);
});
});
test('fireEvent.press', () => {
const onPressMock = jest.fn();
const { getByTestId } = render(<OnPressComponent onPress={onPressMock} />);
fireEvent.press(getByTestId('text-button'));
expect(onPressMock).toHaveBeenCalled();
});
test('fireEvent.scroll', () => {
const onScrollMock = jest.fn();
const eventData = {
nativeEvent: {
contentOffset: {
y: 200,
},
},
};
const { getByTestId } = render(
<ScrollView testID="scroll-view" onScroll={onScrollMock}>
<Text>XD</Text>
</ScrollView>
);
fireEvent.scroll(getByTestId('scroll-view'), eventData);
expect(onScrollMock).toHaveBeenCalledWith(eventData);
});
test('fireEvent.doublePress', () => {
const onDoublePressMock = jest.fn();
const { getByTestId } = render(
<TouchableOpacity onDoublePress={onDoublePressMock}>
<Text testID="button-text">Click me</Text>
</TouchableOpacity>
);
fireEvent.doublePress(getByTestId('button-text'));
expect(onDoublePressMock).toHaveBeenCalled();
});
test('fireEvent.changeText', () => {
const onChangeTextMock = jest.fn();
const CHANGE_TEXT = 'content';
const { getByTestId } = render(
<View>
<TextInput testID="text-input" onChangeText={onChangeTextMock} />
</View>
);
fireEvent.changeText(getByTestId('text-input'), CHANGE_TEXT);
expect(onChangeTextMock).toHaveBeenCalledWith(CHANGE_TEXT);
});
+1 -17
View File
@@ -1,24 +1,8 @@
/* eslint-disable react/no-multi-comp */
import React from 'react';
import { View, Text, TouchableOpacity } from 'react-native'; // eslint-disable-line import/no-unresolved
import { View, Text, TouchableOpacity } from '../__mocks__/reactNativeMock';
import { render } from '..';
jest.mock(
'react-native',
() => ({
View(props) {
return props.children;
},
Text(props) {
return props.children;
},
TouchableOpacity(props) {
return props.children;
},
}),
{ virtual: true }
);
class Button extends React.Component {
render() {
return (
+68
View File
@@ -0,0 +1,68 @@
// @flow
import ErrorWithStack from './helpers/errorWithStack';
const findEventHandler = (element: ReactTestInstance, eventName: string) => {
const eventHandler = toEventHandlerName(eventName);
if (typeof element.props[eventHandler] === 'function') {
return element.props[eventHandler];
}
if (element.parent === null) {
throw new ErrorWithStack(
`No handler function found for event: ${eventName}`,
invokeEvent
);
}
return findEventHandler(element.parent, eventName);
};
const invokeEvent = (
element: ReactTestInstance,
eventName: string,
data?: *
) => {
const handler = findEventHandler(element, eventName);
return handler(data);
};
const toEventHandlerName = (eventName: string) =>
`on${eventName.charAt(0).toUpperCase()}${eventName.slice(1)}`;
const pressHandler = (element: ReactTestInstance) =>
invokeEvent(element, 'press');
const doublePressHandler = (element: ReactTestInstance) =>
invokeEvent(element, 'doublePress');
const changeTextHandler = (element: ReactTestInstance, data?: *) =>
invokeEvent(element, 'changeText', data);
const scrollHandler = (element: ReactTestInstance, data?: *) =>
invokeEvent(element, 'scroll', data);
const EVENTS = [
{
name: 'press',
handler: pressHandler,
},
{
name: 'doublePress',
handler: doublePressHandler,
},
{
name: 'changeText',
handler: changeTextHandler,
},
{
name: 'scroll',
handler: scrollHandler,
},
];
const fireEvent = invokeEvent;
EVENTS.forEach(event => {
fireEvent[event.name] = event.handler;
});
export default fireEvent;
+2
View File
@@ -3,8 +3,10 @@ import render from './render';
import shallow from './shallow';
import flushMicrotasksQueue from './flushMicrotasksQueue';
import debug from './debug';
import fireEvent from './fireEvent';
export { render };
export { shallow };
export { flushMicrotasksQueue };
export { debug };
export { fireEvent };