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
相关产品推荐
相关产品推荐

