Vue,vuex:如何使用命名空间存储和模拟对组件进行单元测试?

     2023-02-22     208

关键词:

【中文标题】Vue,vuex:如何使用命名空间存储和模拟对组件进行单元测试?【英文标题】:Vue, vuex: how to unit test a component with namespaced store and mocking? 【发布时间】:2020-08-09 09:03:44 【问题描述】:

我正在使用 vue、vuex 和 vuetify 构建登录组件。我决定在商店中使用命名空间的身份验证模块,这导致了我的问题。

我正在使用 TDD 来解决这个问题。我的 e2e 测试有效。但是我编写了这个单元测试(使用 mockStore),它应该只验证一个正确的动作已经被调度:

describe('Login component', () => 
  let wrapper
  const mockStore = 
    dispatch: jest.fn(),
  

  beforeEach(() => 
    wrapper = mount(Login, 
      localVue,
      mocks:  $store: mockStore ,
      computed: 
        error: () => 'test error',
      ,
      data: () => (
        valid: true
      )
    )
  )

  it('should dispatch login action', async () => 
    wrapper.find('[data-test="username"]').setValue('username')
    wrapper.find('[data-test="password"]').setValue('password')
    await wrapper.vm.$nextTick()
    await wrapper.vm.$nextTick()
    wrapper.find('[data-test="login"]').trigger('click')
    await wrapper.vm.$nextTick()
    expect(mockStore.dispatch).toHaveBeenCalledWith(
      `auth/$LOGIN`,
       username: 'username', password: 'password' 
    )
  )
)

组件仅通过以下方式使用mapActions

...mapActions('auth', [LOGIN])

以及触发它的按钮:

      <v-btn
        color="info"
        @click="login( username, password )"
        data-test="login"
        :disabled="!valid"
      >Login</v-btn>

我得到的错误是:

[Vue warn]: Error in v-on handler: "TypeError: Cannot read property 'auth/' of undefined"

如果我将命名空间放在mapActions 中,那么我得到的调度操作名称没有命名空间(duh)并且测试失败:

    - Expected
    + Received

    - "auth/login",
    + "login",

我实际上可以通过如下映射操作来修复它:

...mapActions( login: `auth/$LOGIN` )

但我真的更喜欢使用命名空间版本,因为当我有更多操作时它会变得丑陋。

我正在研究 vuex 源代码,但在尝试访问 _modulesNamespaceMap 时它失败了,但它对我来说太复杂了。

测试这个的最佳方法是什么?我现在应该放弃嘲笑并使用真正的商店吗?

完整的项目可用here 并且与此问题相关的提交是4a7e749d4

【问题讨论】:

【参考方案1】:

