解决React测试中act()的弃用警告
问题描述
当使用Jest进行React组件测试时,经常会遇到以下警告消息:
Warning: An update to Component inside a test was not wrapped in act(...).但在使用react@^18.2.0和@testing-library/react@^13.4.0组合时,IDE同时显示act()函数已被弃用:
(6387) The signature '(callback: () => void | Promise): Promise' of 'act' is deprecated核心矛盾在于:
- React要求状态更新需包裹在
act()中 - 新版React的API变更导致IDE显示弃用警告
- 移除
act()会导致测试失败(组件未正确重新渲染)
根本原因
此问题通常由版本不兼容性引起:
- React 18.3.0+ 改变了
act()的API和导入路径 - @testing-library/react <=15.0.5 未适配这个变更
- 测试代码错误地从废弃路径导入
act
典型版本组合问题:
"react": "^18.2.0",
"@testing-library/react": "^13.4.0" // 需要更新解决方案
✅ 最佳方案:更新测试库和React(推荐)
升级相关包到兼容版本:
bash
# 更新React测试库
npm install @testing-library/react@15.0.6
# 兼容的React版本(18.3.1+)
npm install react@18.3.1 @types/react@18.3.1解决关键点:
@15.0.6+支持从react导入act的新路径- React 18.3.1+ 正式导出
act函数
✅ 替代方案:修正导入路径
若无法立即升级,调整act的导入源:
diff
// 修改前(弃用路径)
import { act } from '@testing-library/react'
// 修改后(正确路径)
import { act } from 'react' // React≥18.3.1💡 优化测试代码
使用异步操作最佳实践避免手动act封装:
jsx
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
it('应禁用提交按钮并显示加载状态', async () => {
const user = userEvent.setup()
render(<ContactFormController />)
// 1. 使用async/await替代act
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(screen.getByTestId('contact-submit-button'))
// 2. 使用waitFor处理异步断言
await waitFor(() => {
expect(screen.getByRole('alert')).toBeInTheDocument()
expect(screen.queryByTestId('contact-submit-button')).toBeDisabled()
})
})优化说明:
- 直接使用
userEvent的异步API(如click()返回Promise) waitFor自动处理状态更新边界- 避免手动
act减少冗余代码
现代最佳实践
React Testing Library推荐:
- 优先使用异步API而非手动
act - 用户交互操作使用
await user.click() - 状态更新断言使用
waitFor - 仅遗留组件测试需要手动
act
⚠️ 注意事项
移除冲突包:
bashnpm uninstall react-test-renderer # 避免与新版API冲突React 17+的自动批处理:
javascript// React 17+会自动批量处理渲染更新 // 但仍需确保测试等待更新完成 await screen.findByText('更新后内容')
总结
| 问题类型 | 解决方案 |
|---|---|
| 弃用警告 | 升级到@testing-library/react@≥15.0.6 |
| 测试失败 | 正确导入act:import { act } from 'react' |
| 代码冗余 | 改用异步操作:await user.click()和waitFor |
最终建议工作版本:
json
{
"react": "^18.3.1",
"@testing-library/jest-dom": "^6.1.4",
"@testing-library/react": "^15.0.6",
"@types/react": "^18.3.1"
}正确的更新流程既消除了弃用警告,又符合React测试的最佳实践,确保测试代码既健壮又面向未来兼容。