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

如何用vue-test-utils+Vitest测试Ionic自定义模态框的内容与行为?

问题:Vue3+Ionic8模态框组件单元测试无法访问内部内容

开发基于Vue3和Ionic8的应用时,自定义模态框组件MyCustomModal.vue使用vue-test-utils和Vitest进行单元测试,无法访问模态框内部的渲染内容:测试代码中wrapper.text()输出空字符串,wrapper.html()仅显示空的<ion-modal>标签,无法找到<h2>元素进行断言。

组件代码

<script setup lang="ts">
const props = defineProps<{
  isOpen: boolean;
  userName: string;
}>();
</script>
<template>
  <ion-modal :is-open="isOpen" @did-dismiss="emit('didDismiss')">
    <div><h2>Your initial is {{ userName[0] }}</h2></div>
  </ion-modal>
</template>

原测试代码(存在问题)

import { mount } from '@vue/test-utils';
import MyCustomModal from './MyCustomModal.vue';

describe("MyCustomModal", () => {
  it("should display the title with the name initial", () => {
    const wrapper = mount(MyCustomModal, {
      props: {
        isOpen: true,
        userName: "John Doe",
      },
    });

    expect(wrapper.element.isOpen).toBe(true);
    // 测试通过

    console.log(wrapper.text());
    // 输出空字符串
    console.log(wrapper.html());
    // 输出<ion-modal data-v-30836913=""></ion-modal>

    expect(wrapper.find("h2").text()).toContain("Your initial is J");
    // 报错:Cannot call text on an empty DOMWrapper.
  });
});

解决方案

Ionic8的ion-modal会将内部内容异步渲染到document.body的独立容器中,而非组件根节点内部,因此测试时需要从全局DOM中获取模态框内容。

1. 访问模态框内容的测试代码

import { mount, flushPromises } from '@vue/test-utils';
import MyCustomModal from './MyCustomModal.vue';

describe("MyCustomModal", () => {
  // 测试后清理模态框元素,避免影响其他测试
  afterEach(() => {
    document.querySelectorAll('ion-modal').forEach(el => el.remove());
  });

  it("should display the title with the name initial", async () => {
    const wrapper = mount(MyCustomModal, {
      props: {
        isOpen: true,
        userName: "John Doe",
      },
    });

    // 等待Ionic模态框异步渲染完成
    await flushPromises();

    // 从全局DOM中获取模态框内容容器
    const modalContent = document.querySelector('ion-modal .ion-modal-content');
    expect(modalContent).not.toBeNull();

    // 将DOM元素包装为vue-test-utils的DOMWrapper,方便查询内部元素
    const contentWrapper = wrapper.wrap(modalContent as HTMLElement);
    expect(contentWrapper.find('h2').text()).toContain("Your initial is J");
  });
});

2. 触发模态框事件的测试代码

要测试didDismiss事件的触发,需要直接在模态框DOM元素上分发对应事件:

it("should emit didDismiss when modal is dismissed", async () => {
  const wrapper = mount(MyCustomModal, {
    props: {
      isOpen: true,
      userName: "John Doe",
    },
  });

  await flushPromises();
  const modalElement = document.querySelector('ion-modal') as HTMLElement;

  // 模拟模态框关闭,分发did-dismiss事件
  modalElement.dispatchEvent(new CustomEvent('did-dismiss'));

  // 验证组件是否正确转发事件
  expect(wrapper.emitted('didDismiss')).toBeTruthy();
  expect(wrapper.emitted('didDismiss')?.length).toBe(1);
});

关键注意事项

  • 必须使用await flushPromises()等待Ionic模态框的异步渲染流程完成,否则无法获取到渲染后的内容。
  • 测试完成后务必清理全局DOM中的模态框元素,防止测试用例之间产生干扰。

内容的提问来源于stack exchange,提问作者Djizeus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 13:15:00