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

时间:2018-03-22 14:51:45

标签: vue.js vuex vue-test-utils

假设我有以下组件:

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

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

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

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

4 个答案:

答案 0 :(得分:1)

您可以直接在源(即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')方法,使突变正确发生,而不是直接设置状态。

NB 重要的是,对于每个安装都必须重新初始化状态(即克隆或重新声明状态)。否则,即使包装被破坏,一个测试也可以更改状态,而下一个测试将从该脏状态开始。

答案 1 :(得分:1)

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');
  });
})

答案 2 :(得分:1)

您正在尝试实现的目标

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

(这确实是纯单元测试方法),您可以强制更改此观察程序,这基本上是一个功能。 无需跟踪观察者是否在计算值或数据值更改的情况下进行更改-让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问题的想法。

答案 3 :(得分:0)

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

以意外方式修改状态更容易导致行为与实际用法不同。