Test Vue components using Jest and vue-utils

Viewed 1022

I am trying to test a component been called in vue using jest and vue-utils but it is giving the error below

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

 Expected mock function to have been called, but it was not called.

RandomPhoneNumber component The component makes use of ant-design-vue UI

       <div>
          <a-button
            type="primary"
            @click="generatePhone"
            size="large"
            class="btn-generate"
          >Generate Phone Numbers</a-button>
        </div>

What I have done is below

it('should call generatePhone', () => {
    const wrapper = mount(RandomPhoneNumber, {
      localVue,
      sync: false
    })

    const spy = jest.fn()
    wrapper.vm.generatePhone = spy
    const button = wrapper.find('.btn-generate')
    button.trigger('click')
    expect(wrapper.vm.generatePhone).toHaveBeenCalled()
  })

Can anybody share more light on this and what am I doing wrong here.

2 Answers

Well it's difficult to spot this without your component code. Your test code seems pretty much OK, however I never used sync: true option before.

I have two guesses:

  1. You should provide the mock function via methods,

like:

cost generatePhone = jest.fn();
const wrapper = mount(RandomPhoneNumber, {
  localVue,
  sync: false,
  methods: {
    generatePhone,
  }
})

const spy = jest.fn()
wrapper.vm.generatePhone = spy
const button = wrapper.find('.btn-generate')
button.trigger('click')
expect(generatePhone).toHaveBeenCalled()

Note how I'm expecting against generatePhone, not accessing it via wrapper.vm. I don't know why this happens, but I had problems asserting against jest mocks when accessing via the wrapper,

  1. On top of that, you may need to wait for the call,

as:

const generatePhone = jest.fn();
const wrapper = mount(RandomPhoneNumber, {
  localVue,
  sync: false,
  methods: {
    generatePhone,
  }
})

const spy = jest.fn()
wrapper.vm.generatePhone = spy
const button = wrapper.find('.btn-generate')
button.trigger('click')
await Promise.resolve()
expect(generatePhone).toHaveBeenCalled()
done() // this have to be passed as the 'it' function handler as a parameter: https://jestjs.io/docs/en/asynchronous.html

I am not really sure about the second one, but since you're passing sync as false, you may need to wait for the next tick for the method to be called, I don't really know, as this depends on Vue internals.

So after series of debugging and trying to see what works. It looks like calling wrapper.vm.method is not updating. What I did was to call the generatePhone() without prefixing it with wrapper.vm. I don't know why prefixing with wrapper.vm refused to work though. If anybody knows why I think it will be very helpful.

How I solved it

cost generatePhone = jest.fn();
const wrapper = mount(RandomPhoneNumber, {
  localVue,
  sync: false
})

generatePhone()
const button = wrapper.find('.btn-generate')
button.trigger('click')
expect(generatePhone).toHaveBeenCalled()

if you are want to pass a parameter to generatePhone, you can pass it like:

generatePhone(params)
const button = wrapper.find('.btn-generate')
button.trigger('click')
expect(generatePhone).toBeCalledWith(params)
Related