bigpotato
bigpotato

Reputation: 27557

Jest: How to test prop that is an anonymous function?

I have a component that loads another component, sending it an anonymous function as a prop:

export class Header extends Component {
  constructor(props) {
    super(props)
    this.state = { activeTab: TAB_NAMES.NEEDS_REVIEW }
  }

  filterByNeedsReview() {
    const { filterByNeedsReviewFn } = this.props
    this.setState({ activeTab: TAB_NAMES.NEEDS_REVIEW })
    filterByNeedsReviewFn()
  }

 ...

  render() {
    return (
      <Container>
        ...
        ...
          <FilterTab
            active={this.state.activeTab === TAB_NAMES.NEEDS_REVIEW}
            name={TAB_NAMES.NEEDS_REVIEW}
            count={40}
            onClick={() => this.filterByNeedsReview()}
          />
          ...
        ...
      </Container>
    )
  }
}

I have this failing test:

  it('renders a filter tab with the right props for needs review', () => {
    const filterByNeedsReviewFn = jest.fn()
    expect(
      shallowRender({ filterByNeedsReviewFn })
        .find(FilterTab)
        .findWhere(node =>
          _.isMatch(node.props(), {
            active: true,
            name: 'Needs Review',
            count: 40,
            onClick: filterByNeedsReviewFn, //<-------------- THIS DOESN'T WORK
          })
        )
    ).toHaveLength(1)
  })

How would I test that onClick is the right thing?

Upvotes: 0

Views: 3138

Answers (1)

skyboyer
skyboyer

Reputation: 23763

I believe you don't need to check how internal event handlers look like. You might be interested in different things: if triggering event handler changes component as you expect(.toMatchSnapshot() is much better here instead of testing structure manually with .toHaveLength) and if callback you've passed through props is called when it should to(.toHaveBeenCalled). What if component is changed some day not to just call .props.filterByNeedsReviewFn() but also do some stuff like calling anything else? should your test fail just because there is named method passed somewhere inside? I believe it is not.

So I see your test to be

it('renders a filter tab with expected props after clicking', () => {
    const comp = shallowRender({});
    comp.find(FilterTab).simulate('click');
    expect(comp).toMatchSnapshot();
});

it('calls callback passed after clicking on filter tab', () => {
    const filterByNeedsReviewFn = jest.fn()
    const comp = shallowRender({ filterByNeedsReviewFn });
    comp.find(FilterTab).simulate('click');
    // let's ensure callback has been called without any unexpected arguments
    expect(filterByNeedsReviewFn ).toHaveBeenCalledWith(); 
});

I don't think you actually needed this code but I wanted to illustrate how clear such approach could be. Your component have API: props callback it calls and render output. So we can skip testing internals without any pitfalls

Upvotes: 1

Related Questions