9

I have a Vue component with a button. On a button click, a method is called. I am using Jest for unit test. I expected .trigger method from vue-test-utils to create a synthetic event on the button, but it does nothing.

I tried calling the method directly on the wrapper by calling wrapper.vm.addService() and then using console.log(wrapper.emitted()), I indeed can see an event has been triggered. So my question is why the addServiceBtn.trigger('click') does not do anything.

The console.log(wrapper.emitted()) is an empty object. The test result is failed with error message: Expected spy to have been called, but it was not called.

ServiceItem.vue

<template>
  <v-flex xs2>
    <v-card>
      <v-card-text id="itemTitle">{{ item.title }}</v-card-text>
      <v-card-actions>
        <v-btn flat color="green" id="addServiceBtn" @click="this.addService">Add</v-btn>
      </v-card-actions>
    </v-card>
  </v-flex>
</template>

<script>
export default {
  data: () => ({
    title: ''
  }),
  props: {
    item: Object
  },
  methods: {
    addService: function (event) {
      console.log('service item')
      this.$emit('add-service')
    }
  }
}
</script>

tests.spec.js

import { shallowMount, mount } from '@vue/test-utils'
import ServiceItem from '@/components/ServiceItem.vue'
import Vue from 'vue';
import Vuetify from 'vuetify';

Vue.use(Vuetify);

describe('ServiceItem.vue', () => {
  it('emits add-service when Add button is clicked', () => {
    const item = {
      title: 'Service'
    }

    const wrapper = mount(ServiceItem, {
      propsData: { item }
    })

    expect(wrapper.find('#addServiceBtn').exists()).toBe(true)
    const addServiceBtn = wrapper.find('#addServiceBtn')

    const spy = spyOn(wrapper.vm, 'addService')

    console.log(wrapper.emitted())
    addServiceBtn.trigger('click')
    expect(wrapper.vm.addService).toBeCalled()

  })
})
Billal Begueradj
  • 20,717
  • 43
  • 112
  • 130
Payam Mesgari
  • 953
  • 1
  • 19
  • 38

4 Answers4

5

You got a little mistake in your HTML code. Your bind the @click event to your method without any this. make it:

 <v-btn flat color="green" id="addServiceBtn" @click="addService($event)">Add</v-btn>
Billal Begueradj
  • 20,717
  • 43
  • 112
  • 130
Efrat Levitan
  • 5,181
  • 2
  • 19
  • 40
  • Thanks! Would you care to explain why `this.addService` was not working? – Payam Mesgari Nov 27 '18 at 11:41
  • 2
    @PayamMesgari Because in vue templates all the properties and variables are implicitly using this, so you don't need to add there when you bind something like this @click="method" vue converts this template to on: { click: _vm.controlChanged } in this case _vm is this – David Torroija May 14 '20 at 15:46
4

Actually there is another reason why the tests in the original code didn't work: it's the parenthesis in the function call. I have discovered that the syntax @click="addService" will lead to failing tests, while the very similar (and somehow discouraged) syntax @click="addService()" will succeed.

Example:

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();
});

This test was failing with this syntax:

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

but worked with this syntax:

<button class="btn blue-empty-btn btn-discard" @click="testFunction()">
  {{ sysDizVal('remove') }}
</button>
Giorgio Tempesta
  • 1,816
  • 24
  • 32
  • Actually after investigating the issue I have posted a similar question, and in the accepted answer you can find some explanation on how to test without adding the parenthesis https://stackoverflow.com/questions/62696939/test-on-function-call-in-vue-template-only-passes-if-the-function-is-called-with – Giorgio Tempesta May 07 '21 at 20:45
2

To me it didn work, but failed firing the event when testing with vue-test-utils until I added .native

<v-btn @click.native="addToCart($event)">
      Add
</v-btn>

Despertaweb
  • 1,672
  • 21
  • 29
1

the reason why it didn't work is because this.addService in <template> u're recommended to remove this and say only @click="addService($event)" or @click="addService" also would work just fine but with no event passed in

McWally
  • 217
  • 2
  • 5