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

使用Vitest+React Testing Library测试Context传参的React组件时找不到元素

测试SelectionDropdown组件时找不到选项元素的问题

我在测试SelectionDropdown组件的选项渲染效果时,遇到了以下错误:

TestingLibraryElementError: Unable to find an accessible element with the role "listitem" and name "option1"

测试代码

describe("SelectionDropDown", () => {
  it("should", async () => {
    const options = [{ name: "option1" }, { name: "option2" }];

    render(
      <SelectionDropdownContextProvider options={options}>
        <SelectionDropdown />
      </SelectionDropdownContextProvider>,
      {
        wrapper: AllProviders
      }
    );

    const button = screen.getByRole("button", { name: /select service/i });
    const user = userEvent.setup();

    await user.click(button);

    options.forEach((option) => {
      const result = screen.getByRole("listitem", { name: option.name });
      expect(result).toBeInTheDocument();
    });
  });
});

组件代码

const SelectionDropdown = () => {
  const { options, serviceType, selectedService, onChange, label } = useSelectionDropdownContext();
  const [isOpen, setIsOpen] = useState(false);
  const dropdownRef = useRef();

  useEffect(() => {
    const handleClickOutside = (e) => {
      if (dropdownRef.current && !dropdownRef.current.contains(e.target))
        setIsOpen(false);
    };

    document.addEventListener("mousedown", handleClickOutside);

    return () => document.removeEventListener("mousedown", handleClickOutside);
  }, []);

  return (
    <div className="dropdown selection-dropdown" ref={dropdownRef}>
      <div
        tabIndex={0}
        role="button"
        className="btn btn-sm"
        onClick={() => {
          setIsOpen((prev) => !prev);
        }}
      >
        {selectedService ?? label ?? "Select Service"}
        <IoMdArrowDropdown />
      </div>
      {isOpen && (
        <ul
          className="dropdown-content z-[2] menu shadow bg-white rounded-box min-w-full"
          tabIndex={0}
        >
          <CreateButton serviceType={serviceType} />
          <li>
            <a
              onClick={() => {
                setIsOpen(false);
              }}
            >
              None
            </a>
          </li>
          {options?.map((option) => (
            <li key={option.unique_id ? option.unique_id : option.id}>
              <a
                onClick={() => {
                  onChange && onChange(option);
                  setIsOpen(false);
                }}
              >
                {option.name}
              </a>
            </li>
          ))}
        </ul>
      )}
    </div>
  );
};

export default SelectionDropdown;

问题分析与修复方案

核心问题

  • 可访问名称不匹配:listitem的可访问名称并非直接对应内部<a>的文本,Testing Library无法通过listitem角色匹配到对应的选项名称。
  • DOM更新时机问题:点击按钮后下拉框展开可能存在异步更新,直接同步查找元素会失败。
  • Key值异常:测试数据中没有unique_id或id字段,导致li的key为undefined,可能引发渲染异常。

具体修复步骤

调整查找逻辑(最快解决)

将查找listitem改为直接查找文本元素,或验证文本元素所在的listitem:

await user.click(button);

options.forEach((option) => {
  const optionText = screen.getByText(option.name);
  expect(optionText).toBeInTheDocument();
  // 可选:验证文本在listitem内
  expect(optionText.closest('li')).toHaveRole('listitem');
});
确保listitem的可访问性

给li添加aria-label,明确其可访问名称:

{options?.map((option) => (
  <li 
    key={option.id || option.name} // 改用name作为备用key,避免undefined
    aria-label={option.name}
  >
    <a
      onClick={() => {
        onChange && onChange(option);
        setIsOpen(false);
      }}
    >
      {option.name}
    </a>
  </li>
))}
等待DOM更新完成

使用waitFor包裹查找逻辑,确保下拉框完全渲染:

await user.click(button);

await waitFor(() => {
  options.forEach((option) => {
    const result = screen.getByRole("listitem", { name: option.name });
    expect(result).toBeInTheDocument();
  });
});
修复测试数据的Key问题

给测试数据添加id字段,避免key为undefined:

const options = [{ name: "option1", id: 1 }, { name: "option2", id: 2 }];

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 19:43:10