10

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!

4

2 回答 2

5

请参阅此文档:https ://lmiller1990.github.io/vue-testing-handbook/vue-router.html#component-guards

根据文档,您的测试应如下所示:

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
});
于 2019-12-14T08:06:44.647 回答
2

一个常见的模式beforeRouteEnter是直接在实例化的vm实例上调用方法。该文件指出

beforeRouteEnter 守卫没有访问权限,因为守卫在导航确认之前被调用,因此新的进入组件甚至还没有创建。

但是,您可以通过将回调传递给 next 来访问该实例。确认导航后会调用回调,并将组件实例作为参数传递给回调:

beforeRouteEnter (to, from, next) {
 next(vm => {
   // access to component instance via `vm`
 })
}

这就是为什么在这种情况下简单地创建存根或模拟回调next不起作用的原因。我通过使用以下参数解决了这个问题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();
于 2021-02-14T12:58:51.740 回答