对于迁移到 Vue 3 Test Utils 的任何人,请注意上述答案所依赖的 createLocalVue 方法已在 @vue/test-utils 中删除(请参阅 https://next.vue-test-utils.vuejs.org/migration/#no-more-createlocalvue)。

相反,它建议使用来自 Vuex 的 createStore 方法。我能够让命名空间模块像这样工作:

/* ... other imports and setup ... */
import  mount  from "@vue/test-utils";
import Logon from "path/to/your/logon/component";
import  createStore  from "vuex";

describe('Login component', () => 

  const actions = 
    login: jest.fn(),
  ;

  const mockStore = createStore(
    modules: 
      auth: 
        namespaced: true,
        actions,
      ,
    ,
  );

  let wrapper;

  beforeEach(() => 
    wrapper = mount(Login, 
      global: 
        plugins: [mockStore],
      ,
    );
  );

  it('should dispatch login action', async () => 
     /*...test code goes here */
  )
)

【讨论】:

【参考方案2】:

以the example on the vue-test-utils docs 为基础,我认为这应该可行:

/* ... other imports and setup ... */
import Vuex from 'vuex'

describe('Login component', () => 
  let wrapper
  const actions = 
    login: jest.fn(),
  
  const mockStore = new Vuex(
    modules: 
      auth: 
        namespaced: true,
        actions,
      ,
    ,
  )

  beforeEach(() => 
    wrapper = mount(Login, 
      localVue,
      mocks:  $store: mockStore ,
      computed: 
        error: () => 'test error',
      ,
      data: () => (
        valid: true
      )
    )
  )

  it('should dispatch login action', async () => 
    wrapper.find('[data-test="username"]').setValue('username')
    wrapper.find('[data-test="password"]').setValue('password')
    await wrapper.vm.$nextTick()
    await wrapper.vm.$nextTick()
    wrapper.find('[data-test="login"]').trigger('click')
    await wrapper.vm.$nextTick()
    expect(actions.login).toHaveBeenCalled() // <-- pretty sure this will work
    expect(actions.login).toHaveBeenCalledWith( // <-- not as sure about this one
      username: 'username',
      password: 'password',
    )
  )
)

【讨论】:

太棒了。我最终使用了类似的方法,唯一困扰我的是创建一个实际的 Vuex 对象

从模板访问 vue vuex 命名空间的 getter

...的getter映射,如下所示:...mapGetters([\'fooModule/barGetter\'])如何在.vue组件模板中访问这个getter?我试过fooModule.bar 查看详情

测试 Vue 组件 - 模拟状态和方法

...在尝试对Vue组件进行单元测试,但我似乎无法完全弄清楚如何模拟/存根存储对象和调用异步API的方法。这是我们拥有的Vue组件的示例:importmapState,mapGettersfrom\'vuex\'importrouterfrom 查看详情

在 Vue 和 Vuex 的非子组件中获取存储值

...管理相同的全局状态。问题是我无法使用store,无论它是如何集成的,或者我如何尝试从组件中调用它,它都不起作用。我只是在我的状态中有一个用户对象 查看详情

如何为 vuex 命名空间模块状态创建 getter 和 setter

...述】:如果我有一个命名空间的Vuex模块,当在Vue组件中使用这些状态时,如何为该模块中的状态创建getter和setter?//MycomponentnewVue(computed://How 查看详情

vuex的使用

...,多个组件都能读,也都可以改。vuex的执行流程:安装使用vuex是一个插件,所以需要Vue.use注册了vuex,我们就可以在vue里配置store了getters这里多了个配置getters,他可以看作是基于state的computed属性。使用的方式基本如下:同时get... 查看详情

打字稿:引用 Vuex 存储模块会导致 VueJs 2.5 的命名空间错误

】打字稿:引用Vuex存储模块会导致VueJs2.5的命名空间错误【英文标题】:Typescript:ReferencingaVuexStoreModulegivesnamespaceerrorforVueJs2.5【发布时间】:2019-03-1819:42:40【问题描述】:你好,SO朋友们,我在我的一个Vue组件中引用Vuex存储模块... 查看详情

使用 Jest 测试 NUXT.js 和 Vue.js 应用程序。获取“在 mapState() 中找不到 [vuex] 模块命名空间”和“[vuex] 未知操作类型”

】使用Jest测试NUXT.js和Vue.js应用程序。获取“在mapState()中找不到[vuex]模块命名空间”和“[vuex]未知操作类型”【英文标题】:TestingaNUXT.jsandVue.jsappwithJest.Getting\'[vuex]modulenamespacenotfoundinmapState()\'and\'[vuex]unknownactiontype\'【发布时间... 查看详情

vuejs2:如何将 vuex 存储传递给 vue-router 组件

】vuejs2:如何将vuex存储传递给vue-router组件【英文标题】:vuejs2:Howtopassvuexstoretovue-routercomponents【发布时间】:2018-10-0205:39:10【问题描述】:如果不使用vue-router,可以在声明newVue()时将store传递给子组件但我同时使用vue-router和vuex... 查看详情

vuevuex概念和基本使用(代码片段)

...新中…文章目录Vuex1.概念2.Vuex流程图3.搭建vuex环境4.基本使用5.getters的使用6.四个map方法的使用7.模块化+命名空间Vuex1.概念​Vuex是在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态... 查看详情

vue之vuex的使用(代码片段)

...种组件间通信的方式,且适用于任意组件间的通信2.使用场景多个组件依赖于同一状态来自不同组件的行为需要变更同一状态3. Vuex工作原理State是存储的单一状态,是存储的基本数据(把改变的数据给到VueComponentsÿ... 查看详情

Vue/Vuex。我的组件无法访问 Vuex 存储属性

...得很好。我刚刚导入了vuex来帮助进行状态管理。我正在使用typescript和vue-class-decorator以获得更好的类型安全性。我的 查看详情

如何对使用 vuex-class 的 typescript Vue 组件进行单元测试

】如何对使用vuex-class的typescriptVue组件进行单元测试【英文标题】:HowtounittestatypescriptVueComponentthatusesvuex-class【发布时间】:2020-04-0208:32:31【问题描述】:<scriptlang="ts">importComponent,Vuefrom\'vue-property-decorator\';importAction,Get 查看详情

vue从入门到放弃(代码片段)

...成3.vuex的安装命令4.vuex的state、getters、mutations、actions的使用5.modules模块化和命名空间的使用vuex的介绍**VueX是一个专门为Vue.js应用设计的状态管理架构,统一管理和维护各个vue组件的可变化状态(你能够理解成vue组件里的某些d... 查看详情

vue从入门到放弃(代码片段)

...成3.vuex的安装命令4.vuex的state、getters、mutations、actions的使用5.modules模块化和命名空间的使用vuex的介绍**VueX是一个专门为Vue.js应用设计的状态管理架构,统一管理和维护各个vue组件的可变化状态(你能够理解成vue组件里的某些d... 查看详情

在 PINIA、Vue 3+Typescript 上处理命名空间模块化方法

...。现在我正在使用模块化方法创建商店,但无法真正理解如何在types 查看详情

vuex(代码片段)

文章目录Vuex简介Vuex是什么什么时候使用VuexVuex工作原理Vuex环境搭建下载vuex创建src/store/index.js传入store配置项求和案例纯vue版本Vuex版本getters配置项四个map方法的使用mapState与mapGettersmapActions与mapMutations多组件共享数据模块化+... 查看详情

Vuex 命名空间存储设置两种状态

...换为过滤器,以便以后查询后端。我在两个不同的表旁边使用这些过滤器。如果我在table1中过滤id=123,我不想让table2中的过滤器成为id=123。这就是我创建一个模块并尝试使用命 查看详情

如何在 Vue 3 组件中使用 Vuex 4 状态数据作为另一个调度的有效负载?

】如何在Vue3组件中使用Vuex4状态数据作为另一个调度的有效负载?【英文标题】:HowtouseVuex4statedatainsideVue3componentaspayloadforanotherdispatch?【发布时间】:2021-05-2320:32:15【问题描述】:我正在使用Vue3组合API和Vuex4中的useStore钩子这就... 查看详情