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

React Testing Library+Jest测试Shadow DOM自定义表单元素遇阻

问题排查与解决方案

核心问题分析

  1. 循环逻辑错误:你每个hds-input组件的Shadow DOM里只对应单个表单字段(比如mapName对应一个hds-input,rawDataSiteName对应另一个),但你在循环所有hds-input时,每个元素里都去查找两个不同name的输入框,必然会有一个返回null——因为当前遍历的hds-input根本不包含另一个字段。
  2. Shadow DOM访问方式问题:Testing Library默认不自动穿透Shadow DOM,但可以通过手动访问元素的shadowRoot属性来获取内部元素,同时注意异步操作的处理。

修正后的测试代码示例

首先给React组件中的每个hds-input添加data-testid标识(方便精准定位):

// 在你的Order3DMaps组件中
<hds-input data-testid="map-name-input" name="mapName" />
<hds-input data-testid="raw-data-site-input" name="rawDataSiteName" />
<hds-input data-testid="organization-id-input" name="organizationId" disabled />

然后编写测试用例:

it("check form input fields with dummy values", async () => {
  render(<Order3DMaps />);
  
  expect(screen.getByText("Basic Information")).toBeInTheDocument();

  // 精准定位每个hds-input组件
  const mapNameHdsInput = screen.getByTestId("map-name-input");
  const rawDataSiteHdsInput = screen.getByTestId("raw-data-site-input");
  const organizationIdHdsInput = screen.getByTestId("organization-id-input");

  // 从每个组件的Shadow DOM中获取对应的输入框
  const mapNameField = mapNameHdsInput.shadowRoot.querySelector("input[name='mapName']");
  const rawDataSiteField = rawDataSiteHdsInput.shadowRoot.querySelector("input[name='rawDataSiteName']");
  const organizationIdField = organizationIdHdsInput.shadowRoot.querySelector("input[name='organizationId']");

  // 异步操作要加await,保证输入完成后再进行断言
  await userEvent.type(mapNameField, "testmapname");
  await userEvent.type(rawDataSiteField, "testrawsite");

  // 验证禁用状态
  expect(organizationIdField).toBeDisabled();
});

进阶优化(适配新版Testing Library)

如果你的@testing-library/dom版本≥8.11.0,可以直接使用带shadow: true参数的查询方法,无需手动访问shadowRoot,更符合Testing Library的查询理念:

it("check form input fields with dummy values", async () => {
  render(<Order3DMaps />);
  
  expect(screen.getByText("Basic Information")).toBeInTheDocument();

  // 直接穿透Shadow DOM查找输入框(按用户可见的标签/名称查询)
  const mapNameField = await screen.findByRole('textbox', { name: /map name/i, shadow: true });
  const rawDataSiteField = await screen.findByRole('textbox', { name: /raw data site name/i, shadow: true });
  const organizationIdField = await screen.findByRole('textbox', { name: /organization id/i, shadow: true });

  await userEvent.type(mapNameField, "testmapname");
  await userEvent.type(rawDataSiteField, "testrawsite");

  expect(organizationIdField).toBeDisabled();
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 14:55:25