Skip to content

解决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()会导致测试失败(组件未正确重新渲染)

根本原因

此问题通常由版本不兼容性引起:

  1. React 18.3.0+ 改变了act()的API和导入路径
  2. @testing-library/react <=15.0.5 未适配这个变更
  3. 测试代码错误地从废弃路径导入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

⚠️ 注意事项

  1. 移除冲突包

    bash
    npm uninstall react-test-renderer  # 避免与新版API冲突
  2. React 17+的自动批处理

    javascript
    // React 17+会自动批量处理渲染更新
    // 但仍需确保测试等待更新完成
    await screen.findByText('更新后内容')

总结

问题类型解决方案
弃用警告升级到@testing-library/react@≥15.0.6
测试失败正确导入actimport { 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测试的最佳实践,确保测试代码既健壮又面向未来兼容。