title: How to test component using spyFn in React Jest
body: <p>I want to test my component Actions when I pass actions to children. In a nutshell, every source like twitter or facebook has its own set of actions. I'd like to check that it is called or not using spy.</p>
  <p>This is my Actions component</p>
  <pre><code>const targetMetric = 'account dropdown'
  
  const availableActions = {
      addQuery: {
          facebook: '^facebook://page/',
          twitter: true
      },
      exclude: {
          blog: [
              '^blog://user/eventregistry/',
              '^eventregistry://user/'
          ],
          news: [
              '^news://user/eventregistry/',
              '^eventregistry://user/'
          ],
          twitter: true,
          youtube: true
      },
      reportAsNews: {
          youtube: true,
          mastodon: true,
          twitter: true
      }
  }
  
  const requiredHandlers = {
      exclude: [
          'onExcludeProfile'
      ],
      reportAsNews: [
          'onReportAsNews'
      ]
  }
  class Actions extends React.PureComponent {
  
      get actions() {
          const { account, handlers } = this.props
          const actions = {};
  
          Object.keys(availableActions).forEach(key =&gt;
              actions[ key ] = false
          )
  
          Object.keys(actions).forEach(key =&gt; {
              const value = (
                  !!account.uri
                  &amp;&amp;
                  availableActions[ key ][ account.type ]
              )
  
              if (!value) {
                  return
              }
  
              if (typeof value === 'boolean') {
                  actions[ key ] = value
                  return
              }
  
              if (typeof value === 'string') {
                  const re = new RegExp(value, 'i')
                  actions[ key ] = re.test(account.uri)
  
                  return
              }
  
              if (
                  typeof value === 'object'
                  &amp;&amp;
                  Array.isArray(value)
              ) {
                  actions[ key ] = value.some(v =&gt; {
                      const re = new RegExp(v, 'i')
                      return re.test(account.uri)
                  })
              }
          })
  
          Object.keys(actions).forEach(key =&gt; {
              if (!actions[ key ] || !requiredHandlers[ key ]) {
                  return
              }
  
              actions[ key ] = requiredHandlers[ key ].some(i =&gt; handlers[ i ])
          })
  
          if (actions.addQuery) {
              actions.addQuery = Object
                  .keys(this.addQueryActions)
                  .some(key =&gt; this.addQueryActions[ key ])
          }
  
          return actions
      }
  
      get addQueryActions() {
          const { availableLanguages = [], userIsAdmin } = this.context
          const { caseItem, handlers } = this.props
  
          const actions = {
              addQueryToFilter: !caseItem.isPaused &amp;&amp; !!handlers.onAddQuery,
              addQueryToAccountList: userIsAdmin &amp;&amp; !!handlers.onAddToAccountList
          }
  
          actions.addQueryToSearch = actions.addQueryToFilter &amp;&amp; !!availableLanguages.length
  
          return actions
      }
  
      get actor() {
          return pick(
              this.props.account,
              [ 'uri', 'name', 'link' ]
          )
      }
  
      onExclude = () =&gt; {
          const { account, handlers, isCaseLocked } = this.props
  
          if (isCaseLocked) {
              return
          }
  
          handlers.onExcludeProfile(account)
      }
  
      onReportAsNews = () =&gt; this.props.handlers.onReportAsNews(this.actor)
  
      onAddToAccountList = () =&gt; {
          const { account, from, handlers } = this.props
  
          handlers.onAddToAccountList(account, from)
      }
  
      onAddToQuery = type =&gt; ({ language } = {}) =&gt; {
          const { account, caseItem, handlers } = this.props
          const { id } = caseItem
          const metrics = {
              index: getId(),
              language,
              type
          }
  
          handlers.onAddQuery({
              ...metrics,
              expression: this.expressionFromAccount(account),
              hideSearch: true,
              id,
          })
  
          return metrics
      }
  
      expressionFromAccount = account =&gt; ({
          and: [
              { account }
          ]
      })
  
      trackExcludeEvent = () =&gt; {
          const { account } = this.props
  
          this.trackEvent(
              events.excludeAccounts,
              {
                  accountsAdded: 1,
                  source: account.type
              }
          )
      }
  
      trackCreateNewQueryEvent = ({ index, language, type }) =&gt; {
          const eventNameMap = {
              filters: events.createNewFilter,
              queries: events.createNewSearch,
          }
  
          const metrics = {
              queryId: index,
              target: targetMetric
          }
  
          if (type === 'queries') {
              metrics[ 'language' ] = language.toLowerCase()
          }
  
          this.trackEvent(
              eventNameMap[ type ],
              metrics
          )
      }
  
      trackReportAsNewsEvent = () =&gt; (
          this.trackEvent(
              events.reportAsNews,
              { source: this.props.account.type }
          )
      )
  
      trackEvent = (eventName, props = {}) =&gt; {
          const { from, message } = this.props
  
          eventTracker.track(
              eventName,
              {
                  ...props,
                  from,
                  messageUri: message.uri
              }
          )
      }
  
      getLangMenuActions = ({ handlers, isCaseLocked }, { availableLanguages }) =&gt; {
          if (
              isCaseLocked
              ||
              !availableLanguages
              ||
              !handlers.onAddQuery
          ) {
              return []
          }
  
          const onClick = compose(
              this.trackCreateNewQueryEvent,
              this.onAddToQuery('queries')
          )
  
          return availableLanguages.map(({ label, value: language }) =&gt; ({
              handler: onClick.bind(this, { language }),
              id: `add-account-to-search-lang-${language}`,
              label
          }))
      }
  
      getActions = () =&gt; {
          const { isCaseLocked } = this.props
          const { userIsAdmin } = this.context
  
          const actions = []
  
          if (this.actions.addQuery) {
              const addQueryAction = {
                  id: 'add-account-to',
                  isInactive: isCaseLocked &amp;&amp; !userIsAdmin,
                  label: i18n.t('SOURCES.DROPDOWN_ADD_TO'),
                  children: []
              }
  
              if (this.addQueryActions.addQueryToSearch) {
                  addQueryAction.children.push({
                      id: 'add-account-to-search',
                      isInactive: isCaseLocked,
                      label: i18n.t('SOURCES.DROPDOWN_NEW_SEARCH'),
                      children: this.getLangMenuActions(this.props, this.context)
                  })
              }
  
              if (this.addQueryActions.addQueryToFilter) {
                  addQueryAction.children.push({
                      handler: compose(
                          this.trackCreateNewQueryEvent,
                          this.onAddToQuery('filters')
                      ),
                      id: 'add-account-to-filter',
                      isInactive: isCaseLocked,
                      label: i18n.t('SOURCES.DROPDOWN_NEW_FILTER')
                  })
              }
  
              if (this.addQueryActions.addQueryToAccountList) {
                  addQueryAction.children.push({
                      handler: this.onAddToAccountList,
                      id: 'add-account-to-account-list',
                      label: i18n.t('SOURCES.DROPDOWN_ACCOUNT_LIST')
                  })
              }
  
              actions.push(addQueryAction)
          }
  
          if (this.actions.reportAsNews) {
              actions.push({
                  handler: compose(
                      this.onReportAsNews,
                      this.trackReportAsNewsEvent
                  ),
                  id: 'report-as-news',
                  label: i18n.t('SOURCES.DROPDOWN_REPORT_AS_NEWS')
              })
          }
  
          if (this.actions.exclude) {
              actions.push({
                  handler: compose(
                      this.onExclude,
                      this.trackExcludeEvent
                  ),
                  id: 'exclude-account',
                  isInactive: isCaseLocked,
                  label: i18n.t('SOURCES.DROPDOWN_EXCLUDE')
              })
          }
  
          console.log(actions)
  
          return actions
      }
  
      render() {
          return this.props.children({
              actions: this.getActions()
          })
      }
  }
  </code></pre>
  <p>This is my test file</p>
  <pre><code>import expect from 'expect'
  
  const injectActions = require('inject-loader!./actions')
  
  const Actions = injectActions({
      'cm/common/event-tracker': {
          eventTracker: {
              track: () =&gt; {},
              clear: () =&gt; {}
          },
          events: {
              createNewFilter: '...',
              createNewSearch: '...',
              excludeAccounts: '...',
              reportAsNews: '...',
          }
      },
  }).default
  
  const handlers = {
      onAddQuery: () =&gt; { },
      onAddToAccountList: () =&gt; { },
      onExcludeProfile: () =&gt; { },
      onReportAsNews: () =&gt; { }
  }
  
  const testProps = {
      twitter: {
          account: {
              name: 'Twitter account',
              uri: 'twitter://status/12345',
              type: 'twitter'
          },
          handlers,
      },
      facebookPage: {
          account: {
              name: 'Facebook page account',
              uri: 'facebook://page/12345',
              type: 'facebook'
          },
          handlers
      }
  }
  
  describe('Actions component', () =&gt; {
      let node
  
      beforeEach(() =&gt; {
          node = document.createElement('div')
      })
  
      afterEach(() =&gt; {
          ReactDOM.unmountComponentAtNode(node)
      })
  
      it('returns empty actions array by default', () =&gt; {
          const spyFn = expect.createSpy().andReturn(null)
  
          ReactDOM.render(
              &lt;Actions&gt;{spyFn}&lt;/Actions&gt;,
              node
          )
  
          expect(spyFn).toHaveBeenCalledWith({ actions: [] })
      })
  
  
      describe('Twitter', () =&gt; {
          it('returns &quot;Exclude&quot; action', () =&gt; {
              const { account, handlers } = testProps.twitter
              const spyFn = expect.createSpy()
  
              ReactDOM.render(
                  &lt;Actions
                      account={account}
                      handlers={{
                          onExcludeProfile: handlers.onExcludeProfile
                      }}
                      isCaseLocked={false}
                  &gt;
                      {spyFn}
                  &lt;/Actions&gt;,
                  node
              )
  
              expect(spyFn).toHaveBeenCalledWith({ actions: [
                  {
                      handler: () =&gt; {},
                      id: 'exclude-account',
                      isInactive: false,
                      label: 'Exclude',
                  }
              ] })
          })
  })
  </code></pre>
  <p>First unit case works fine, but the second is wrong. Actually I don't need all object there too. I'd like to be only sure that it contains <code>id: 'exclude-account'</code> there.</p>
  <p>Please guys about any help.</p>