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

React Jest单元测试中自定义Dropdown的blur失焦关闭功能不生效如何解决

问题成因

  1. 你当前使用的fireEvent仅能触发单一的指定事件,不会模拟真实用户交互的完整事件流,点击外部元素时不会自动触发下拉根元素的blur事件。
  2. 你测试用例中的外部<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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 04:12:01