Vitest单元测试中TipTap编辑器内容无法渲染的问题排查
TipTap Vue组件单元测试无法渲染内容的问题分析
问题说明
我有一个集成TipTap编辑器的Vue 3组件,在浏览器中运行完全正常,但用Vitest结合vue-test-utils写单元测试时,无法渲染出编辑器的内容。尝试用vue/testing-library的render函数测试,结果也一样。
组件代码
<script setup lang="ts"> import { useEditor, EditorContent } from "@tiptap/vue-3"; import StarterKit from "@tiptap/starter-kit"; const props = defineProps({ text: { type: String, default: "", }, }); const editor = useEditor({ content: props.text, extensions: [StarterKit], }); </script> <template> <editor-content class="entry-text" :editor="editor" /> </template>
测试代码
it("displays content", () => { const wrapper = mount(EntryEditor, { propsData: { text: "Testing" }, }); console.log(wrapper.vm.text); // output: Testing console.log(wrapper.element.outerHTML); // output: <div class="entry-text"></div> });
原因分析
- 编辑器初始化是异步的:TipTap的
useEditor方法是异步初始化编辑器实例的,单元测试中mount组件后立即检查DOM,此时编辑器还没完成初始化和内容渲染,所以DOM是空的。 - 测试环境API缺失:单元测试用的jsdom环境缺少部分真实浏览器的DOM API(比如Range、Selection等),TipTap的渲染逻辑依赖这些API,导致内容无法正常渲染到DOM中。
解决方案
方案1:等待编辑器初始化完成
利用TipTap编辑器的ready状态(一个Promise),在测试中等待编辑器就绪后再断言内容:
it("displays content", async () => { const wrapper = mount(EntryEditor, { props: { text: "Testing" }, // Vue3推荐用props代替propsData }); // 等待编辑器完成初始化 await wrapper.vm.editor.ready; // 再等待Vue的DOM更新周期 await wrapper.vm.$nextTick(); // 断言编辑器内容 expect(wrapper.find(".ProseMirror").text()).toBe("Testing"); });
方案2:直接测试编辑器内容而非DOM
如果DOM渲染在测试环境中受限,可以直接测试TipTap编辑器实例的内容,不需要依赖DOM:
it("has correct content", async () => { const wrapper = mount(EntryEditor, { props: { text: "Testing" }, }); await wrapper.vm.editor.ready; // 断言编辑器的HTML内容 expect(wrapper.vm.editor.getHTML()).toBe("<p>Testing</p>"); });
方案3:补充测试环境缺失的API
如果是jsdom缺少必要的API导致渲染失败,可以在测试的全局setup中补充模拟这些API。比如安装jsdom-extended或者手动模拟Range等对象,不过TipTap官方已经对测试环境做了部分适配,优先尝试前两种方案。
内容的提问来源于stack exchange,提问作者Nicole Harris
相关产品推荐
相关产品推荐

