Skip to content

Tests timeout with jest fakeTimers and waitFor for on Promise.resolve calls #873

Open
@5c077yP

Description

@5c077yP

Hey, I get some of my tests timing out when using waitFor and jest.useFakeTimers, but not using a timer internally, but only Promise.resolve. As a context I'm trying to migrate a bigger code base from v4 to the latest version from v5 on some tests are failing. I'm also using jests faketimers by default for the tests.

This might be a bit related to #631

  • react-hooks-testing-library version: 8.0.1
  • react version: 17.02
  • react-dom version (if applicable): 17.02
  • react-test-renderer version (if applicable): 17.02
  • node version: 16.14.2
  • yarn version: 1.22.10

Relevant code or config:

const React = require('react');
const { renderHook } = require('@testing-library/react-hooks');

jest.useFakeTimers(); // modern or fake doesn't matter here

const useStateAndAsyncEffect = (fn) => {
  const [s, set] = React.useState(false);

  React.useEffect(() => {
    Promise.resolve().then(() => set(true));
  }, []);

  React.useEffect(() => {
    if (s) fn();
  }, [s]);

  return;
};

test('test hook', async () => {
  const fn = jest.fn();
  const { waitFor } = renderHook(() => useStateAndAsyncEffect(fn));
  await waitFor(() => expect(fn).toHaveBeenCalled());
});

What happened:

The test fails from v5 and onwards, but worked in v4.

Suggested solution:

I was digging a bit into the code and saw v4 is calling act inside async-utils inside the while(true) loop, while from v5 upwards act is only called once. I've tried to figure out the details, but not really sure why calling act more than once is making this work. I'm thinking about react flushing micro tasks more often, but also not very familiar with react internals/fibers.

I've played with patch-package on got this diff working for me. Please let me know what you think about it 🙏

diff --git a/node_modules/@testing-library/react-hooks/lib/core/asyncUtils.js b/node_modules/@testing-library/react-hooks/lib/core/asyncUtils.js
index dbf1a49..77b9785 100644
--- a/node_modules/@testing-library/react-hooks/lib/core/asyncUtils.js
+++ b/node_modules/@testing-library/react-hooks/lib/core/asyncUtils.js
@@ -26,9 +26,11 @@ function asyncUtils(act, addResolver) {
 
     const waitForResult = async () => {
       while (true) {
-        const intervalSignal = (0, _createTimeoutController.createTimeoutController)(interval);
-        timeoutSignal.onTimeout(() => intervalSignal.cancel());
-        await intervalSignal.wrap(new Promise(addResolver));
+        await act(async () => {
+          const intervalSignal = (0, _createTimeoutController.createTimeoutController)(interval);
+          timeoutSignal.onTimeout(() => intervalSignal.cancel());
+          await intervalSignal.wrap(new Promise(addResolver));
+        })
 
         if (checkResult() || timeoutSignal.timedOut) {
           return;
@@ -37,7 +39,7 @@ function asyncUtils(act, addResolver) {
     };
 
     if (!checkResult()) {
-      await act(() => timeoutSignal.wrap(waitForResult()));
+      await timeoutSignal.wrap(waitForResult());
     }
 
     return !timeoutSignal.timedOut;

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions