Vue-test-utils: Discussion: Best API for stubbing methods?

Created on 29 Jul 2017  路  8Comments  路  Source: vuejs/vue-test-utils

Currently, to stub methods on a component you need to do this:

const wrapper = mount(TestComponent)
wrapper.vm.clickHandler = sinon.stub() // Stub the method
wrapper.update() // Force the vm to update
wrapper.find('button').trigger('click')
expect(wrapper.vm.clickHandler.called).to.equal(true)

I think we should either add a method, or an option that stubs component methods:

// Method
const wrapper = mount(TestComponent)
wrapper.stubMethod(clickHandler, sinon.stub()) // Stubs the method and forces update
wrapper.find('button').trigger('click')
expect(wrapper.vm.clickHandler.called).to.equal(true)

It could also be called setMethods, like the setData and setProps methods, and take an object.

// Option
const wrapper = mount(TestComponent, {
    stubMethods: { // stubs methods before mount
        clickHandler: clickHandlerStub
    }
})
wrapper.find('button').trigger('click')
expect(wrapper.vm.clickHandler.called).to.equal(true)

Personally I prefer the stubMethod/ setMethods approach, but I'd like to hear peoples thoughts 馃檪

Most helpful comment

There's now a setMethods method.

We should have a setComputed method too. I've created a new issue for that:

https://github.com/vuejs/vue-test-utils/issues/55

All 8 comments

I previously had a hook that was called before the component was mounted, which exposed a deep copy of the component so you could manually stub it's methods (without affecting the original component). But i actually really like your approach, I think it's really simple.

A couple of thoughts:

  • would you want the option to restore a stubbed method at a later point?
  • could you stub a method without having to provide an alternate function {clickHandler:true}
  • what about computed properties? There have been times when a method relies on a computed property that is so complicated it's taken me far outside the purpose of my unit test just to get the right computed value!

I prefer setMethods as it is consistent with setData and setProps. However, I think there should also be a method to retrieve them as it could be confusing that you then have to use the vm to check if it has been called.

wrapper.stubMethod(clickHandler, sinon.stub())
...
expect(wrapper.vm.clickHandler.called).to.equal(true)

With the current way, at least the way you set and get is consistent.

wrapper.vm.clickHandler = sinon.stub() 
...
expect(wrapper.vm.clickHandler.called).to.equal(true)

@philefstat

We could recommend this pattern:

const clickHandlerStub = sinon.stub()

wrapper.stubMethod('clickHandler', clickHandlerStub)
...
expect(clickHandlerStub.called).to.equal(true)

Or this:

const clickHandlerStub = sinon.stub()

wrapper.stubMethods({
  clickHandler: clickHandlerStub
})

@jackmellis

would you want the option to restore a stubbed method at a later point?

I don't think so, with stubMethod you could save the original before stubbing and then restore it later with the same method.

could you stub a method without having to provide an alternate function {clickHandler:true}

Yes I think that's a good idea

what about computed properties?

Yes I think that a setComputed method would be a good idea if setData does not work for a use case. Would you be able to provide example where setData doesn't work, so I can use it as a test case?

@eddyerburgh those both look great 馃憤

That pattern also allows some of the useful sinon methods to be called on the stub without reaching directly into the vm.

i.e.
clickhandlerStub.resetHistory()

stubMethods could be quite useful for larger components with multiple methods that need to be stubbed.

const methods = {
  foo: sinon.stub().returns(3),
  bar: sinon.stub(),
  baz: sinon.stub().throws("TypeError")
}

wrapper.stubMethods(methods)

...

expect(methods.foo).to.be.calledOnce
expect(methods.bar).to.be.calledTwice

There's now a setMethods method.

We should have a setComputed method too. I've created a new issue for that:

https://github.com/vuejs/vue-test-utils/issues/55

setMethods worked great.

like here:

const spy = jest.spyOn(wrapper.vm, 'handleChange')
wrapper.setMethods({ handleChange: spy })
wrapper.find('.some-input').trigger('change')
expect(spy).toHaveBeenCalled()

Hi All,

  const spy = sinon.stub()
  wrapper.setMethods({ onClickCreate: spy })
  wrapper.find('#btn-create-proposal').trigger('click')
  expect(spy.called).toBe(true)

this is not working.
In Actual the method defined in component being mounted is being called.
Thanks for help in advance

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dlumbrer picture dlumbrer  路  3Comments

38elements picture 38elements  路  3Comments

vilarinholeo picture vilarinholeo  路  3Comments

alexanderstudte picture alexanderstudte  路  3Comments

vwxyutarooo picture vwxyutarooo  路  3Comments