react-hooks-testing-library icon indicating copy to clipboard operation
react-hooks-testing-library copied to clipboard

Asyncs utils: You called act(async () => ...) without await

Open enzzoperez opened this issue 4 years ago • 6 comments

Hi!, Im starting to test my hooks (in a POC stage), I have a simple test that works but I get the following warning that I dont know how can it solved :thinking:

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 console.error (node_modules/@testing-library/react-hooks/lib/core/console.js:19:7)
      at printWarning (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:68:30)
      at error (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:44:5)
      at node_modules/react-test-renderer/cjs/react-test-renderer.development.js:15297:13
      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)

this is my hook

import {useState, useEffect} from 'react';

const defaultValue = {data: 'Default'};

const useRemoteData = ({data}: any) => {
  const [response, setResponse] = useState<any>();
  const [error] = useState<any>();
  const [isLoading] = useState(true);

  useEffect(() => {
    data ? setTimeout(() => setResponse(data), 500) : setResponse(defaultValue);
  }, [data]);

  return {response, error, isLoading};
};

export default useRemoteData;

and in my test file, Im trying to test that if the props change, the data will change too

  import {renderHook} from '@testing-library/react-hooks';
  import useRemoteData from './useRemoteData';


  it('Init error false ', async () => {
    const {result, waitFor, rerender} = renderHook(
      ({data}) => useRemoteData({data}),
      {
        initialProps: {data: 'first render'},
      },
    );

    await waitFor(() => {
      expect(result.current.response).toEqual('first render');
    });

    rerender({data: 'second render'});

    await waitFor(() => {
      expect(result.current.response).toEqual('second render');
    });
  });

Am I forgetting something in the test file?

Thanks!

enzzoperez avatar Apr 13 '22 05:04 enzzoperez

Same issue here! The problem comes when using more than one awaited waitFor in the same it Already read the act behavior in this PR https://github.com/callstack/react-native-testing-library/pull/969/files and tried all the suggestions of this issue https://github.com/callstack/react-native-testing-library/issues/379.

tcank avatar May 04 '22 16:05 tcank

We can fix the problem using the solution proposed on https://stackoverflow.com/questions/64952449/react-native-testing-act-without-await/69201830#69201830 It seems that react-native jest preset is replacing global Promise implementation (2020 issue https://github.com/facebook/react-native/issues/29303) and this leads to the act-await warning.

The patch consists in add one previous preset and one post preset in order to save the original implementation and restore it after react-native preset is set. We do this and found that many tests started to fail (many), and in order to not debug each one, we change the patch to save the original implementation (in first preset) in global.nativePromise and polyfilled in global.polyfilledPromise (in last preset). Later, when we need to fix the Act Await warning, we swap the implementations only for a specific test suite calling fixActAwaitWarning:

const fixActAwaitWarning = (): void => {
  beforeAll(() => {
    global.Promise = global.nativePromise;
  });
  afterAll(() => {
    global.Promise = global.polyfilledPromise;
  });
};

tcank avatar May 06 '22 12:05 tcank

Thank you for your effort and investigation into this @tcank.

mpeyper avatar May 07 '22 08:05 mpeyper

We can fix the problem using the solution proposed on https://stackoverflow.com/questions/64952449/react-native-testing-act-without-await/69201830#69201830 It seems that react-native jest preset is replacing global Promise implementation (2020 issue facebook/react-native#29303) and this leads to the act-await warning.

The patch consists in add one previous preset and one post preset in order to save the original implementation and restore it after react-native preset is set. We do this and found that many tests started to fail (many), and in order to not debug each one, we change the patch to save the original implementation (in first preset) in global.nativePromise and polyfilled in global.polyfilledPromise (in last preset). Later, when we need to fix the Act Await warning, we swap the implementations only for a specific test suite calling fixActAwaitWarning:

const fixActAwaitWarning = (): void => {
  beforeAll(() => {
    global.Promise = global.nativePromise;
  });
  afterAll(() => {
    global.Promise = global.polyfilledPromise;
  });
};

Do you mean to change the content of restore-promise.js like this:

global.polyfilledPromise = Promise;

I found it really works!

farid-mitchi avatar Jul 06 '22 02:07 farid-mitchi

This is still happening. It only happens when I use more than one awaited waitFor in the same it.

robbporto avatar Apr 11 '23 23:04 robbporto