Reputation: 27557
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
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