You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Jest与vue-test-utils测试Nuxt中vuex-module-decorators定义的Vuex模块

直接实例化模块失败的原因

你直接new AuthModule拿到的是空实例,是因为vuex-module-decorators的装饰器只会把类转换成Vuex模块的配置结构,并不会自动绑定Vuex Store上下文,所以实例上的mutations、actions、getters都没有被正确初始化,不能直接使用。

报错Cannot find module 'undefined/store.js'的原因

Jest的setupFilesAfterEnv配置项不支持异步初始化逻辑,你在jest.setup.js里编写的异步构建Nuxt实例的逻辑不会被Jest等待执行完成,导致process.env.buildDir还没赋值就已经开始执行测试代码,所以拼接出来的store路径变成了undefined/store.js,自然找不到对应文件。

正确的单元测试方案

不需要构建完整的Nuxt实例,直接手动创建Vuex Store注册模块即可,测试步骤如下:

  1. 测试文件中创建本地Vue实例,注册Vuex插件
  2. 每次测试前初始化干净的Vuex Store实例,将你的AuthModule作为子模块注册
  3. 通过vuex-module-decorators提供的getModule方法,拿到绑定了Store上下文的模块实例
  4. 针对不同的模块属性编写测试用例

完整测试代码示例

// auth.spec.ts
import { createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'
import { getModule } from 'vuex-module-decorators'
// 替换成你实际的AuthModule文件路径
import AuthModule from '@/store/auth'
// mock外部依赖的服务,比如你用到的cognito注册服务
jest.mock('@/services', () => ({
  register: jest.fn()
}))
import services from '@/services'

const localVue = createLocalVue()
localVue.use(Vuex)

describe('AuthModule测试', () => {
  let authModule: AuthModule
  let store: Vuex.Store<any>

  // 每次测试前重置实例,避免用例之间互相影响
  beforeEach(() => {
    store = new Vuex.Store({
      modules: {
        // 这里的key要和你模块的命名空间对应,你开了namespaced: true,后续调用也会用到这个命名空间
        auth: AuthModule
      }
    })
    // 获取绑定了store的模块实例
    authModule = getModule(AuthModule, store)
  })

  // 测试Mutation
  it('setIsLoading mutation可正确修改加载状态', () => {
    authModule.setIsLoading(true)
    expect(authModule.isLoading).toBe(true)
    authModule.setIsLoading(false)
    expect(authModule.isLoading).toBe(false)
  })

  // 测试Getter
  it('getEmail getter可正确返回存储的邮箱', () => {
    authModule.setEmail('test@test.com')
    expect(authModule.getEmail).toBe('test@test.com')
  })

  // 测试异步Action
  it('register action注册成功时状态更新正确', async () => {
    // mock注册接口返回成功
    (services.register as jest.Mock).mockResolvedValue({ user: {} })
    await authModule.register({ email: 'test@test.com', password: '123456' })
    
    // 断言依赖被正确调用
    expect(services.register).toHaveBeenCalledWith('test@test.com', '123456')
    // 断言状态符合预期
    expect(authModule.isLoading).toBe(false)
    expect(authModule.registrationInitiated).toBe(true)
    expect(authModule.error).toBeUndefined()
  })

  it('register action注册失败时状态更新正确', async () => {
    const testError = new Error('邮箱已被注册')
    // mock注册接口返回失败
    (services.register as jest.Mock).mockRejectedValue(testError)
    await authModule.register({ email: 'test@test.com', password: '123456' })
    
    expect(authModule.error).toEqual(testError)
    expect(authModule.registrationInitiated).toBe(false)
    expect(authModule.isLoading).toBe(false)
  })

  // MutationAction测试逻辑和普通Action一致,直接调用后断言状态即可
  it('setEmail MutationAction可正确存储邮箱', async () => {
    await authModule.setEmail('new@test.com')
    expect(authModule.email).toBe('new@test.com')
  })
})

各类模块属性的测试方法

  • Mutation:直接调用模块实例上的mutation方法,断言state对应属性是否符合预期即可
  • Getter:先给state设置对应值,再调用getter断言返回值是否正确
  • 普通Action/MutationAction:mock掉所有外部依赖(接口请求、其他模块调用等),调用action后断言依赖是否被正确传入、state是否发生预期变化,异步action需要加await等待执行完成

内容的提问来源于stack exchange,提问作者StarLord27

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 23:18:02