title: ReactJS Unit Testing - TypeError: this.props.onChange is not a function
body: <p>I am doing unit-testing on React Components with karma+jasmine involving Login. The tests always throws error </p>
  
  <pre><code>? LoginForm test &gt; ValidatedInput test &gt; should validate password
  </code></pre>
  
  <blockquote>
    <p><strong>TypeError: this.props.onChange is not a function</strong></p>
  </blockquote>
  
  <pre><code> at ValidatedInput.handleChangeValue (src/components/ValidatedInput.js:14:24)
   at node_modules/enzyme/build/ShallowWrapper.js:844:23
   at ReactDefaultBatchingStrategyTransaction.perform (node_modules/react-test-renderer/lib/shallow/Transaction.js:143:20)
   at Object.batchedUpdates (node_modules/react-test-renderer/lib/shallow/ReactDefaultBatchingStrategy.js:62:26)
   at Object.batchedUpdates (node_modules/react-test-renderer/lib/shallow/ReactUpdates.js:97:27)
   at ReactShallowRenderer.unstable_batchedUpdates (node_modules/react-test-renderer/lib/shallow/ReactShallowRenderer.js:130:25)
   at performBatchedUpdates (node_modules/enzyme/build/ShallowWrapper.js:103:21)
   at node_modules/enzyme/build/ShallowWrapper.js:843:13
   at withSetStateAllowed (node_modules/enzyme/build/Utils.js:284:3)
   at ShallowWrapper.simulate (node_modules/enzyme/build/ShallowWrapper.js:840:42)
   at Object.&lt;anonymous&gt; (src/__tests__/login-test.js:93:37)
   at Promise.resolve.then.el (node_modules/p-map/index.js:42:16)
   at process._tickCallback (internal/process/next_tick.js:109:7)
  </code></pre>
  
  <p>Following are my files:</p>
  
  <blockquote>
    <p><strong>LoginForm.js</strong> renders the component</p>
  </blockquote>
  
  <pre><code>&lt;ValidatedInput
      name={'userId'}
      type={'text'}
      title={'User ID'}
      value={this.state.userId}
      placeholder={'Enter User ID'}
      onChange={this.handleUserIdChange}
      onComponentMounted={this.handleRegisterFormFields}
      validations={/^[0-9]{5,10}$/}
      validationError={'This is not valid user Id'}
      isRequired={true}
  /&gt;
  </code></pre>
  
  <p>I have bind the <strong>handleUserIdChange</strong> in constructor and defined in the class body as</p>
  
  <pre><code>handleUserIdChange(value) {
      this.setState({ userId : value });
  }
  </code></pre>
  
  <blockquote>
    <p><strong>ValidatedInput.js</strong></p>
  </blockquote>
  
  <pre><code>import React, { Component } from 'react';
  
  class ValidatedInput extends Component {
      constructor(props) {
          super(props);
  
          this.handleChangeValue = this.handleChangeValue.bind(this);
          this.isValid = this.isValid.bind(this);
          this.validateInput = this.validateInput.bind(this);
      }
  
      /**********************************************/
      // referred function //
      handleChangeValue(e) {
          this.props.onChange(e.target.value);
          var isValidField = this.isValid(e.target);
      }
      /**********************************************/    
      isValid(input) {
          if (input.getAttribute('required') !== null &amp;&amp; input.value === "") {
              input.classList.add('Error');
              input.nextSibling.textContent = this.props.validationError;
              return false;
          } else {
              input.classList.remove('Error');
              input.nextSibling.textContent =  '';
          }
  
          if(input.value !== "") {
              if(!this.validateInput(input.value)) {
                  input.classList.add('Error');
                  input.nextSibling.textContent = this.props.validationError;
                  return false;
              } else {
                  input.classList.remove('Error');
                  input.nextSibling.textContent =  '';
              }
          }
              return true;
      }
  
      validateInput(value) {
          var regularExpressionToBeMatched = this.props.validations;
          return regularExpressionToBeMatched.test(value);
      }
  
      componentDidMount() {
          if (this.props.onComponentMounted) {
              this.props.onComponentMounted(this);
          }
      }
  
      render () {
          console.log(this.props.onChange);
          return (
              &lt;div className="form-group"&gt;
                  &lt;div className="col-5 text-center"&gt;
                      &lt;label htmlFor={this.props.name}&gt;{this.props.title}&lt;/label&gt;
                  &lt;/div&gt;
                  &lt;div className="col-5 text-center"&gt;
                      &lt;input
                          className="form-input text-center"
                          type={this.props.type}
                          ref={this.props.name}
                          name={this.props.name}
                          value={this.props.value}
                          required={this.props.isRequired}
                          placeholder={this.props.placeholder}
                          onChange={this.handleChangeValue}
                      /&gt;
                      &lt;span className='Error'&gt;&lt;/span&gt;
                  &lt;/div&gt;
              &lt;/div&gt;
          );
      }
  }
  
  export default ValidatedInput;
  </code></pre>
  
  <p>The following is the code of the test:</p>
  
  <pre><code>it('should validate userId', () =&gt; {
      const component = shallow( &lt;ValidatedInput
              name={'userId'}
              type={'text'}
              title={'User Id'}
              value={'001251623'}
              placeholder={'Enter User Id'}
              validations={/^[0-9]{5,10}$/}
              validationError={'This is not valid user Id'}
              isRequired={true}
      /&gt;);
      const handleChangeValue = spyOn(component.instance(), 'handleChangeValue');
      component.find('input').simulate('change', {target: { value: '00125' } });
      // expect(component.state().value).equals("00125");
      expect(handleChangeValue.calledWith('00125'));
  });
  </code></pre>
  
  <p>I have looked extensively in all resources. The app is working fine and <strong>console.log(this.props.onChange)</strong> in ValidatedInput says <strong>bound handleUserIdChange</strong>. Please suggest a work-around or change.
  Thanks.</p>
  
  <p><strong><em>EDIT 1</em></strong></p>
  
  <blockquote>
    <p>LoginForm.js</p>
  </blockquote>
  
  <pre><code>class LoginForm extends Component {
      constructor(props) {
          super(props);
          this.state = {
              userId : '',
              password : '',
              loginType : ['Customer', 'Payer', 'Super-User'],
              userLoggedInAs : ['Customer'],
              userType : '',
              FieldsRegister : [],
              serverMessage : '',
          }
          this.handleClearForm = this.handleClearForm.bind(this);
          this.handleSubmitForm = this.handleSubmitForm.bind(this);
          this.handleUserIdChange = this.handleUserIdChange.bind(this);
          this.handlePasswordChange = this.handlePasswordChange.bind(this);
          this.handleUserTypeChangeSelect = this.handleUserTypeChangeSelect.bind(this);
          this.handleRegisterFormFields = this.handleRegisterFormFields.bind(this);
      }
  
      handleUserIdChange(value) {
          this.setState({ userId : value });
      }
  ...
  </code></pre>
  
  <p><strong><em>EDIT 2</em></strong></p>
  
  <pre><code>it('should validate userId', () =&gt; {
              const component = shallow( &lt;ValidatedInput
                      name={'userId'}
                      type={'text'}
                      title={'User Id'}
                      value={'001251623'}
                      placeholder={'Enter User Id'}
                      validations={/^[0-9]{5,10}$/}
                      validationError={'This is not valid user Id'}
                      isRequired={true}
                      onChange={handleUserIdChange()}
              /&gt;);
              const handleChangeValue = spyOn(component.instance(), 'handleChangeValue');
              component.find('input').simulate('change', {target: { value: '00125' } });
              // expect(component.state().value).equals("00125");
              expect(handleChangeValue.calledWith('00125'));
          });
  </code></pre>