使用Vitest与Vuetify进行快照组件测试:组件解析失败问题
问题:Vue 3 + Vuetify 3 快照测试警告与空快照问题及配置疑问
问题背景
在Vue 3 + Vuetify 3环境下使用Vitest对ConfirmationModal组件执行快照测试时遇到两个核心问题:
- 仅初始化
createVuetify()时,快照内容正常,但会抛出大量Vuetify组件未解析的警告(如v-layout无法解析)。 - 按照官方文档引入所有Vuetify组件和指令后,警告消失,但生成的快照几乎为空,失去测试意义。
- 组件库项目(无完整Vue应用)不确定应使用
vite.config.ts还是vitest.config.ts进行配置。
相关代码与现象
初始测试代码(有警告但快照正常)
import { createVuetify } from 'vuetify'; import { describe, it, expect } from 'vitest'; import ConfirmationModal from '@/components/ConfirmationModal.vue'; const vuetify = createVuetify(); global.ResizeObserver = require('resize-observer-polyfill'); describe(`Composant ConfirmationModal`, () => { it(`Match snapshot`, async () => { const wrapper = mount( { template: '<v-layout><confirmation-modal></confirmation-modal></v-layout>' }, { props: { value: true, title: 'test', width: 100 }, global: { components: { ConfirmationModal }, plugins: [vuetify] } } ); expect(wrapper.html()).toMatchSnapshot(); }); });
初始快照内容
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`Composant ConfirmationModal > Match snapshot 1`] = ` "<v-layout title=\"test\" width=\"100\" value=\"true\"> <div class=\"text-center\"> <v-dialog width=\"510\" class=\"confirmation-modal\" persistent=\"\" value=\"false\"> <v-card> <v-card-title class=\"text-h5 grey lighten-2\" primary-title=\"\"></v-card-title> <v-card-text></v-card-text> <v-divider></v-divider> <v-card-actions> <v-spacer></v-spacer> <v-btn class=\"btn-ok\" color=\"primary\" text=\"\"> OK</v-btn> <v-btn id=\"btn-annulation\" color=\"primary\" text=\"\"> Annuler</v-btn> </v-card-actions> </v-card> </v-dialog> </div> </v-layout>" `;
组件未解析警告
[Vue warn]: Failed to resolve component: v-layout If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement. at <Anonymous value=true title="test" width=100 ... > at <VTUROOT>
引入完整Vuetify组件后的配置(警告消失但快照为空)
import { createVuetify } from 'vuetify' import * as components from 'vuetify/components' import * as directives from 'vuetify/directives' const vuetify = createVuetify({ components, directives, })
空快照内容
exports[`Composant ConfirmationModal > Correspond au snapshot 1`] = ` "<div class=\"v-layout\" title=\"test\" width=\"100\" value=\"true\"> <div class=\"text-center\"> <!----> <!----> </div> </div>" `;
当前vitest.config.ts配置
import { defineConfig, loadEnv } from 'vite'; import { fileURLToPath, URL } from 'node:url'; import vue from '@vitejs/plugin-vue'; export default ({ mode }) => { const env = loadEnv(mode, process.cwd(), ''); return defineConfig({ plugins: [vue()], define: { 'process.env': env }, test: { globals: true, environment: 'jsdom', deps: { inline: ['vuetify'] }, }, resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } } }); };
解决方案
1. 解决警告与空快照的矛盾
修改测试代码
import { createVuetify } from 'vuetify'; import * as components from 'vuetify/components'; import * as directives from 'vuetify/directives'; import { describe, it, expect, vi } from 'vitest'; import { mount } from '@vue/test-utils'; import ConfirmationModal from '@/components/ConfirmationModal.vue'; // 模拟ResizeObserver,避免无关警告 vi.stubGlobal('ResizeObserver', require('resize-observer-polyfill')); const vuetify = createVuetify({ components, directives, }); describe(`Composant ConfirmationModal`, () => { it(`Match snapshot`, async () => { // 直接挂载目标组件,而非废弃的v-layout const wrapper = mount(ConfirmationModal, { props: { // Vue3中v-model的prop名改为modelValue(若组件仍使用value需同步调整) modelValue: true, title: 'test', width: 100 }, global: { plugins: [vuetify] } }); // 等待Vuetify组件异步渲染完成 await wrapper.vm.$nextTick(); expect(wrapper.html()).toMatchSnapshot(); }); });
关键调整说明
- 移除废弃组件:Vuetify3已删除
v-layout组件,直接挂载ConfirmationModal避免无效布局容器干扰。 - 修正v-model prop:Vue3中v-model的绑定prop从
value改为modelValue,确保模态框显示状态生效。 - 等待DOM更新:Vuetify组件渲染存在异步过程,通过
$nextTick()确保快照捕获完整渲染状态。
2. 组件库项目配置选择
- 通用场景:若构建与测试配置差异不大,直接在
vite.config.ts的test字段中配置测试规则即可,Vitest会自动读取该配置。 - 独立测试需求:若测试需要与构建不同的配置(如特殊alias、插件),可创建
vitest.config.ts,导入基础Vite配置并扩展测试专属规则:import { defineConfig } from 'vitest/config'; import viteConfig from './vite.config'; export default defineConfig({ ...viteConfig, test: { ...viteConfig.test, // 添加测试专属配置 environment: 'jsdom', globals: true, }, });
原因分析
- 初始配置警告:仅调用
createVuetify()未注册组件/指令,Vuetify不会全局注册组件,导致测试时无法解析v-dialog、v-card等组件。 - 空快照问题:
- 使用了Vuetify3废弃的
v-layout组件,完整引入Vuetify后该组件无法正常渲染,导致内部ConfirmationModal挂载异常。 - Vue3 v-model prop名变更未同步,导致模态框显示状态未触发,
v-dialog处于隐藏状态(快照中显示为<!---->)。 - 未等待组件异步渲染完成,直接生成快照捕获了未初始化的DOM状态。
- 使用了Vuetify3废弃的
内容的提问来源于stack exchange,提问作者Clément Picou
相关产品推荐
相关产品推荐

