I'm trying to test my 'Container' component which handles a forms logic. It is using vue-router
and the vuex
store to dispatch actions to get a forms details.
I have the following unit code which isn't working as intended:
it('On route enter, it should dispatch an action to fetch form details', () => {
const getFormDetails = sinon.stub();
const store = new Vuex.Store({
actions: { getFormDetails }
});
const wrapper = shallowMount(MyComponent, { store });
wrapper.vm.$options.beforeRouteEnter[0]();
expect(getFormDetails.called).to.be.true;
});
With the following component (stripped of everything because I don't think its relevant (hopefully):
export default {
async beforeRouteEnter(to, from, next) {
await store.dispatch('getFormDetails');
next();
}
};
I get the following assertion error:
AssertionError: expected false to be true
I'm guessing it is because I am not mounting the router in my test along with a localVue. I tried following the steps but I couldn't seem to get it to invoke the beforeRouteEnter
.
Ideally, I would love to inject the router with a starting path and have different tests on route changes. For my use case, I would like to inject different props/dispatch different actions based on the component based on the path of the router.
I'm very new to Vue, so apologies if I'm missing something super obvious and thank you in advance for any help! 🙇🏽
See this doc: https://lmiller1990.github.io/vue-testing-handbook/vue-router.html#component-guards
Based on the doc, your test should look like this:
it('On route enter, it should dispatch an action to fetch form details', async () => {
const getFormDetails = sinon.stub();
const store = new Vuex.Store({
actions: { getFormDetails }
});
const wrapper = shallowMount(MyComponent, { store });
const next = sinon.stub()
MyComponent.beforeRouteEnter.call(wrapper.vm, undefined, undefined, next)
await wrapper.vm.$nextTick()
expect(getFormDetails.called).to.be.true;
expect(next.called).to.be.true
});
A common pattern with beforeRouteEnter
is to call methods directly at the instantiated vm
instance. The documentation states:
The beforeRouteEnter guard does NOT have access to this, because the guard is called before the navigation is confirmed, thus the new entering component has not even been created yet.
However, you can access the instance by passing a callback to next. The callback will be called when the navigation is confirmed, and the component instance will be passed to the callback as the argument:
beforeRouteEnter (to, from, next) { next(vm => { // access to component instance via `vm` }) }
This is why simply creating a stub or mock callback of next
does not work in this case. I solved the problem by using the following parameter for next
:
// mount the component
const wrapper = mount(Component, {});
// call the navigation guard manually
Component.beforeRouteEnter.call(wrapper.vm, undefined, undefined, (c) => c(wrapper.vm));
// await
await wrapper.vm.$nextTick();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With