React Jest单元测试中自定义Dropdown的blur失焦关闭功能不生效如何解决
问题成因
- 你当前使用的
fireEvent仅能触发单一的指定事件,不会模拟真实用户交互的完整事件流,点击外部元素时不会自动触发下拉根元素的blur事件。 - 你测试用例中的外部
<a>标签默认没有tabIndex属性,无法获得焦点,点击后不会夺走下拉组件根div的焦点,导致onBlur回调根本没有执行。JSDOM(Jest依赖的DOM模拟环境)的焦点行为和真实浏览器存在差异,不会默认将焦点转移到不可聚焦的普通元素上。
解决方案
推荐使用React Testing Library官方推荐的@testing-library/user-event库模拟用户行为,它会完整复现真实用户交互的事件序列,包括焦点转移逻辑。
修正后测试代码
import userEvent from '@testing-library/user-event' it('should close and reset dropdown when a click is produced outside of it', async () => { // 初始化userEvent实例 const user = userEvent.setup() render(<> <MultilevelDropdown {...multilevelDropdownProps} /> {/* 给外部元素添加tabIndex使其可聚焦,确保点击后能夺走下拉的焦点 */} <div> <a data-testid='outside-element' tabIndex={0}> Test </a> </div> </>); const multilevelDropdownTrigger = screen.getByText('Ajouter une démarche'); // 所有userEvent操作都是异步的,需要加await await user.click(multilevelDropdownTrigger); const group = screen.getByText('Matière'); await user.click(group); expect(screen.getByText('Polyamide Recyclé')).toBeInTheDocument(); // 点击外部元素 await user.click(screen.getByTestId('outside-element')); expect(screen.queryByText('Matière')).not.toBeInTheDocument(); expect(screen.queryByText('Polyamide Recyclé')).not.toBeInTheDocument(); expect(multilevelDropdownTrigger).not.toHaveClass('dropdown__trigger__open'); });
备选快速验证方案
如果你只想快速验证onBlur逻辑的正确性,也可以直接手动触发下拉根元素的blur事件:
// 点击展开下拉后,找到下拉根节点 const dropdownRoot = screen.getByText('Ajouter une démarche').closest('.dropdown') as HTMLElement; fireEvent.blur(dropdownRoot); // 后续断言保持不变
内容的提问来源于stack exchange,提问作者Antoine Deloy
相关产品推荐
相关产品推荐

