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

React Native测试中已await act仍触发未await警告,求原因解析

问题:已用await包裹act,仍出现"未await异步act调用"警告

场景与代码

待测试的自定义Hook

export function useSomethingSaver() {
  let somethingMutation = useMutation(async (newSomething) => {
    return await saveSomething(newSomething)
  })

  return {
    saveSomething: somethingMutation.mutate,
    saveSomethingAsync: somethingMutation.mutateAsync,
    isLoading: somethingMutation.isLoading,
    isError: somethingMutation.isError,
  }
}

测试代码

import { act, renderHook, waitFor } from '@testing-library/react-native'

...

it('Something can be saved', async () => {
  saveSomething.mockImplementation(() => SOMETHING_DATA)

  const wrapper = ({ children }) => (
    <BaseContexts queryClient={queryClient}>{children}</BaseContexts>
  )

  const { result } = renderHook(() => useSomethingSaver(), { wrapper })

  await act(async () => {
    await result.current.saveSomething(SOMETHING_SAVE_DATA)
  })
  await waitFor(() => !result.current.isLoading)

  expect(saveSomething).toBeCalledWith(SOMETHING_SAVE_DATA)
})

控制台警告信息

console.error
  Warning: You called act(async () => ...) without await. This could lead to unexpected testing behaviour, interleaving multiple act calls and mixing their scopes. You should - await act(async () => ...);

    at printWarning (node_modules/react/cjs/react.development.js:209:30)
    at error (node_modules/react/cjs/react.development.js:183:7)
    at node_modules/react/cjs/react.development.js:2559:15
    at tryCallOne (node_modules/promise/lib/core.js:37:12)
    at node_modules/promise/lib/core.js:123:15
    at flush (node_modules/asap/raw.js:50:29)

补充的act语句(仍出现警告)

const { result } = renderUseSomethingSaver();

await act(async () => {
   await result.current.saveSomethingAsync(SOMETHING_SAVE_DATA);
});
await waitFor(() => !result.current.isLoading);

问题原因分析

1. 针对saveSomething(mutate)的情况

saveSomething对应React Query的mutate方法,它本身是同步执行的,不会返回Promise。你在act回调里await result.current.saveSomething(...)完全无效——这个await会立即完成,act提前结束,但React Query内部的异步请求和状态更新(比如isLoading的变化)是在act执行完毕后才触发的,这部分状态更新没有被act包裹,React就会抛出警告(提示文案有歧义,实际不是你没await act,而是act范围没覆盖到后续的状态更新)。

2. 针对saveSomethingAsync(mutateAsync)的情况

mutateAsync返回Promise,你await它确实会等待请求完成,但React Query的状态更新(比如isLoading变为false)可能是在Promise resolve之后才触发的,这部分更新同样不在你手动写的act范围内,因此警告依然出现。

3. Testing Library的内置处理逻辑

Testing Library的renderHook和waitFor已经内置了act的处理,手动包裹act反而会导致状态更新的范围不匹配。

修正后的测试代码

不需要手动用act包裹异步操作,直接调用方法后用waitFor等待状态变化即可:

it('Something can be saved', async () => {
  saveSomething.mockImplementation(() => SOMETHING_DATA)

  const wrapper = ({ children }) => (
    <BaseContexts queryClient={queryClient}>{children}</BaseContexts>
  )

  const { result } = renderHook(() => useSomethingSaver(), { wrapper })

  // 直接调用异步方法,无需手动act包裹
  await result.current.saveSomethingAsync(SOMETHING_SAVE_DATA);
  
  // waitFor会自动用act包裹状态更新的等待逻辑
  await waitFor(() => expect(result.current.isLoading).toBe(false));

  expect(saveSomething).toBeCalledWith(SOMETHING_SAVE_DATA)
})

如果用同步的mutate方法:

it('Something can be saved', async () => {
  saveSomething.mockImplementation(() => SOMETHING_DATA)

  const wrapper = ({ children }) => (
    <BaseContexts queryClient={queryClient}>{children}</BaseContexts>
  )

  const { result } = renderHook(() => useSomethingSaver(), { wrapper })

  // 调用同步的mutate方法
  result.current.saveSomething(SOMETHING_SAVE_DATA);
  
  // 用waitFor等待状态更新,内部自动处理act
  await waitFor(() => expect(result.current.isLoading).toBe(false));

  expect(saveSomething).toBeCalledWith(SOMETHING_SAVE_DATA)
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 08:10:32