React-native-testing-library: No handler function found for event: "changeText" in custom component

Created on 7 Jul 2020  路  2Comments  路  Source: callstack/react-native-testing-library

Component

Here I have a component named <TextInput />:

import React, { memo, useCallback, useState } from 'react';
import { View, TextInput as Input, Text } from 'react-native';
import PropTypes from 'prop-types';

import { COLORS } from '@Styles';
import { styles } from './styles';

const TextInput = memo(({ name, form, error = '', ...props }) => {
  const [ focus, setFocus ] = useState(false);

  const toggleFocus = useCallback((isFocus) => {
    setFocus(isFocus);
    form && form.handleBlur(name);
  });

  return (
    <View style={styles.inputBox}>
      <Input
        style={[
          styles.input,
          props.multiline && styles.multiline,
          (props.editable === false) && styles.disable,
          error && styles.error,
          focus && styles.focus
        ]}
        value={form && form.values[name]}
        onFocus={() => toggleFocus(true)}
        onBlur={() => toggleFocus(false)}
        onChangeText={form && form.handleChange(name)}
        underlineColorAndroid="transparent"
        placeholderTextColor={COLORS.INPUT.PLACEHOLDER}
        {...props}
      />
    </View>
  );
});

TextInput.propTypes = {
  name: PropTypes.string.isRequired,
  form: PropTypes.object.isRequired
};

export default TextInput;

Test

Then I create a test like below:

import React from 'react';
import chalk from 'chalk';
import { render, fireEvent } from 'react-native-testing-library';
import TextInput from '@Components/TextInput';

describe(chalk.bgCyan.black('@Component - TextInput'), () => {
  describe(chalk.bgGreen.black('### functionality'), () => {
    it('textInput values can be changed', () => {
      let form = { touched: {}, errors: {}, values: {}, handleChange: jest.fn() };

      const { getByPlaceholder } = render(<TextInput name="test" form={form} placeholder="Hey" />);
      fireEvent.changeText(getByPlaceholder('Hey'), 'Hello');
      expect(form.handleChange).toHaveBeenCalled();
    });
  });
});

Actual Result

It leads to the error below:

No handler function found for event: "changeText"

    46 |       const { getByPlaceholder } = render(<TextInput name="test" form={form} placeholder="Hey" />);
    47 |       console.log(getByPlaceholder('Hey'));
  > 48 |       fireEvent.changeText(getByPlaceholder('Hey'), 'Hello');
       |                 ^
    49 |       expect(form.handleChange).toHaveBeenCalled();
    50 |     });
    51 |   });

System Version

"devDependencies": {
    "@babel/core": "7.9.0",
    "@babel/runtime": "7.9.2",
    "@react-native-community/eslint-config": "1.1.0",
    "@testing-library/jest-native": "3.1.0",
    "babel-jest": "25.5.0",
    "eslint": "6.8.0",
    "jest": "25.5.0",
    "metro-react-native-babel-preset": "0.59.0",
    "react-native-testing-library": "1.14.0",
    "react-test-renderer": "16.11.0"
},

Debug

I have tried to add console.log(getByPlaceholder('Hey')); and here is the element got:

