如何使用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注册模块即可,测试步骤如下:
- 测试文件中创建本地Vue实例,注册Vuex插件
- 每次测试前初始化干净的Vuex Store实例,将你的AuthModule作为子模块注册
- 通过
vuex-module-decorators提供的getModule方法,拿到绑定了Store上下文的模块实例 - 针对不同的模块属性编写测试用例
完整测试代码示例
// 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
相关产品推荐
相关产品推荐

