vue-test-utils: @click event cannot be tested with a find-trigger function in Jest

Version

1.0.0-beta.19

Reproduction link

https://codesandbox.io/s/2vlyrzkm1p

Steps to reproduce

The next test in jest does not work with the code in the example:

it('calls the toggleVisibility method when clicking', () => {
    wrapper = shallowMount(App)
    wrapper.vm.toggleVisibility = jest.fn()

    wrapper
      .find('.unread-messages')
      .trigger('click')

    expect(wrapper.vm.toggleVisibility).toHaveBeenCalledTimes(1)
  })

Only if click is changed click.self does the test work, but in that case no component inside can be clicked (and that’s what I want to achieve)

What is expected?

The test pass whether click or click.self is wrote.

What is actually happening?

The test fails.


A console.log of the wrapper shows that it has the class in the wrapper, so it should be found and triggered.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 40 (13 by maintainers)

Most upvoted comments

@TheoSl93 I pulled your repo and got it working. You can use setMethods, then your test passes.

  it('calls the toggleVisibility method when the icon is clicked', () => {
    wrapper.setMethods({ toggleVisibility:jest.fn() })

    wrapper
      .find('.unread-messages')
      .trigger('click')

    expect(wrapper.vm.toggleVisibility).toHaveBeenCalledTimes(1)
  })

If you shallowMount and if you’re button comes from a framework, then it is stubbed and the click action is not accessible.

I have a similar problem. I don’t understand why my cancelAlert() method is not called in tests… The strangest thing is that the code inside the function is executed… 1 2 3 4 Please, advice. @eddyerburgh

setMethods updates the instance, which re render vnodes (and ultimately Elements) to use the new method in their on handlers.

I’m going to close this issue, since we aren’t able to change this behavior in Vue Test Utils.

The recommended way to set a method is to use setMethods

Ok thanks to this answer on Stack Overflow I’ve found how to mock the method before mounting:

mock + mount

const testFunctionSpy = jest.spyOn(Component.methods, 'testFunction');
const wrapper = shallowMount(Component);

In this way I can test that the function is called even without the parentheses.

spec

expect(testFunctionSpy).toHaveBeenCalled();

template

<button class="btn blue-empty-btn btn-discard" @click="testFunction">
  {{ sysDizVal('remove') }}
</button>

You probably need to add parentheses to the event handler on the child component. For example when testing from a parent component that a child emits an event and calls the appropriate function…

This works:

<MainTopbar @account="handleTopbarAccountClick()" />

This does not:

<MainTopbar @account="handleTopbarAccountClick" />

Good day, I am have issue testing click on my application, I have tried all the methods mention here; none is working . Please can anyone provide me an example to follow, I will really appreciate Thanks.

Note: merge is likely from the lodash library. It is not part of VTU.

According to the docs, the official way to mock a method is:

wrapper.setMethods({ clickMethod: clickMethodStub })

But in the same docs they say that it is deprecated.

Anyway, if I test he function mocking it like this:

wrapper.vm.testFunction = jest.fn();

or like this:

wrapper.setMethods({ testFunction: jest.fn() });`

the issue is still the same: my test succeeds if the method is called in the template with the parenthesis, otherwise it fails.

Official syntax (deprecated), with parenthesis in the template Schermata 2020-07-02 alle 12 05 52

Official syntax (deprecated), without parenthesis in the template Schermata 2020-07-02 alle 12 10 35

Luckily I already had a test in which a click event was triggered, and I was able to understand the very subtle difference between tests passing and tests failing: it’s the parenthesis in the function call.

So basically the very same test:

test('Click calls the right function', () => {
    // wrapper is declared before this test and initialized inside the beforeEach
    wrapper.vm.testFunction = jest.fn();
    const $btnDiscard = wrapper.find('.btn-discard');
    $btnDiscard.trigger('click');
    expect(wrapper.vm.testFunction).toHaveBeenCalled();
});

was failing with this template:

<button class="btn blue-empty-btn btn-discard" @click="testFunction">
  {{ sysDizVal('remove') }}
</button>

while it passed with this subtle change:

<button class="btn blue-empty-btn btn-discard" @click="testFunction()">
  {{ sysDizVal('remove') }}
</button>

I’ve seen that in the original post the parenthesis were missing, so I assume this answers the question.

I hope this behavior will be fixed in future releases because the syntax without parenthesis is somehow encouraged in all the docs I have seen.

Hope this helps.