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

Cypress/test-vue-utils测试Vuex action时API mock未生效问题

问题原因

测试代码和业务代码存在4个核心错误,导致stub不生效、断言失败:

  • 第一,API函数导入方式错误,stub无法替换引用。exActions.js里直接用命名导入的方式拿getApiExById,这个函数会被绑定到action模块的独立作用域,你在测试里stub api对象上的方法,根本改不了action里已经拿到的函数引用,所以会走真实请求。
  • 第二,action没有返回Promise链,await store.dispatch()不会等待内部的异步API请求、commit逻辑执行完,断言触发时异步逻辑还没跑完。
  • 第三,store.dispatch传参完全错误。action的第一个参数context(包含commit、rootGetters等)是Vuex自动注入的,你不需要手动传,你之前把自定义的commit spy、rootGetters当参数传,Vuex根本不会用,而且你写的逗号表达式会把payload结构传错。
  • 第四,stub恢复写法错误,cy.stub.restore()是无效调用,拿不到你创建的那个stub实例。另外如果你的exStore模块开了命名空间,dispatch不带命名空间前缀会找不到action。
修正方案

1. 修改exActions.js

调整API导入方式,并且返回Promise链:

// exActions.js
import * as api from './exAPi.js' // 导入整个API模块对象,不要单独解构导入函数
export const exActions = {
    getExFromApi({ commit, rootGetters }, { id }) {
        // 必须return Promise链,否则await无法等待异步执行完成
        return api.getApiExById({ access_token: rootGetters.auth.token, id }).then(res => {
            commit('SET_INIT_EX', res)
            commit('SET_CURRENT_EX', res)
        }).catch(error => {
            console.warn(error)
        })
    },
}

如果你坚持要用命名导入的方式写API调用,那你需要用cy.intercept mock网络请求,而不是stub模块方法,这种写法不需要改业务代码的导入方式。

2. 修正测试用例代码

const api = require('../../../src/api/exAPi')
const exStore = require('../../../src/store/modules/exStore').default // 按实际路径导入exStore模块
let store = null

describe('Unit Test', function() {
    beforeEach(() => {
        const localVue = createLocalVue()
        localVue.use(Vuex)
        store = new Vuex.Store({
            modules: {
                exStore,
                // 注入mock的auth模块,提供rootGetters.auth.token
                auth: {
                    namespaced: true,
                    getters: {
                        token: () => 'aaa'
                    }
                }
            }
        })
    })
    context('test : action -> getExFromApi', function() {
        it('1',  async function() {
            // 保存stub实例
            const apiStub = cy.stub(api, 'getApiExById').resolved('foo')
            // 正确dispatch:第二个参数仅传payload,context由store自动注入
            // 如果exStore开了namespaced: true,action路径要写'exStore/getExFromApi',否则直接写'getExFromApi'
            await store.dispatch('getExFromApi', { id: '1' })

            // 断言commit执行结果,直接判断store里的state即可
            expect(store.state.exStore.initEx).to.equal('foo')
            expect(store.state.exStore.currentEx).to.equal('foo')

            // 恢复stub
            apiStub.restore()
        })
    })
})

如果你不想改业务代码的API导入方式,直接删掉模块stub的逻辑,换成cy.intercept('GET', '**/your-api-path/**', { body: 'foo' }) mock网络请求即可,这种方式不需要关心模块引用关系,更稳定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 17:39:22