Vue Test Utils 中如何正确模拟异步组件的加载?

Air-志丹 阅读 4

我在用 Vue Test Utils 测试一个使用了 defineAsyncComponent 的异步组件,但测试总是报错说找不到组件实例。明明在真实环境中能正常加载,测试里却不行。

我试过用 await flushPromises() 等待,也试过在 mount 之后手动调用 nextTick,但组件还是没渲染出来。是不是要 mock 这个异步加载过程?具体该怎么写?

我的组件大概是这样:

const AsyncComp = defineAsyncComponent(() =>
  import('@/components/MyAsyncComponent.vue')
)

测试代码里直接 mount 包含这个组件的父组件,结果就挂了。

我来解答 赞 4 收藏
二维码
手机扫码查看
1 条解答
上官博硕
这个问题很典型,测试环境里动态 import 不会自动 resolve,需要手动 mock。

核心解决办法是 mock 异步组件的导入路径。假设你的异步组件路径是 @/components/MyAsyncComponent.vue,测试这样写:

import { shallowMount, flushPromises } from '@vue/test-utils'
import ParentComponent from '@/components/ParentComponent.vue'

// 在 import 语句之前 mock
jest.mock('@/components/MyAsyncComponent.vue', () => ({
default: {
name: 'MyAsyncComponent',
template: '<div>mocked async component</div>'
}
}))

describe('ParentComponent', () => {
it('should render async component', async () => {
const wrapper = shallowMount(ParentComponent)
await flushPromises()

expect(wrapper.findComponent({ name: 'MyAsyncComponent' }).exists()).toBe(true)
})
})


如果你用的是 Vitest,把 jest.mock 换成 vi.mock 就行。

另外提醒一点安全相关的问题:mock 数据的时候别直接用生产环境的真实组件,最好用简化的 mock 组件,一来测试跑得快,二来避免测试依赖实现细节。上面这种返回简单 template 的方式就比较稳妥。

如果你的异步组件有 loading 和 error 状态需要测试,还可以这样写:

jest.mock('@/components/MyAsyncComponent.vue', () => ({
default: defineAsyncComponent({
loader: () => Promise.resolve({
name: 'MyAsyncComponent',
template: '<div>mocked</div>'
}),
loadingComponent: {
template: '<div>loading...</div>'
},
delay: 0
})
}))


这样可以分别测试 loading 状态和加载完成后的状态。
点赞
2026-03-13 03:04