ReactTestInstance {
  _fiber: <ref *1> FiberNode {
    tag: 1,
    key: null,
    elementType: [Function: Component] {
      displayName: 'Component',
      '$$typeof': Symbol(react.forward_ref),
      render: [Function: TextInput],
      defaultProps: [Object],
      propTypes: [Object],
      State: [Object]
    },
    type: [Function: Component] {
      displayName: 'Component',
      '$$typeof': Symbol(react.forward_ref),
      render: [Function: TextInput],
      defaultProps: [Object],
      propTypes: [Object],
      State: [Object]
    },
    stateNode: Component {
      props: [Object],
      context: {},
      refs: {},
      updater: [Object],
      _reactInternalFiber: [Circular *1],
      _reactInternalInstance: {},
      state: null
    },
    return: FiberNode {
      tag: 5,
      key: null,
      elementType: 'View',
      type: 'View',
      stateNode: [Object],
      return: [FiberNode],
      child: [Circular *1],
      sibling: null,
      index: 0,
      ref: null,
      pendingProps: [Object],
      memoizedProps: [Object],
      updateQueue: null,
      memoizedState: null,
      dependencies: null,
      mode: 0,
      effectTag: 0,
      nextEffect: null,
      firstEffect: null,
      lastEffect: null,
      expirationTime: 0,
      childExpirationTime: 0,
      alternate: null,
      actualDuration: 0,
      actualStartTime: -1,
      selfBaseDuration: 0,
      treeBaseDuration: 0,
      _debugID: 40,
      _debugIsCurrentlyTiming: false,
      _debugSource: null,
      _debugOwner: [FiberNode],
      _debugNeedsRemount: false,
      _debugHookTypes: null
    },
    child: FiberNode {
      tag: 5,
      key: null,
      elementType: 'TextInput',
      type: 'TextInput',
      stateNode: [Object],
      return: [Circular *1],
      child: null,
      sibling: null,
      index: 0,
      ref: null,
      pendingProps: [Object],
      memoizedProps: [Object],
      updateQueue: null,
      memoizedState: null,
      dependencies: null,
      mode: 0,
      effectTag: 0,
      nextEffect: null,
      firstEffect: null,
      lastEffect: null,
      expirationTime: 0,
      childExpirationTime: 0,
      alternate: null,
      actualDuration: 0,
      actualStartTime: -1,
      selfBaseDuration: 0,
      treeBaseDuration: 0,
      _debugID: 42,
      _debugIsCurrentlyTiming: false,
      _debugSource: null,
      _debugOwner: [Circular *1],
      _debugNeedsRemount: false,
      _debugHookTypes: null
    },
    sibling: null,
    index: 0,
    ref: null,
    pendingProps: {
      style: [Array],
      value: undefined,
      onFocus: [Function: onFocus],
      onBlur: [Function: onBlur],
      onChangeText: undefined,
      underlineColorAndroid: 'transparent',
      placeholderTextColor: '#aaa',
      placeholder: 'Hey',
      allowFontScaling: true,
      rejectResponderTermination: true
    },
    memoizedProps: {
      style: [Array],
      value: undefined,
      onFocus: [Function: onFocus],
      onBlur: [Function: onBlur],
      onChangeText: undefined,
      underlineColorAndroid: 'transparent',
      placeholderTextColor: '#aaa',
      placeholder: 'Hey',
      allowFontScaling: true,
      rejectResponderTermination: true
    },
    updateQueue: null,
    memoizedState: null,
    dependencies: null,
    mode: 0,
    effectTag: 1,
    nextEffect: null,
    firstEffect: null,
    lastEffect: null,
    expirationTime: 0,
    childExpirationTime: 0,
    alternate: null,
    actualDuration: 0,
    actualStartTime: -1,
    selfBaseDuration: 0,
    treeBaseDuration: 0,
    _debugID: 41,
    _debugIsCurrentlyTiming: false,
    _debugSource: null,
    _debugOwner: FiberNode {
      tag: 15,
      key: null,
      elementType: [Object],
      type: [Function (anonymous)],
      stateNode: null,
      return: [FiberNode],
      child: [FiberNode],
      sibling: null,
      index: 0,
      ref: null,
      pendingProps: [Object],
      memoizedProps: [Object],
      updateQueue: null,
      memoizedState: [Object],
      dependencies: null,
      mode: 0,
      effectTag: 1,
      nextEffect: null,
      firstEffect: null,
      lastEffect: null,
      expirationTime: 0,
      childExpirationTime: 0,
      alternate: null,
      actualDuration: 0,
      actualStartTime: -1,
      selfBaseDuration: 0,
      treeBaseDuration: 0,
      _debugID: 38,
      _debugIsCurrentlyTiming: false,
      _debugSource: null,
      _debugOwner: null,
      _debugNeedsRemount: false,
      _debugHookTypes: [Array]
    },
    _debugNeedsRemount: false,
    _debugHookTypes: null
  }
}

Does anyone have ideas on how to solve this? Thanks.

question

Most helpful comment

Are there any plans to allow fireEvent.changeText to trigger both onChange and onChangeText? Since React Native's TextInput allows for both an onChange: (event) prop and an onChangeText: (string) prop to be used somewhat interchangeably, it would be nice to have fireEvent.changeText trigger both callbacks. Alternatively, pointing this out in the documentation or having the No handler function found for event: "changeText" provide more descriptive information on how to resolve the error would be wonderful

All 2 comments

render(<TextInput name="test" form={form} placeholder="Hey" />)

There's no onChangeText implemented, hence there's no handler to call and you see the error. It's an expected behavior, you have to implement onChangeText.

Are there any plans to allow fireEvent.changeText to trigger both onChange and onChangeText? Since React Native's TextInput allows for both an onChange: (event) prop and an onChangeText: (string) prop to be used somewhat interchangeably, it would be nice to have fireEvent.changeText trigger both callbacks. Alternatively, pointing this out in the documentation or having the No handler function found for event: "changeText" provide more descriptive information on how to resolve the error would be wonderful

Was this page helpful?
0 / 5 - 0 ratings

Related issues

entiendoNull picture entiendoNull  路  6Comments

CodingItWrong picture CodingItWrong  路  4Comments

dephiros picture dephiros  路  5Comments

deepakaggarwal7 picture deepakaggarwal7  路  3Comments

jonmchan picture jonmchan  路  11Comments