Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Sinon spy a Vue component method triggered by a Vue event?

Tags:

vuejs2

sinon

The basic setup that I've done in order to describe my problem:

Using vue-cli 2.8.2, I generated a new project based on webpack template (vue init webpack vue-test-sinon-spy) keeping all the defaults of vue-cli (with the irrelevant exception of disabling eslint).

Changes done in this vue-cli generated project:

  1. I attached an event on h2 tag from Hello.vue:
<h2 @click="sayHello">Essential Links</h2>
  1. I added a method in Hello component
<script>
export default {
  ...
  methods: {
    sayHello() {
      console.log('hello!')
    }
  }
}
</script>
  1. I added a new test in Hello.spec.js
describe('Hello.vue', () => {
  // ...

  it('should handle click on h2 tag', () => {
    const Constructor = Vue.extend(Hello)
    const vm = new Constructor().$mount()
    sinon.spy(vm, 'sayHello')

    // [A] if I run the line below, vm.sayHello.callCount will be 0 - not as expected
    vm.$el.querySelector('h2').click()

    // [B] if I run the line below, vm.sayHello.callCount will be 1 - as expected
    // vm.sayHello()

    // vm.sayHello.callCount will be 0 or 1, depending on
    //    what line I execute ([A] or [B]),
    //    even if in both cases sayHello method is really executed
    console.log('###', vm.sayHello.callCount)
  })
})

When I programmatically click the html tag (using vm.$el.querySelector('h2').click()), spy won't capture the execution of the method sayHello, thus vm.sayHello.callCount will be 0. Not what I like.

But, if I directly call sayHello (using vm.sayHello()), vm.sayHello.callCount will be 1. As I expect.

How can I make spy capture the call of sayHello (so that vm.sayHello.callCount will be 1), if I want to simulate the click on the html tag (vm.$el.querySelector('h2').click()), and not directly calling sayHello (no vm.sayHello())?

Thanks

like image 934
awho Avatar asked Aug 20 '17 23:08

awho


1 Answers

The problem here is that callback is being bound to the event when the component is mounted. I'm not sure exactly how it works in the background but it's like its a copy of the sayHello method within the click event scope. You can't modify it after it has been bound.

You are creating the spy after that on the components method. They act the same but they are not. One is a spy and one is not.

wrapper.vm.sayHello() executes the method (spied on) wrapper.find('h2').trigger('click') executes the callback (not spied on)

Create the spy on the component Class before mounting rather than the instance afterwards and it should work as expected.

it('should handle click on h2 tag - vue-test-utils + dummy click version', () =>     {
    const clickSpy = sinon.spy(Hello.methods, 'sayHello')
    const wrapper = mount(Hello)
    ...
})
like image 60
brianf Avatar answered Oct 13 '22 01:10

brianf