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

React Testing Library中Input的onBlur事件自动触发测试问题

React测试中onBlur事件未自动触发的原因及解决办法

问题描述

我有一个带输入框和按钮的简单组件,编写测试用例时发现:onBlur事件始终未触发,但onFocus看似正常。比如用fireEvent.change修改输入框内容后点击Continue按钮,实际场景中输入框会失去焦点触发onBlur,但测试里onBlur的console.log没执行。手动调用fireEvent.blur能触发,但不符合真实交互逻辑——实际中onBlur会触发修改页面其他元素的函数。

React组件代码

<div>
   <input
   name="name"
   id="project"
   placeholder="Name of your project"
   onFocus={console.log("Focus called")}
   onBlur={console.log("Blur called")}
   />
   <button>Continue</button>
</div>

测试代码

it('Should submit the answer', async () => {
        renderWithProviders(
            <ProjectNamePage />
        );

        expect(await screen.findByPlaceholderText('Name of your project')).toBeInTheDocument();

        fireEvent.change(screen.getByPlaceholderText('Name of your project'), { target: { value: 'First project' } });

        fireEvent.click(screen.getByText('Continue'));

        // fireEvent.blur(screen.getByPlaceholderText('Name of your project')); 
        
        expect(mockedNavigate).toHaveBeenCalledWith('/smth', undefined);
    });

原因分析及解决办法

1. 组件事件绑定的错误

你当前的onFocus和onBlur写法存在问题:直接写console.log("xxx")会在组件渲染时立即执行,而不是事件触发时才执行。你觉得onFocus“正常触发”,其实是组件初始化时就打印了日志,并非真正的focus事件触发的结果。

修正方法:传递回调函数给事件属性,这样只有当事件触发时才会执行代码:

<div>
   <input
   name="name"
   id="project"
   placeholder="Name of your project"
   onFocus={() => console.log("Focus called")}
   onBlur={() => console.log("Blur called")}
   />
   <button>Continue</button>
</div>

2. 测试工具的选择问题

fireEvent是底层的事件触发工具,它只会触发你指定的单个事件,不会模拟真实用户交互的完整流程(比如点击按钮时自动让输入框失去焦点)。而真实用户点击按钮时,输入框会失去焦点,自动触发onBlur。

解决办法:使用@testing-library/user-event替代fireEvent,它专门模拟真实用户的交互行为,会自动处理焦点切换、事件连锁触发等细节。

修改后的测试代码:

import userEvent from '@testing-library/user-event';

it('Should submit the answer', async () => {
  const user = userEvent.setup();
  renderWithProviders(<ProjectNamePage />);

  const input = await screen.findByPlaceholderText('Name of your project');
  expect(input).toBeInTheDocument();

  // 模拟用户输入文本(自动获取焦点)
  await user.type(input, 'First project');
  // 模拟用户点击按钮(自动让输入框失去焦点,触发onBlur)
  await user.click(screen.getByText('Continue'));

  expect(mockedNavigate).toHaveBeenCalledWith('/smth', undefined);
});

使用userEvent后,点击按钮的操作会自动触发输入框的onBlur事件,无需手动调用fireEvent.blur,完全贴合真实用户的交互逻辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 02:40:18