在Vue组件单元测试中如何验证自定义事件触发次数?

婷婷 阅读 76

我在测试一个带计数功能的按钮组件时,发现用Vue Test Utils的$emit无法正确验证事件触发次数。组件点击后会连续触发两次自定义事件,但测试总是显示调用次数为0:


// CounterButton.vue
export default {
  methods: {
    handleClick() {
      this.$emit('increment');
      this.$nextTick(() => this.$emit('increment'));
    }
  }
}

测试代码这样写的:


import { mount } from '@vue/test-utils';
describe('CounterButton', () => {
  it('should emit increment twice', () => {
    const wrapper = mount(CounterButton);
    const spy = jest.spyOn(wrapper.vm, '$emit');
    wrapper.find('button').trigger('click');
    expect(spy.mock.calls.length).toBe(2); // 期望2次实际0次
  });
});

尝试过用wrapper.emitted(‘increment’)也返回空对象,是不是$nextTick里的emit需要特别处理?或者spy的使用方式有问题?

我来解答 赞 9 收藏
二维码
手机扫码查看
2 条解答
UP主~梓豪
问题出在你用 jest.spyOn(wrapper.vm, '$emit') 监听的是 Vue 实例上的 $emit 方法本身,但 Vue Test Utils 的 mount 会用一个包装过的 vm,实际触发事件时走的是内部机制,spy 可能根本没捕获到——尤其在 $nextTick 异步回调里更难抓。

验证事件触发次数的正确姿势是用 wrapper.emitted(),但要记得等 $nextTick 执行完。你当前测试里没等异步结束就断言,自然拿不到结果。

建议改成这样:

import { mount } from '@vue/test-utils';
import { nextTick } from 'vue';

describe('CounterButton', () => {
it('should emit increment twice', async () => {
const wrapper = mount(CounterButton);
wrapper.find('button').trigger('click');
await nextTick(); // 等 $nextTick 回调执行完
expect(wrapper.emitted('increment')).toHaveLength(2);
});
});


如果还担心事件顺序或异步时序问题,可以加个 await nextTick() 确保微任务清空。另外 emitted() 返回的是数组,每个事件名对应一个数组,数组长度就是触发次数,比 spy 更可靠,也避免了对 Vue 内部方法的过度依赖。

顺便说一句,如果你组件里经常用 $nextTick 触发事件,最好在测试里统一用 await nextTick() 或者 await wrapper.vm.$nextTick() 显式等待,不然很容易踩这种“看起来执行了但测试拿不到”的坑。
点赞 2
2026-02-24 14:01
Good“瑞芳
问题出在你监听的时机不对,$emit 的 spy 没法正确捕获 $nextTick 里的调用。直接这样改:


import { mount } from '@vue/test-utils';
describe('CounterButton', () => {
it('should emit increment twice', async () => {
const wrapper = mount(CounterButton);
await wrapper.find('button').trigger('click');
await wrapper.vm.$nextTick(); // 等待 $nextTick 完成
expect(wrapper.emitted('increment').length).toBe(2); // 直接验证事件触发次数
});
});


别用 spy 去监听 $emit,用 wrapper.emitted() 更靠谱,记得加上 async/await$nextTick 执行完。
点赞 10
2026-02-14 15:03