如何对Vue3中的errorCaptured生命周期钩子进行单元测试?
完善触发errorCaptured钩子的单元测试
问题背景
想要通过子组件抛出错误,触发Main.vue中的errorCaptured钩子,但当前的单元测试无法正确模拟这一场景,需要完善测试代码。
原Main.vue代码(修正语法错误后)
原代码存在method拼写错误(应为methods),且TS环境下需用defineComponent包裹,修正后如下:
<template> <div class="main"> <q2-section class="section"> <header> <h1>Testing</h1> </header> <router-view /> </q2-section> </div> </template> <script lang="ts"> import { defineComponent } from 'vue'; export default defineComponent({ errorCaptured(err: Error) { this.errorMethod(err); return false; }, methods: { errorMethod(err: Error){ console.error(err); return false; } } }); </script>
原测试代码的问题
- 直接调用
wrapper.vm.$options.errorCaptured.call(error)不符合Vue的错误捕获逻辑:errorCaptured是Vue自动调用的钩子,而非手动触发,且call的第一个参数应为组件实例(wrapper.vm)。 - spy创建时机错误:在触发动作后才创建
spyOnError,无法捕获之前的方法调用。
完善后的单元测试方案
方案1:通过Stub替换router-view(无需配置路由)
直接用会抛出错误的测试组件替换router-view,模拟子组件错误场景:
import { mount } from '@vue/test-utils'; import Main from '@/components/Main.vue'; test('errorCaptured钩子在子组件抛出错误时触发', async () => { // 创建一个在created钩子抛出错误的测试子组件 const ErrorThrowingComponent = { created() { throw new Error('Generic Error'); }, template: '<div></div>' }; // 提前监听errorMethod,确保在触发错误前创建spy const spyOnError = vi.spyOn(Main.methods, 'errorMethod'); // 挂载Main组件,用测试组件替换router-view const wrapper = mount(Main, { global: { stubs: { 'router-view': ErrorThrowingComponent } } }); // 验证errorMethod被正确调用 expect(spyOnError).toHaveBeenCalledOnce(); expect(spyOnError).toHaveBeenCalledWith(expect.any(Error)); expect(spyOnError.mock.calls[0][0].message).toBe('Generic Error'); });
方案2:配置路由渲染错误组件(更贴近真实路由场景)
如果需要模拟真实的路由导航场景,可配置路由让router-view渲染错误组件:
import { mount } from '@vue/test-utils'; import Main from '@/components/Main.vue'; import { createRouter, createWebHistory } from 'vue-router'; test('errorCaptured钩子在路由组件抛出错误时触发', async () => { // 创建错误组件 const ErrorThrowingComponent = { created() { throw new Error('Generic Error'); }, template: '<div></div>' }; // 配置路由 const router = createRouter({ history: createWebHistory(), routes: [ { path: '/', component: ErrorThrowingComponent } ] }); // 提前创建spy const spyOnError = vi.spyOn(Main.methods, 'errorMethod'); // 挂载组件并注入路由 const wrapper = mount(Main, { global: { plugins: [router] } }); // 触发路由导航,渲染错误组件 await router.push('/'); await router.isReady(); // 验证调用 expect(spyOnError).toHaveBeenCalledOnce(); expect(spyOnError.mock.calls[0][0].message).toBe('Generic Error'); });
关键说明
- 必须在触发错误前创建spy,否则无法捕获方法调用。
- 模拟真实的子组件错误场景(如
created/mounted钩子抛出错误),才能让Vue自动触发errorCaptured钩子,而非手动调用钩子函数。
内容的提问来源于stack exchange,提问作者Arun Shetty
相关产品推荐
相关产品推荐

