React Select测试中下拉菜单无法保持展开,但浏览器中正常
问题场景
我用以下配置的AsyncReactSelect组件,开启了多选且设置closeMenuOnSelect={false},浏览器里选中选项后菜单能正常保持展开:
<AsyncReactSelect defaultOptions loadOptions={async () => [ { value: "Pear", label: "Pear" }, { value: "Banana", label: "Banana" }, { value: "Raspberry", label: "Raspberry" }, ]} closeMenuOnSelect={false} isMulti />
但在测试代码里,用userEvent.type触发Enter选中选项后,菜单直接关闭了,fireEvent.click也没用,甚至onMenuClose回调在测试里被莫名触发(浏览器里只有点击菜单外部才会触发):
await act(async () => { // 打开下拉框 const selectDropdown = screen.getAllByRole("combobox")[0] await userEvent.click(selectDropdown) await screen.findByText("Pear") screen.debug() // 第一次debug能看到所有选项 await userEvent.type(selectDropdown, "{enter}") screen.debug() // 第二次debug菜单已关闭 })
解决方法
1. 直接点击选项元素(最推荐)
测试里给combobox发Enter事件的逻辑,和组件内部的事件处理可能不匹配,换成直接点击对应的选项元素,更贴近真实用户操作:
await act(async () => { const selectDropdown = screen.getAllByRole("combobox")[0]; await userEvent.click(selectDropdown); // 找到Pear选项并点击 const pearOption = await screen.findByText("Pear"); await userEvent.click(pearOption); screen.debug(); // 此时菜单应该保持展开状态 });
2. 等待组件状态完全同步
AsyncReactSelect的异步加载可能在测试环境里有状态更新延迟,虽然已经用findByText等选项出现,但可以加个微任务等待状态稳定:
await act(async () => { const selectDropdown = screen.getAllByRole("combobox")[0]; await userEvent.click(selectDropdown); await screen.findByText("Pear"); // 等待组件内部状态完成更新 await new Promise(resolve => setTimeout(resolve, 0)); await userEvent.click(await screen.findByText("Pear")); screen.debug(); });
3. 调整键盘事件触发方式或升级userEvent
不同版本的@testing-library/user-event对键盘事件的模拟有差异,试试用keyboard方法替代type,或者升级到最新稳定版:
await act(async () => { const selectDropdown = screen.getAllByRole("combobox")[0]; await userEvent.click(selectDropdown); await screen.findByText("Pear"); // 用keyboard方法触发Enter键 await userEvent.keyboard("{enter}"); screen.debug(); });
4. 手动控制组件状态(备选方案)
如果上面的方法都不行,可以通过ref直接操作组件实例,手动选中选项并强制保持菜单展开:
// 组件里先设置ref const selectRef = useRef(null); <AsyncReactSelect ref={selectRef} ... /> // 测试代码中调用 await act(async () => { const selectDropdown = screen.getAllByRole("combobox")[0]; await userEvent.click(selectDropdown); await screen.findByText("Pear"); // 手动选中选项并强制打开菜单 selectRef.current.selectOption({ value: "Pear", label: "Pear" }); selectRef.current.setState({ menuIsOpen: true }); screen.debug(); });
内容的提问来源于stack exchange,提问作者Red Baron
相关产品推荐
相关产品推荐

