You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Tests with async useEffect don't seem to complete #1067
So I guess this is on the back of my question (#1066) where I was trying to reproduce and isolate the issue. However, I have come up against something similar.
I have created a new component MyComponent which has three useEffects which consume async methods (each has appropriate cleanup functions). The test waits for these effects to run, and then assert the final rendered text. However, this never succeeds and the text can never be found. It seems to hang on the second useEffect and the test times out - resulting in the component being unmounted.
Expected behavior
Test should pass and should be able to find 'Hello world.' - this works as expected in simulator with no errors.
Steps to Reproduce
Clone repo, install deps and run npm test or yarn test
I believe the issue is the combination of timeouts and promises. From what I notice, the first promise is never resolved. Not sure this should be handled by the library but I do think in this kind of situation what you want to do is use fake timers. Using real timers with timeouts makes tests less predictable and in some cases quite long running so I'd advise against that.
I managed to make your test work by using fake timers with the following code :
jest.useFakeTimers();test("MyComponent",async()=>{render(<MyComponent/>);// Commenting this out makes it work but with `act` warnings... however// wrapping it in an async `act` causes the test to fail again// await wait({ ms:5000 });// Run timer of stage 1jest.runOnlyPendingTimers();// Wait for promise to be resolvedawaitwaitFor(()=>{});// Run timer of stage 2jest.runOnlyPendingTimers();// Wait for promise to be resolvedawaitwaitFor(()=>{});// Run timer of stage 3jest.runOnlyPendingTimers();awaitscreen.findByText("Hello world.",{},{timeout: 20000});},30000);
This is not ideal as there are waitFor with empty callbacks which act here as a way to flush promises but there is no observable effect at the end of the first two stages. This is a very contrived example though and it should be rather unlikely that you encounter something similar very often
I'm more concerned about why the first promise doesn't resolve ... I can't see any reason it shouldn't. And I don't think I should be limited to fake timers to make this run. Appreciate this is a contrived example, but I currently have real world code that is similar to this - async useEffects updating state to trigger other useEffects.
I'll certainly take a look over your approach. Thanks.
@leepowelldev Does the MyComponent test work correctly if we have only 2 promises? What about a single promise? I wonder what might be threshold fold observed behaviour.
@mdjastrzebski a single promise passes, mutiple promises fails. I don't believe this is a problem with timeouts, but possibly an issue with the promises...
I tried changing the wait util from:
function wait({
ms = 500,
signal,
}: { ms?: number; signal?: AbortSignal } = {}): Promise<void> {
return new Promise((resolve, reject) => {
const id = setTimeout(() => {
resolve()
}, ms);
if (signal) {
signal.addEventListener('abort', () => {
clearTimeout(id);
reject(new Error('Aborted'));
});
}
});
}
to simply:
function wait(): Promise<void> {
return Promise.resolve();
}
I'm pretty sure it's the same as #1093. If you use react 18, we seem to have issues with some cases. In the linked issue there is an attached PR that should fix that.
@leepowelldev If the issue still occurs for you on the latest version of RNTL, please provide update the repo with latest RNTL, React, etc deps so that we are able to reproduce it on our end.
Activity
pierrezimmermannbam commentedon Aug 19, 2022
I believe the issue is the combination of timeouts and promises. From what I notice, the first promise is never resolved. Not sure this should be handled by the library but I do think in this kind of situation what you want to do is use fake timers. Using real timers with timeouts makes tests less predictable and in some cases quite long running so I'd advise against that.
I managed to make your test work by using fake timers with the following code :
This is not ideal as there are waitFor with empty callbacks which act here as a way to flush promises but there is no observable effect at the end of the first two stages. This is a very contrived example though and it should be rather unlikely that you encounter something similar very often
Hope this helps !
leepowellnbs commentedon Aug 19, 2022
I'm more concerned about why the first promise doesn't resolve ... I can't see any reason it shouldn't. And I don't think I should be limited to fake timers to make this run. Appreciate this is a contrived example, but I currently have real world code that is similar to this - async useEffects updating state to trigger other useEffects.
I'll certainly take a look over your approach. Thanks.
mdjastrzebski commentedon Aug 19, 2022
@leepowelldev Does the
MyComponenttest work correctly if we have only 2 promises? What about a single promise? I wonder what might be threshold fold observed behaviour.leepowelldev commentedon Aug 20, 2022
@mdjastrzebski a single promise passes, mutiple promises fails. I don't believe this is a problem with timeouts, but possibly an issue with the promises...
I tried changing the
waitutil from:to simply:
And still got the same issues.
leepowellnbs commentedon Sep 21, 2022
FYI I tested this in
@testing-library/reactand it passes as expected.AugustinLF commentedon Sep 21, 2022
I'm pretty sure it's the same as #1093. If you use react 18, we seem to have issues with some cases. In the linked issue there is an attached PR that should fix that.
mdjastrzebski commentedon Sep 26, 2022
I've retested the repro repo you submitted with following deps update and all tests pass:
Note: the tests seem to require Node 16, due to
AbortControllernot available in Node 14.@leepowelldev can you confirm the RNTL v11.2.0 (with potential React, React Test Renderer and React Native updates) does solve the issue for you.
mdjastrzebski commentedon Sep 30, 2022
Closing as fixed.
@leepowelldev If the issue still occurs for you on the latest version of RNTL, please provide update the repo with latest RNTL, React, etc deps so that we are able to reproduce it on our end.
leepowellnbs commentedon Sep 30, 2022
@mdjastrzebski sorry, this was on my "todo" list, but it's been a busy few days and it slipped my mind. Thanks for the fix and for testing 🙇