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

Shopware 6 Vue组件Jest测试出现无限更新循环问题求助

Vue组件测试出现无限更新循环问题排查与修复

环境版本

  • Vue 2.6.14
  • Vuex 3.1.1
  • Vue Test Utils 1.3.0
  • Jest 29.3

问题背景

组件在开发环境运行正常,但使用Jest结合Vue Test Utils进行组件测试时,抛出「组件渲染函数存在无限更新循环」错误。注释掉Shopware.State.commit('MyPluginStore/setLoading', ['productComponents', true])后,测试即可通过。

组件代码(my-component/index.js)

const { Component } = Shopware;

Component.register('my-component', {
    template: '<sw-number-field :value="computedComponentPurchaseSum(0)"></sw-number-field>',

    inject: [
        'repositoryFactory'
    ],

    computed: {
        computedComponentPurchaseSum() {
            return (i) => {
                Shopware.State.commit('MyPluginStore/setLoading', ['productComponents', true]) // 引发错误
                return 15;
            }
        }
    }
})

Store代码(store.js)

...
mutations: {
    setLoading(state, params) {
        console.log('hello')
    }
}

错误输出

Expected test not to call console.error().

If the error is expected, test for it explicitly by mocking it out using jest.spyOn(console, 'error').mockImplementation() and test that the warning occurs.

[Vue warn]: You may have an infinite update loop in a component render function.

found in

---> <MyComponent>
       <Root>
    at console.captureMessage [as error] ([...]/node_modules/jest-fail-on-console/index.js:56:25)
    at warn ([...]/node_modules/vue/dist/vue.runtime.common.dev.js:621:15)
    at flushSchedulerQueue ([...]/node_modules/vue/dist/vue.runtime.common.dev.js:4319:9)
    at Array.<anonymous> ([...]/node_modules/vue/dist/vue.runtime.common.dev.js:1985:12)
    at flushCallbacks ([...]/node_modules/vue/dist/vue.runtime.common.dev.js:1911:14)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)

  at flushUnexpectedConsoleCalls ([...]/node_modules/jest-fail-on-console/index.js:40:13)
  at Object.<anonymous> ([...]/node_modules/jest-fail-on-console/index.js:95:7)

问题解答

1. 如何调试该错误?

  • 在计算属性内部、mutation方法中添加console.log,打印调用次数,确认是否存在循环执行
  • 用Vue DevTools查看组件更新触发记录,追踪每次更新的触发源
  • 临时移除commit调用,验证测试是否恢复正常,确认commit是否为循环触发点
  • 在测试中用jest.spyOn(Shopware.State, 'commit')监听commit调用次数,确认是否被反复触发

2. 错误产生的原因是什么?

核心问题是在渲染阶段调用了Vuex的mutation:

  • 组件模板中的computedComponentPurchaseSum(0)会在渲染时执行,而该函数内部调用Shopware.State.commit触发了Vuex状态变更
  • Vue检测到状态变更后,会触发组件重新渲染;重新渲染时又会再次执行该计算属性函数,再次调用commit,形成无限循环
  • 开发环境未报错,可能是因为开发环境的更新调度机制与测试环境存在差异,或者循环被Vue内部限制打断,但测试环境的Jest和Vue Test Utils对这类循环的检测更严格

3. 如何修复该问题?

核心原则是不要在渲染/计算属性中修改状态,可通过以下方案修复:

方案一:将状态变更移至生命周期钩子

如果loading状态需要在组件初始化时设置,放到created或mounted钩子中:

Component.register('my-component', {
    template: '<sw-number-field :value="computedComponentPurchaseSum(0)"></sw-number-field>',

    inject: ['repositoryFactory'],

    created() {
        Shopware.State.commit('MyPluginStore/setLoading', ['productComponents', true])
    },

    computed: {
        computedComponentPurchaseSum() {
            return (i) => {
                return 15;
            }
        }
    }
})

方案二:将计算属性改为方法

如果状态变更需要在特定时机触发(如用户交互),把计算属性改为方法,仅在需要时调用:

Component.register('my-component', {
    template: '<sw-number-field :value="componentPurchaseSum"></sw-number-field>',

    inject: ['repositoryFactory'],

    data() {
        return {
            componentPurchaseSum: 0
        }
    },

    methods: {
        fetchComponentPurchaseSum(i) {
            Shopware.State.commit('MyPluginStore/setLoading', ['productComponents', true])
            this.componentPurchaseSum = 15;
        }
    },

    mounted() {
        this.fetchComponentPurchaseSum(0);
    }
})

方案三:测试时mock掉commit方法

如果仅需测试组件渲染逻辑,无需验证状态变更,可在测试中mockShopware.State.commit:

jest.spyOn(Shopware.State, 'commit').mockImplementation(() => {});

// 后续执行组件测试逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 12:57:09