使用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
相关产品推荐
相关产品推荐

