5

I am trying to test onClick of a span tag of a react component.

<span id="A" onClick={this.changeImage}> Image A</span>

Want to test if 'onClick' the 'changeImage' function is being called or not!

// test.js

describe('Tests', () => {
const wrapper = shallow(<Image />);
it('Should render without exploading', () => {
    expect(wrapper).toHaveLength(1);
});

it('Should call changeImage() function on click', () => {
    wrapper.instance().changeImage = jest.fn();
    wrapper.update();
    wrapper.find('#A').simulate('click', { target: { id: 'A' } });
    expect(wrapper.instance().changeImage).toHaveBeenCalled();
    });
});

Also tried this -

it('Should call changeImage() function on click', () => {
    const spy = jest.spyOn(wrapper.instance(), 'changeImage');
    wrapper.find('#A').simulate('click', { target: { id: 'A' } });
    expect(spy).toHaveBeenCalled();
});

Both returning the same error. // Error

● Tests › Should call changeImage() function on click

expect(jest.fn()).toHaveBeenCalled()

Expected mock function to have been called.

Can someone please point out what am I doing wrong? Thanks.

doelleri
  • 19,232
  • 5
  • 61
  • 65
remelkabir
  • 366
  • 1
  • 4
  • 11
  • Possible duplicate of [Using Jest to spy on method call in componentDidMount](https://stackoverflow.com/questions/43245040/using-jest-to-spy-on-method-call-in-componentdidmount) – Oluwafemi Sule Dec 12 '17 at 14:55
  • @OluwafemiSule Thanks, figured out What I was doing wrong from that link. :) – remelkabir Dec 13 '17 at 16:25
  • Can you try storing a reference to `wrapper.instance()` instead of calling it multiple times to see if it fixes the problem? I'm wondering if you're getting a new instance every time – Ruan Mendes Dec 15 '17 at 20:30

1 Answers1

2

// fixed mistake

describe('Tests', () => {
it('Should render without exploading', () => {
    const wrapper = shallow(<Image />);
    expect(wrapper).toHaveLength(1);
});

it('Should call changeImage() function on click', () => {
    const spy = jest.spyOn(Image.prototype, 'changeImage');
    const wrapper = shallow(<Image/>);
    wrapper.find('#A').simulate('click', { target: { id: 'A' } });
    expect(spy).toHaveBeenCalled();
    spy.mockClear();//clearing the mock functions
    });    
 });

Putting the wrapper after the jest.spyOn() mock function made the test work.

In the case of mocking function the order of declaring const matters. Spy needs to be declared first then the wrapper. Declaring wrapper before spy will cause this error:

expect(jest.fn()).toHaveBeenCalled()

Expected mock function to have been called.
remelkabir
  • 366
  • 1
  • 4
  • 11
  • - 1 Please explain what the problem was instead of just pasting code that works (why did making moving code after wrapper work?). That way, your answer can be more helpful to others. – Ruan Mendes Dec 15 '17 at 20:15
  • This is not a good test because it will give you a false positive if another instance of your object calls `changeImage` since you are spying on the shared prototype method. – Ruan Mendes Dec 15 '17 at 20:18
  • @JuanMendes you're right. You need to clear the mock function in order to use it correctly with other instances. :) I have edited my answer. Thanks for pointing it out. – remelkabir Dec 15 '17 at 20:24
  • What you are suggesting will work around the problem instead of fixing it (there could be some unintended consequence of your code where a new instance does call `changeImage` before you call `mockClear`, as unlikely as it may be, it's just a sign that you could be testing it better. You should be spying on the object, not the prototype. I realize I don't have a good answer for you, just letting you know that this is not quite up to par. – Ruan Mendes Dec 15 '17 at 20:27
  • I tried spying on the object but I couldn't figure it out, this is the only thing that worked for me. Let me know if you find better ways to do it. :) – remelkabir Dec 15 '17 at 20:31
  • I did suggest something to try in the comments, please try it out and respond. – Ruan Mendes Dec 15 '17 at 20:37