I'm running into an issue where I can't mock the method called in my mounted() hook and I'm assuming it has to do with the load order.
const myMethod = sinon.stub();
wrapper.setMethods({ myMethod });
I've also tried
const myMethod = sinon.spy();
wrapper = mount(ProfileSidebarIndex, {
methods: { myMethod },
});
and mocking mounted itself
const mounted = sinon.stub();
wrapper = mount(ProfileSidebarIndex, {
mounted
});
Is there a way to do this?
If it helps, I figured out how to do this without the test utils but then I don't have the wrapper so I'm still stuck here.
const Constructor = Vue.extend(MyComponent);
vm = new Constructor();
sinon.stub(vm, 'myMethod');
vm.$mount();
You can pass a methods object:
const myMethod = jest.fn()
wrapper = mount(ProfileSidebarIndex, {
methods: { myMethod }
});
no luck. Looks like this still runs the mounted hook
const mounted = sinon.stub();
wrapper = mount(ProfileSidebarIndex, {
methods: { mounted }
});
Do you want to stub the mounted hook, or a method that's called in a mounted hook?
There isn't currently a way to pass stubs to hooks.
either would work. Can't seem to get stubbing the mounted hook working any of the ways discussed in this thread
Can you post a minimal reproduction?
I can successfully stub methods by passing a methods object in the mount options.
I too am able to stub a method by passing it to the mount options. However, when that method is used in mounted() on the vue instance, it is not stubbed. I'm assuming this is because mount() (from your library, not to be confused with mounted() from Vue) first creates the vue instance and mounted() gets called before stubbing can happen. Going along with my other examples here, my component has this within the script
mounted() {
this.myMethod();
},
methods: {
myMethod() {
...
},
...
},
So to reiterate, I think mounted() is called before subbing myMethod happens. Thanks for all the help so far, let me know if you're unable to see the same issue.
I can confirm the observation made by @kleinjm:
const TestComp = Vue.extend({
mounted() {
this.testMethod()
},
methods: {
testMethod() {
console.log('this is the original test method!')
}
}
})
describe.only('TestComp', () => {
it('should call the original method', () => shallow(TestComp))
it('should not call the original method', () => shallow(TestComp, { stubs: ['testMethod'] }))
})
This example will print this is the original test method! in both tests. Mocking is no workaround.
To further the discussion about how to mock hooks: Not sure, if this is too hacky, but if we do
const vm = new TestComp()
vm.$options.mounted = [() => console.log('this is the successful mock of mounted')]
before vm.$mount() gets called (so basically when the attributes get applied in create-instance.js), it would work to replace hooks. Either a second stubs/mocks object could be provided, or we go through the stubs and mocks before applying them, filter for hook method names and add them in this different way.
I think that's a good solution @wtho
Would you like to implement it with a test case like the example you posted
@eddyerburgh yeah, I would like to try. Some points I have in mind/ran into:
beforeCreate, so just removing all functions might be the wrong approach. On the other hand I do not have an idea yet how to identify and remove only the function the author intends to override...mounted will be called, other mocked methods seem to not work (see initial problem of this issue)Made it work partially:
I will continue to work on it, but I am not sure if I can mock beforeCreate and created at all, would a PR still be accepted?
I also found out, that lifecycle-hooks added via mixins for activated, deactivated and update are not working. Will check on vuejs/vue if it is a known issue.
Thanks for looking into this @wtho 馃榾
It seems I really dropped the ball. The stubs option is for components, not methods. It's expected behavior that the example you posted doesn't overwrite the console.log method.
You can make the test pass by add a methods object:
mount(TestComp, { methods: {testMethod: () => {}} })
describe.only('TestComp', () => {
it('should not call the original method', () => shallow(TestComp, { methods: {testMethod: () => {}} }))
})
Sorry, I should have seen this earlier.
I think we should add support for mocking all lifecycle events, or none.
Even though this issues is called ability to mock lifecycle hooks, the problem was that @kleinjm couldn't stub a method inside mount. This is solved by passing a methods object with a method to override the method called in mount.
I'm renaming this issue. Stubbing lifecycle events should be a separate issue.
Sorry for the confusion.
I'm closing this issue, as I'm able to solve the original problem with the code I posted.
@wtho If you still want to stub lifecycle events, please create a fresh issue
I agree, we got carried away it seems.
@eddyerburgh One more thing, you say you can mock the methods using the methods property in options. It works, but the methods property seems not to be documented, and I also could not find it in the source code. Can you link it maybe (might be interesting for the lifecycle-hook issue)?
Should I create an issue for the missing documentation as well?
I will analyse the lifecycle mocking a bit further regarding the beforeCreate / created hooks, If I will be successful, I will let you know.
So the mount options comprise two things.
There are the options used by vue-test-utils like stubs, mocks, context. These get used by vue-test-utils. I've just added a method to extract these.
The options then get passed to the component, just like when you create a Vue instance:
const vm = new Vue({
store: store,
methods: methods
})
methods is part of that option. It overrides the methods on the component.
We need some docs on this, but I don't think we should specify methods specifically.
@wtho thanks for looking into this, I hope that stubbing hooks will be possible.
@eddyerburgh thanks a ton for the feedback. I figured out that stubbing is working, however, I need to await wrapper.vm.$nextTick();.
Do you remember how you succeeded to stub mounted() hook? @kellym
@eddyerburgh How can I stub the mounted() lifecycle hook?
I tried what you suggested: mount(TestComp, { methods: {mounted: () => {}} })
You could spy on the method like so:
const spy = jest.spyOn(ComponentName.methods, 'methodName');
const wrapper = shallowMount(ComponentName, {
localVue,
router,
}
expect(spy).toHaveBeenCalled();
Thanks @GitRaymond, this worked for me:
const spy = sinon.spy(Component.methods, 'componentMethod') // Called in `created` hook
const wrapper = createWrapper()
expect(spy).to.have.been.called
spy.restore()
In fact the solution above worked for me too
if you are want to mock the component on used in vue router you can use
import mockComponentName from '../components/ComponentName'
import App from '@/App.vue'
import flushPromises from 'flush-promises'
describe('Routing', () => {
it('It mounts correctly', async () => {
jest.mock('../components/ComponentName', () => {
mockComponentName.mounted = () => {}
return mockComponentName
})
let router = await require('@/router').default
const wrapper = mount(App, {
router
})
router.push('path/propValue')
await flushPromises()
let comp = wrapper.find(mockProductDetail)
expect(comp.exists()).toBe(true)
expect(comp.props('propName')).toBe('propValue')
})
})
useful when testing props pass to components via router
@dcshiman this issue was never about mocking a whole component, only about mocking a single lifecycle hook inside a component (in this case mount)
Hello @eddyerburgh
When i do what you suggested above:
mount(TestComp, {
methods: {
testMethod: () => {}
}
})
And try later to assert the method is called:
expect(wrapper.vm.testMethod).toBeCalled()
I get this error message:
Received has type: function
Received has value: [Function bound testMethod]
Why this happens or how to fix it ?
@begueradj you want testMethod to be a jest spy (or sinon)
E.g.
mount(TestComp, {
methods: {
testMethod: jest.fn()
}
})
Indeed, that is what I ended up doing last night, and it works, thank you very much for the feedback. @JessicaSachs
I wonder if you have a hint why I got the error above for the previous implementation I did ?
Most helpful comment
You could spy on the method like so:
const spy = jest.spyOn(ComponentName.methods, 'methodName');const wrapper = shallowMount(ComponentName, {localVue,router,}expect(spy).toHaveBeenCalled();