title: How to test functions in component with enzyme, jest, recompose, react
body: <p>Ok, so I'm a little stumped on how to test my component's functionality using enzyme/jest. Still learning how to test my components - I can write simple tests but now I need to make them more complex. </p>
  
  <p>I'd like to know the best way to test that my component's functions are being called properly and that they update state props as they're supposed to. What I'm finding is tricky is that my functions and state all live in my component's props.</p>
  
  <p>If I need to use a spy I'd like to preferably know how to with Jest, but if a dep like Sinon or Jasmine is better suited for the job I'm open to it (just let me know why so I can better understand).</p>
  
  <p>As an example, I have a <strong>UserDetails</strong> component</p>
  
  <pre><code>const UserDetails = ({
   userInfo,
   onUserInfoUpdate,
   className,
   error,
   title,
   primaryBtnTitle,
   submit,
   secondaryBtnTitle,
   secondaryBtnFunc,
   ...props
  }) =&gt; (
   &lt;div className={className}&gt;
     &lt;div className="user-details-body"&gt;
       &lt;Section title="User details"&gt;
         &lt;TextInput
           className="firstName"
           caption="First Name"
           value={userInfo.first}
           onChange={onUserInfoUpdate('first')}
           name="first-name"
           min="1"
           max="30"
           autoComplete="first-name"
         /&gt;
         &lt;TextInput
           className="lastName"
           caption="Last Name"
           value={userInfo.last}
           onChange={onUserInfoUpdate('last')}
           name="last-name"
           min="1"
           max="30"
           autoComplete="last-name"
         /&gt;
       &lt;/Section&gt;
     &lt;/div&gt;
  
     &lt;div className="errorBar"&gt;
       {error &amp;&amp; &lt;Alert type="danger"&gt;{error}&lt;/Alert&gt;}
     &lt;/div&gt;
  
     &lt;ActionBar&gt;
       &lt;ButtonGroup&gt;
         &lt;Button type="secondary" onClick={secondaryBtnFunc}&gt;
           {secondaryBtnTitle}
         &lt;/Button&gt;
         &lt;Button type="primary" onClick={submit}&gt;
           {primaryBtnTitle}
         &lt;/Button&gt;
       &lt;/ButtonGroup&gt;
     &lt;/ActionBar&gt;
   &lt;/div&gt;  
  </code></pre>
  
  <p><strong>TextInput</strong> consists of:</p>
  
  <pre><code>&lt;label className={className}&gt;
   {Boolean(caption) &amp;&amp; &lt;Caption&gt;{caption}&lt;/Caption&gt;}
   &lt;div className="innerContainer"&gt;
     &lt;input value={value} onChange={updateValue} type={type} {...rest} /&gt;     
   &lt;/div&gt;
  &lt;/label&gt;
  </code></pre>
  
  <p>Here is example code of my <strong>index.js</strong> file that composes my withState and withHandlers to my Component:</p>
  
  <pre><code>import UserDetails from './UserDetails'
  import { withState, withHandlers, compose } from 'recompose'
  
  export default compose(
    withState('error', 'updateError', ''),
    withState('userInfo', 'updateUserInfo', {
      first: '',
      last: '',
    }),
    withHandlers({
      onUserInfoUpdate: ({ userInfo, updateUserInfo }) =&gt; key =&gt; e =&gt; {
        e.preventDefault()
        updateCardInfo({
          ...cardInfo,
          [key]: e.target.value,
        })
      },
      submit: ({ userInfo, submitUserInfo }) =&gt; key =&gt; e =&gt; {
        e.preventDefault()
        submitUserInfo(userInfo) 
        //submitUserInfo is a graphQL mutation
        })
      }  
    }) 
  )
  </code></pre>
  
  <p>So far, my <strong>test</strong> file looks like this:</p>
  
  <pre><code>import React from 'react'
  import { mount } from 'enzyme' 
  import UserDetails from './'
  import BareUserDetails from './UserDetails'
  
  describe('UserDetails handlers', () =&gt; {
    let tree, bareTree
  
    beforeEach(() =&gt; {
      tree = mount(
        &lt;ThemeProvider theme={theme}&gt;
          &lt;UserDetails /&gt;
        &lt;/ThemeProvider&gt;
      )
      bareTree = tree.find(BareUserDetails)
    })
  
    it('finds BareUserDetails props', () =&gt; {
      console.log(bareTree.props())
      console.log(bareTree.props().userInfo)
      console.log(bareTree.find('label.firstName').find('input').props())
    })
  
  })
  </code></pre>
  
  <p>the console logs return me the right information in regards what I expect to see when I call on them:</p>
  
  <pre><code>//console.log(bareTree.props())
     { error: '',
        updateError: [Function],
        userInfo: { first: '', last: '' },
        updateUserInfo: [Function],
        onUserInfoUpdate: [Function] }
  
  //console.log(bareTree.props().userInfo)
     { first: '', last: '' }
  
  //console.log(bareTree.find('label.firstName').find('input).props()
     { value: '',
        onChange: [Function],
        type: 'text',
        name: 'first-name',
        min: '1',
        max: '30',
        autoComplete: 'first-name' }
  </code></pre>
  
  <p>Now the question is how I can use them, and the best way. Do I even use my functions or do I just check to see that onChange was called?   </p>
  
  <h2>UPDATE (sort of)</h2>
  
  <p>I've tried this and I get the following:</p>
  
  <pre><code>  it('Input element updates userInfo with name onChange in FirstName input', () =&gt; {
      const firstNameInput = bareTree.find('label.firstName').find('input)
      ccNameInput.simulate('change', {target: {value: 'John'}})
      expect(ccNameInput.prop('onChange')).toHaveBeenCalled()
    })
  </code></pre>
  
  <p>In my terminal I get:</p>
  
  <pre><code> expect(jest.fn())[.not].toHaveBeenCalled()
  
      jest.fn() value must be a mock function or spy.
      Received:
        function: [Function anonymous]
  </code></pre>
  
  <p>If I try and create a spyOn with Jest, however, I get an error that it cannot read the function of 'undefined'.</p>
  
  <p>I've tried <code>spy = jest.spyOn(UserDetails.prototypes, 'onUpdateUserInfo')</code> and <code>spy = jest.spyOn(BareUserDetails.prototypes, 'onUpdateUserInfo')</code> and they both throw the error.</p>