繁体   English   中英

如何测试从 VueX 观察计算属性的 Vue 观察者?

[英]How to test Vue watcher that watches a computed property from VueX?

假设我有以下组件:

import { mapState } from 'vuex';
import externalDependency from '...';

export default {
  name: 'Foo',
  computed: {
    ...mapState(['bar'])
  },
  watch: {
    bar () {
     externalDependency.doThing(this.bar);
    }
  }
}

测试时,我想确保externalDependency.doThing()使用bar (来自 vuex 状态)调用,如下所示:

it('should call externalDependency.doThing with bar', () => {
  const wrapper = mount(Foo);
  const spy = jest.spyOn(externalDependency, 'doThing');

  wrapper.setComputed({bar: 'baz'});

  expect(spy).toHaveBeenCalledWith('baz');
});

Vue test-utils 有一个 setComputed 方法,它允许我当前对其进行测试,但是我不断收到警告说 setComputed 将很快被删除,我不知道还有什么可以测试的:

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

从你试图实现

测试时,我想确保 externalDependency.doThing() 使用 bar(来自 vuex 状态)调用,如下所示:

(这确实是纯单元测试方法),您可以强制更改此观察者,这基本上是一个函数。 如果计算值或数据值发生变化,则无需跟踪观察者是否发生变化 - 让 Vue 处理它。 因此,要在已挂载的 Vue 实例中更改观察者,只需将其称为

wrapper.vm.$options.watch.bar.call(wrapper.vm)

其中bar是您的观察者的姓名。 通过这种方式,您将能够测试您要测试的确切功能。

来自此评论https://github.com/vuejs/vue-test-utils/issues/331#issuecomment-382037200 的想法,关于 vue-test-utils 问题,您在问题中提到。

Vue Test Utils文档指出了一种使用非常简单的 Vuex 存储的不同方法:

import { shallowMount, createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'

// use a localVue to prevent vuex state from polluting the global Vue instance
const localVue = createLocalVue();
localVue.use(Vuex);

describe('Foo.vue', () => {
  let state;
  let store;

  beforeEach(() => {
    // create a new store for each test to prevent pollution
    state = { bar: 'bar' };
    store = new Vuex.Store({ state });
  })

  it('should call externalDependency.doThing with bar', () => 
  {
    shallowMount(MyComponent, { store, localVue });
    const spy = jest.spyOn(externalDependency, 'doThing');
    // trigger the watch
    state.bar = 'baz';
    expect(spy).toHaveBeenCalledWith('baz');
  });
})

您将需要在 VueX 实例上使用某种 mutator,是的,这确实为测试引入了另一个不相关的单元,但就您个人而言,包括使用 Vuex 在内的测试,该概念已经被打破。

以意想不到的方式修改状态更容易导致与实际使用不同的行为。

您可以直接在源代码处设置该值,即 VueX。 所以你的store.js 中有这样的东西:

const state = {
  bar: 'foo',
};
const mutations = {
  SET_BAR: (currentState, payload) => {
    currentState.bar = payload;
  },
};
const actions = {
  setBar: ({ commit }, payload) => {
    commit('SET_BAR', payload);
  },
};

export const mainStore = {
  state,
  mutations,
  actions,
};

export default new Vuex.Store(mainStore);

然后在你的component.spec.js你会这样做:

import { mainStore } from '../store';
import Vuex from 'vuex';

//... describe, and other setup functions
it('should call externalDependency.doThing with bar', async () => {
  const localState = {
    bar: 'foo',
  };
  const localStore = new Vuex.Store({
      ...mainStore,
      state: localState,
  });
  const wrapper = mount(Foo, {
    store: localStore,
  });
  const spy = jest.spyOn(externalDependency, 'doThing');
  localStore.state.bar = 'baz';
  await wrapper.vm.$nextTick();
  expect(spy).toHaveBeenCalledWith('baz');
});

您还可以调用dispatch('setBar', 'baz')dispatch('setBar', 'baz')方法并让突变正确发生,而不是直接设置状态。

NB为每个挂载重新初始化您的状态很重要(即制作一个克隆或重新声明它)。 否则,一个测试可以改变状态,下一个测试将从那个脏状态开始,即使包装器被破坏。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM