You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Vue Vitest中访问自定义元素的Shadow DOM以进行测试

如何在Vue Vitest中访问自定义元素的Shadow DOM以进行测试

我之前在测试Vue项目里的Web组件时也遇到过一模一样的问题,尤其是用Vitest的时候,Shadow DOM的访问经常踩坑。让我一步步告诉你怎么解决,帮你顺利测试自定义元素内部的内容:

1. 先确保自定义元素在测试环境中正确注册

Shadow DOM访问失败最常见的原因之一就是自定义元素还没被定义,导致测试执行时元素还不是一个有效的Web组件,自然拿不到Shadow DOM。

  • 如果你的custom-header是用Vue 3的defineCustomElement创建的Web组件,记得在测试前先注册它:
import { defineCustomElement } from 'vue';
import CustomHeader from './components/CustomHeader.ce.vue';

// 注册自定义元素
const CustomHeaderElement = defineCustomElement(CustomHeader);
customElements.define('custom-header', CustomHeaderElement);
  • 如果是第三方Web组件库,要确保在测试文件开头就导入对应的组件脚本,让测试环境能识别这个自定义元素。

2. 等待自定义元素定义完成(关键!)

即使你注册了元素,浏览器(或者测试用的jsdom环境)需要一点时间来完成元素的定义流程。直接去拿shadowRoot很可能会拿到null,因为元素还没初始化好。

一定要用customElements.whenDefined()来等待元素就绪,这个API会返回一个Promise,等元素定义完成后才会resolve:

test('测试custom-header的Shadow DOM内容', async () => {
  const wrapper = mount(YourTestComponent); // 挂载包含custom-header的Vue组件

  // 等待custom-header元素定义完成
  await customElements.whenDefined('custom-header');

  // 现在再去获取元素和Shadow DOM
  const customHeaderEl = wrapper.find('custom-header').element;
  const shadowRoot = customHeaderEl.shadowRoot;

  // 这时候shadowRoot应该就不是null了
  expect(shadowRoot).not.toBeNull();

  // 接下来就可以正常查询内部元素了
  const navEl = shadowRoot.querySelector('nav');
  expect(navEl).toBeTruthy();
  expect(navEl.textContent).toContain('导航内容'); // 测试文本内容
});

3. 排查测试环境的Shadow DOM支持

Vitest默认用jsdom作为测试环境,旧版本的jsdom对Shadow DOM的支持不够完善。如果上面的步骤还是不行,检查一下你的jsdom版本——建议升级到v20以上,确保它支持open模式的Shadow DOM。

你可以在package.json里查看jsdom的版本,或者直接更新:

npm update jsdom --save-dev

4. 用waitFor处理延迟初始化的情况

如果你的Web组件内部有异步逻辑(比如请求数据后渲染内容),Shadow DOM里的元素可能会更晚出现。这时候可以用@testing-library/vue提供的waitFor来轮询元素,直到它出现:

import { waitFor } from '@testing-library/vue';

// ... 前面的注册和挂载代码

await waitFor(() => {
  const navEl = customHeaderEl.shadowRoot?.querySelector('nav');
  expect(navEl).toBeInTheDocument();
}, { timeout: 2000 }); // 可以设置超时时间,默认是1000ms

额外注意事项

  • 你已经确认Shadow DOM是open模式,这点很重要——如果是closed模式,无论如何都拿不到shadowRoot,所以确保组件代码里的Shadow DOM是open的(比如attachShadow({ mode: 'open' }))。
  • 如果你是在Vue SFC里直接使用自定义元素,要确保Vue不会把它当成未知组件处理——可以在Vue配置里把custom-header加入compilerOptions.isCustomElement,避免Vue的编译警告:
// vite.config.js 或者 vue.config.js
export default {
  vue: {
    compilerOptions: {
      isCustomElement: tag => tag === 'custom-header'
    }
  }
}

这样应该就能顺利访问到Shadow DOM里的内容,进行各种断言测试了。如果还有问题,可以检查一下自定义元素的初始化逻辑,看看有没有在connectedCallback里做异步操作导致Shadow DOM延迟生成的情况,这时候只要对应延长等待时间或者等待异步操作完成就行。

备注:内容来源于stack exchange,提问作者SandyKrish

火山引擎 最新活动