React测试中act已弃用却被Jest要求使用的解决方案咨询
React测试中act弃用警告与组件重渲染等待问题的解决方案
问题核心
你遇到的矛盾本质是:React 18+测试环境自动批处理状态更新,无需手动调用act,但旧代码依赖act强制等待状态更新,移除后因未正确等待异步用户操作导致测试失败;同时旧版act(callback)签名已被弃用,触发IDE警告。
解决方案
关键修改点
- 移除手动
act调用:Testing Library的render、userEvent等API内部已自动用act包裹所有触发组件更新的操作,手动调用旧版act会触发弃用警告。 - 使用
userEvent.setup()创建实例:这是@testing-library/user-eventv13+的推荐用法,确保异步操作的生命周期被正确管理。 - 等待所有异步用户操作完成:每个
userEvent的操作(如type、click)都是异步的,必须用await等待其完成,确保组件状态更新和重渲染结束后再执行断言。
修改后的测试代码
import '@testing-library/jest-dom' import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import ContactFormController from '.' describe('Contact Form Controller tests', () => { it('should render loader and disable submit button on form submit', async () => { render(<ContactFormController />) const submitBtn = screen.getByTestId('contact-submit-button') const user = userEvent.setup() await user.type(screen.getByLabelText(/^First Name/i), 'Captain') await user.type(screen.getByLabelText(/^Last Name/i), 'Bob') await user.type(screen.getByLabelText(/^Email/i), 'captain@bob.com') await user.type(screen.getByPlaceholderText(/^Greetings/i), 'Captain Ahoy') await user.click(submitBtn) expect(screen.getByRole('alert')).toBeInTheDocument() expect(submitBtn).toBeDisabled() }) })
额外优化说明
- 替换
component.getBy*为screen.getBy*:这是Testing Library官方推荐的查询方式,无需保留render返回的组件实例,简化代码的同时符合测试最佳实践。 - 若遇到异步操作(如表单提交后的API请求),可配合
waitFor辅助函数等待断言条件满足,例如:await waitFor(() => { expect(screen.getByRole('alert')).toBeInTheDocument() })
原理说明
- React 18+在测试环境中默认启用自动批处理,所有由用户交互、状态更新触发的组件更新会被自动批量处理,无需手动
act包裹。 @testing-library/user-eventv13+的setup()方法会创建一个绑定了测试上下文的用户事件实例,其返回的异步方法会自动等待组件更新完成,本质上已经封装了act的逻辑。- 之前移除
act后测试失败,是因为未等待userEvent的异步操作完成,导致组件还未完成状态更新和重渲染就执行了断言,此时断言的目标元素或状态尚未出现。
内容的提问来源于stack exchange,提问作者user3146945
相关产品推荐
相关产品推荐

