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

Nuxt组件测试问题:子组件事件触发后页面方法未被监听

问题:Vitest测试Nuxt页面时,子组件事件触发后页面方法的Spy断言失败

我正在用Vitest测试Nuxt页面,页面包含MyButton子组件,该组件会触发on-click事件并绑定到页面的onClick方法。目标是验证事件触发时页面方法能被正确调用,但测试中手动触发子组件事件后,仅能检测到事件已触发,无法断言页面方法被调用;直接调用该方法则测试通过。


页面代码

<template>
  <h1>Hello</h1>
  <MyButton @on-click="onClick" data-unit="btn" />
</template>

<script lang="ts" setup>
const onClick = () => {
  console.log('on click');
};
</script>

子组件代码

<template>
  <button @click="onClick">CLICK ME</button>
</template>

<script setup lang="ts">
const emits = defineEmits<{
  (e: 'on-click'): void;
}>();

const onClick = () => {
  emits('on-click');
};
</script>

当前测试代码

describe('Test click', () => {
      let btn: Awaited<ReturnType<typeof wrapper.find>>;
      beforeAll(() => {
        btn = wrapper.findComponent('[data-unit="btn"]');
      });
      it('Should find the btn', async () => {
        expect(btn).toBeTruthy();
      });

      describe('Should listen the event', () => {
        it('Should listen to the btn events', async () => {
          const spy = vi.spyOn(wrapper.vm, 'onClick');
          await btn.vm.$emit('on-click', { ... });
          expect(btn.emitted()['on-click']).toBeTruthy(); // 断言通过

          expect(spy).toHaveBeenCalled(); // 断言失败
          spy.mockRestore();
        });
      });
    });

问题原因与解决方法

核心原因

<script setup>是封闭作用域,内部定义的onClick方法默认不会挂载到组件实例(wrapper.vm)上,因此无法通过vi.spyOn(wrapper.vm, 'onClick')捕获到方法调用;另外直接手动$emit子组件事件的方式,跳过了真实的用户交互流程,也可能导致事件绑定的回调未被正确触发。

方案1:模拟真实用户点击(推荐)

直接找到子组件内的原生按钮,模拟点击操作,完整触发从原生点击到子组件emit、再到页面方法调用的流程:

describe('Test click', () => {
  let btnComponent: Awaited<ReturnType<typeof wrapper.findComponent>>;

  beforeAll(() => {
    btnComponent = wrapper.findComponent('[data-unit="btn"]');
  });

  it('Should trigger page onClick method when button is clicked', async () => {
    // 监听console.log来验证方法调用
    const consoleSpy = vi.spyOn(console, 'log');
    // 找到子组件内的原生按钮并模拟点击
    const nativeBtn = btnComponent.find('button');
    await nativeBtn.trigger('click');
    
    expect(consoleSpy).toHaveBeenCalledWith('on click');
    consoleSpy.mockRestore();
  });
});

方案2:暴露页面方法给测试

如果需要直接监听onClick方法,可以在页面的<script setup>中通过defineExpose暴露方法:

<script lang="ts" setup>
const onClick = () => {
  console.log('on click');
};

// 暴露方法给测试用
defineExpose({
  onClick
});
</script>

然后修改测试代码:

it('Should listen to the btn events', async () => {
  const spy = vi.spyOn(wrapper.vm, 'onClick');
  const nativeBtn = btnComponent.find('button');
  await nativeBtn.trigger('click');
  
  expect(spy).toHaveBeenCalled();
  spy.mockRestore();
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 20:42:42