You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何测试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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 02:43:11