I have the following hook :
const useBar = () => {
const [myFoo, setFoo] = useState(0);
const [myBar, setBar] = useState(0);
useEffect(() => {
setFoo(myFoo + 1);
console.log("setting foo (1)", myFoo, myBar);
}, [setFoo, myFoo, myBar]);
useEffect(() => {
setBar(myBar + 1);
console.log("setting bar (2)", myFoo, myBar);
}, [setBar, myBar, myFoo]);
};
When working with a component I have the expected behaviour of infinite loop :
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
const Bar = () => {
useBar();
return <div>Bar</div>;
};
function App() {
return (
<Bar />
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
From console.log :
setting foo (1) 1 1
setting bar (2) 1 1
setting foo (1) 2 2
setting bar (2) 2 2
setting foo (1) 3 3
setting bar (2) 3 3
...
However testing this with @testing-library/react-hooks
gives only the first loop output :
describe("Tests", () => {
test("useBar", async () => {
const { rerender } = renderHook(() => {
return useBar();
});
// await waitForNextUpdate();
// tried the above doesn't work
// rerender();
// with rerender it loops through the next "cycle"
});
});
Was wondering how to test properly hooks, without calling rerender
and mimic the same behaviour as React - to re-render the component on state changes.
act
helper: codesandbox.io/s/ecstatic-ardinghelli-hsctu (keep in mind it's a contrived example). – Brutal@testing-library/react-hooks
but, as Simon said, have you tried using the build it act fromreact-dom/test-utils
? – PenetrantuseEffect
. I've put the infinite loop there, since sometimes your hook might go to infinite loop because of this effect and since you probably want to test that this doesn't happen. On the other hand hooks with 2+useEffect
are not executed properly when tested withreact-hooks-testing-library
, so that's the reason of my question. If you find the example illogical, please try to think : "How to test that a hook is not running an infinite loop, due to interdependentuseEffect
" – NervineuseEffect
( check usehooks.com/useEventListener as an example ). There are lots of places where you need to have async action and the only way to achieve that would be inside auseEffect
. On the other handsetBar
is a function used in the hook and the officialeslint
react hooks plugin complains if not added. – NervinemyFoo
ormyBar
from theuseBar
hook, callrerender
and see if they have incremented as expected. But that doesn't really help you as what you really want to know is if you ended up with an infinite loop. Another way I had some success identifying something was wrong was usingwaitForElement
, but it doesn't necessarily fail the test and requires you to test the integration of the hook instead of testing the hook directly. – Brutal