Leon Gaban
Leon Gaban

Reputation: 39034

Need help getting 1 line covered with Jest (React)

This is the function I'm covering, however npm run coverage is still complaining that I don't have the 4th line before covered.

export const CardContainer = ({ index, icon, copy, click }) => (
    <BlankCard variant="light" title={copy}>{icon}<p>{copy}</p>
        {click && <a className="tile-learn-more" id={`tile-id-${index}`} onClick={() => click(index)}>Learn More</a>}
    </BlankCard>
);

The line in question:

{click && <a className="tile-learn-more" id={`tile-id-${index}`} onClick={() => click(index)}>Learn More</a>}
describe('CardContainer component', () => {
    it('will contain BlankCard component', () => {
        const props = { icon: 'icon', copy: 'foo' };
        const wrapperBlankCard = shallow(<CardContainer {...props} />);
        const blankCard = wrapperBlankCard.find('BlankCard');
        expect(blankCard).toHaveLength(1);
        expect(blankCard.at(0).prop('variant')).toEqual('light');
        expect(blankCard.at(0).prop('title')).toEqual('foo');
    });

    it('will contain a Learn More link if click contains a function', () => {
        const mockOnClick = jest.fn();
        const props = { index: 1, icon: 'icon', copy: 'foo', click: mockOnClick };
        const wrapper = shallow(<CardContainer {...props} />);
        const learnMore = wrapper.find('.tile-learn-more');
        expect(learnMore).toEqual({});
        expect(learnMore.prop('id')).toEqual('tile-id-1');
        expect(learnMore.contains('Learn More'));
        expect(learnMore.prop('onClick')).toEqual(expect.any(Function));
    });

    it('will not contain a Learn More link if click is undefined', () => {
        const props = { icon: 'icon', copy: 'foo', click: null };
        const wrapper = shallow(<CardContainer {...props} />);
        expect(wrapper.find('.tile-learn-more')).toEqual({});
    });
});

I'm testing for different states of the click prop, however so far unable to get the line covered, any thoughts here?

Upvotes: 2

Views: 64

Answers (1)

jonrsharpe
jonrsharpe

Reputation: 122090

If you refactor slightly, you can see which line doesn't get called:

export const CardContainer = ({ index, icon, copy, click }) => (
  <BlankCard variant="light" title={copy}>{icon}<p>{copy}</p>
      {click && <a className="tile-learn-more" id={`tile-id-${index}`} onClick={() => {
        click(index);  // this one!
      }}>Learn More</a>}
  </BlankCard>
);

That line isn't covered because the onClick callback is never actually invoked.

Also, just testing that any function is bound to it isn't very useful - binding to a no-op like onClick={() => {}}, or even to the wrong function, would still pass. This is also testing the implementation, not the behaviour.

Instead, simulate the click and make sure the mock gets called:

it('will do the right thing when the Learn More link is clicked', () => {
    const mockOnClick = jest.fn();
    const index = 1;
    const props = { index, icon: 'icon', copy: 'foo', click: mockOnClick };
    const wrapper = shallow(<CardContainer {...props} />);

    wrapper.find('.tile-learn-more').simulate('click');

    expect(mockOnClick).toHaveBeenCalledWith(index);
});

Upvotes: 1

Related Questions