如何测试Vuetify折叠面板?解决测试中模型不更新问题
测试Vuetify折叠面板时模型未更新的解决方案
问题重现
测试Vuetify折叠面板组件时,点击面板后绑定的expandedPanel模型未更新,导致断言失败。
组件代码
<template> <div> <h1>Test Expansion Panel</h1> <v-expansion-panels v-model="expandedPanel" mandatory> <v-expansion-panel test-id="panel-0" text="Test Panel 0" /> <v-expansion-panel test-id="panel-1" text="Test Panel 1" /> </v-expansion-panels> <div test-id="panel-display">Panel Index: {{ expandedPanel }}</div> </div> </template> <script setup lang="ts"> import { ref } from 'vue'; // 注意:TypeScript中没有int类型,应改为number const expandedPanel = ref<number>(0); </script>
测试代码
import { mount, flushPromises } from '@vue/test-utils' import { expect, test } from 'vitest' import { createVuetify } from 'vuetify' import * as components from 'vuetify/components' import * as directives from 'vuetify/directives' import ExpansionPanelForm from '../../src/components/ExpansionPanelForm.vue' const vuetify = createVuetify({ components, directives, }) global.ResizeObserver = require('resize-observer-polyfill') test('displays text', async () => { const wrapper = mount({ template: '<v-layout><expansion-panel-form></expansion-panel-form></v-layout>' }, { attachTo: document.body, props: {}, global: { components: { ExpansionPanelForm }, plugins: [vuetify], } }) const panelOneEl = wrapper.find('[test-id="panel-1"]'); panelOneEl.trigger('click'); await flushPromises(); const panelDisplayEl = wrapper.find('[test-id="panel-display"]'); expect(panelDisplayEl.text()).toContain('Panel Index: 1'); })
错误信息
AssertionError: expected 'Panel Index: 0' to contain 'Panel Index: 1'
Expected: "Panel Index: 1"
Received: "Panel Index: 0"
问题原因
v-expansion-panel本身只是外层容器,并非可点击的交互元素。实际触发面板折叠/展开的是其内部的v-expansion-panel-header组件(或由text属性生成的头部元素)。直接点击v-expansion-panel元素无法触发状态变更事件。
解决方法
需要定位到面板内部的可点击头部元素,再触发点击事件,具体有两种实现方式:
方式一:通过类名定位内部头部
直接查找v-expansion-panel内部的.v-expansion-panel-header类元素:
test('displays text', async () => { const wrapper = mount({ template: '<v-layout><expansion-panel-form></expansion-panel-form></v-layout>' }, { attachTo: document.body, props: {}, global: { components: { ExpansionPanelForm }, plugins: [vuetify], } }) // 找到panel-1的内部头部元素 const panelOneHeader = wrapper.find('[test-id="panel-1"] .v-expansion-panel-header'); await panelOneHeader.trigger('click'); await flushPromises(); await wrapper.vm.$nextTick(); // 确保DOM完全更新 const panelDisplayEl = wrapper.find('[test-id="panel-display"]'); expect(panelDisplayEl.text()).toContain('Panel Index: 1'); })
方式二:给头部添加专属test-id
修改组件代码,显式定义v-expansion-panel-header并添加test-id,方便测试定位:
<template> <div> <h1>Test Expansion Panel</h1> <v-expansion-panels v-model="expandedPanel" mandatory> <v-expansion-panel test-id="panel-0"> <v-expansion-panel-header test-id="panel-header-0">Test Panel 0</v-expansion-panel-header> </v-expansion-panel> <v-expansion-panel test-id="panel-1"> <v-expansion-panel-header test-id="panel-header-1">Test Panel 1</v-expansion-panel-header> </v-expansion-panel> </v-expansion-panels> <div test-id="panel-display">Panel Index: {{ expandedPanel }}</div> </div> </template>
然后在测试中直接查找头部的test-id:
const panelOneHeader = wrapper.find('[test-id="panel-header-1"]'); await panelOneHeader.trigger('click');
另外,注意组件中ref<int>(0)的写法错误,TypeScript没有int类型,应改为ref<number>(0),避免类型报错。
内容的提问来源于stack exchange,提问作者Jamin
相关产品推荐
相关产品推荐

