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
This may be related to #241 and #393, but it might be different.
If these are separate renders, why can't I assert about them separately?
When using useEffect to sequence events, it seems act causes all the updates to be batched into one. Often this is what you want, but what if I want to assert about the intermediate states here, specifically the moment where a == true and b == false?
functionuseHook(){const[a,setA]=useState(false);const[b,setB]=useState(false);console.log({a, b});// { a: false, b: false }// { a: true, b: false }// { a: true, b: true }// so `setA` is causing one render, and `setB` is causing a second render, as expecteduseEffect(()=>{if(a)setB(true);},[a]);return{a, b,run: ()=>setA(true)};}it("updates a and then b",()=>{const{result}=renderHook(()=>useHook());act(()=>result.current.run());// can't do:// expect(result.current.a).toBe(true);// expect(result.current.b).toBe(false);expect(result.current.b).toBe(true);});
Same issue but now with async setState
If I wrap the initial setA in a setTimeout to make it async (which more resembles the real code I'm basing this on) we need waitForNextUpdate to get any result. This makes sense to me, but it opens up an even bigger space in which it seems like I should be able to assert a == true and b == false.
functionuseHook(){const[a,setA]=useState(false);const[b,setB]=useState(false);useEffect(()=>{if(a)setB(true);},[a]);construn=()=>{setTimeout(()=>{setA(true);});};return{a, b, run};}it("updates a and then b",async()=>{const{result, waitForNextUpdate}=renderHook(()=>useHook());act(()=>result.current.run());// I want to assert a == true and b == false hereawaitwaitForNextUpdate();expect(result.current.b).toBe(true);});
The text was updated successfully, but these errors were encountered:
I'm not sure what to tell you as this is the expected behaviour when using act to trigger updates to the hook's state. act will wait for all the batched updates from successive renders to flush before moving on (at least that's my understanding of what it does).
You can get see the intermediate states in your test if you remove the act and wait for the changes yourself, but you will be met by a big warning in your console from react about not doing that:
it('updates a and then b',async()=>{const{ result, waitForNextUpdate }=renderHook(()=>useHook())result.current.run()expect(result.current.a).toBe(true)expect(result.current.b).toBe(false)awaitwaitForNextUpdate()expect(result.current.b).toBe(true)})
From my perspective, I'm not sure what value you gain from testing that one went true before the other and the timing of those events. It feels very much like an implementation detail of your hook and what you really care about is the end state anyway. Do you care that a was true immediately after run was called and b followed a single render frame later, or that both a and b we true when the rendering was complete?
In any case, there is not much I can do to change the behaviour of act or the warnings react produces when you don't act for updates, but if it is important enough to you, you could try opening an issue in their repo and see what options they can give you.
Thanks for the answer. I agree that it's at best dubious that I would want to assert about that state. The real code that inspired this question was a create and poll hook that makes a POST request and then polls with GETs for progress. So the initial POST coming back would trigger the first GET. Before the GET comes back, it would be in a state analogous to a == true, b == false, so I wanted to assert something about that. But I can live without it.
This may be related to #241 and #393, but it might be different.
If these are separate renders, why can't I assert about them separately?
When using
useEffect
to sequence events, it seemsact
causes all the updates to be batched into one. Often this is what you want, but what if I want to assert about the intermediate states here, specifically the moment wherea == true
andb == false
?Same issue but now with async
setState
If I wrap the initial
setA
in asetTimeout
to make it async (which more resembles the real code I'm basing this on) we needwaitForNextUpdate
to get any result. This makes sense to me, but it opens up an even bigger space in which it seems like I should be able to asserta == true
andb == false
.The text was updated successfully, but these errors were encountered: