解决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测试的最佳实践,确保测试代码既健壮又面向未来兼容。