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

