Vue-test-utils: Original methods are called instead of stubs if invoke through events

Created on 19 Dec 2017  路  5Comments  路  Source: vuejs/vue-test-utils

When using Sinon stubs and Vue's event system, it appears that the original, stubbed, methods are still being called instead of the stubs themselves. Consider the following example:

import eventBus from '@/utils' // just a simple Vue instance
import Foo from '@/components/Foo'

const initStub = sinon.stub()
const wrapper = shallow(Foo)
wrapper.setMethods({ init: initStub })
eventBus.emit('event that invokes init()')

Expected Behavior

  • Foo.init() shouldn't be called
  • initStub.called should be true

Actual Behavior

  • Foo.init() is called
  • initStub.called is false

Notice that the bug (?) doesn't happen if init() is called directly i.e. wrapper.vm.init().

Most helpful comment

Hm, I'm doubtful that there's a way to fix it. Presumalby, you did something like this:

created () {
  eventBus.$on('event that invokes init()', this.init)
}

When you replace the method init after the event has registered, the eventbus doesn't know about it - it still has the old method as the callback for the event listener. And vue-test-utils doesn't know about the event bus, which is not part of the component instance, so it can't "replace" the callback either.

The same would happen if you registered a "normal" event listener (e.g. window.addEventListener('click', this.init), so this would be something that can happen frequently in tests.

The only solution I see it to stub the method immediatly:

const wrapper = shallow(Foo, {
  methods: {
    init: initStub
  }
})

I would not classify this as a bug and rather maybe document this under a headline like "stubbing event listeners set up in created" or something.

All 5 comments

Hm, I'm doubtful that there's a way to fix it. Presumalby, you did something like this:

created () {
  eventBus.$on('event that invokes init()', this.init)
}

When you replace the method init after the event has registered, the eventbus doesn't know about it - it still has the old method as the callback for the event listener. And vue-test-utils doesn't know about the event bus, which is not part of the component instance, so it can't "replace" the callback either.

The same would happen if you registered a "normal" event listener (e.g. window.addEventListener('click', this.init), so this would be something that can happen frequently in tests.

The only solution I see it to stub the method immediatly:

const wrapper = shallow(Foo, {
  methods: {
    init: initStub
  }
})

I would not classify this as a bug and rather maybe document this under a headline like "stubbing event listeners set up in created" or something.

Another way to work around this is to wrap the passing function in another one:

created() {
  this.bus.$on('event', () => { this.init() })
},

That way the reference to this.init will be determined during runtime.

In my opinion this is no issue in the vue-test-utils and could be closed.

What exactly are you trying to test? Maybe there is a better way to do it.

I'm looking to write some documents about how/what to test for vue-test-utils, knowing what kind of problems people run into and what they are trying to achieve is valuable feedback @phanan .

I'm closing this issue since it won't be fixed, the solution is to use @LinusBorg's suggestion:

const wrapper = shallow(Foo, {
  methods: {
    init: initStub
  }
})

Woot. When I think @LinusBorg's explanation does make a lot of sense, I quickly tried the suggestion and it didn't appear to work. I'll be spending a little more time when I have it, but closing can seem to be a bit too quick.

Was this page helpful?
0 / 5 - 0 ratings