I have an async method that changes the state by callback:
class Demo{
callback: () => void;
async triggerCallback() {
this.callback();
}
}
This callback is being used to hide/show an element:
const DemoComponent: React.FunctionComponent<Props> = ({Demo}) =>{
const [show, setShow] = useState(false);
const changeStateCallback = () => {
setState(true);
}
useEffect(() =>{
Demo.callback = changeStateCallback;
}, []);
return(
<>
{show && <p>Foo</p>}
</>
)
};
I now want to test this and I'm still learning testing with Jest and React Testing Library, so at first I had:
it("test", async () => {
const Demo = new Demo();
render(<DemoComponent Demo={Demo}/>);
await Demo.triggerCallback();
expect(screen.queryByText("Foo")).toBeTruthy();
}
And this failed because it complained that Demo.triggerCallback(); had to be wrapped in an act():
When testing, code that causes React state updates should be wrapped into act(...):
act(() => { /* fire events that update state / }); / assert on the output */
Which I did with the async/await rules:
it("test", async () => {
const Demo = new Demo();
render(<DemoComponent Demo={Demo}/>);
await act( async () =>{
await Demo.triggerCallback();
};
expect(screen.queryByText("Foo")).toBeTruthy();
}
It failed again saying I couldn't make act async:
Warning: The callback passed to ReactTestUtils.act(...) function must not return anything.
It looks like you wrote ReactTestUtils.act(async () => ...), or returned a Promise from the callback passed to it. Putting asynchronous logic inside ReactTestUtils.act(...) is not supported.
After some research in the docs and google, I found this waitFor() method but together with expect, e.g.:
await waitFor(() => {
expect(getByText('1')).toBeInTheDocument();
});
But for sake of it, I replaced act() for waitFor() since it's one of the few async methods I found in the react testing library. Final look (I wrapped it in a try/catch just in case):
it("test", async () => {
const Demo = new Demo();
render(<DemoComponent Demo={Demo}/>);
try {
await waitFor( async () =>{
await Demo.triggerCallback();
};
} catch(e) {
fail("Test failed": + e);
}
expect(screen.queryByText("Foo")).toBeTruthy();
}
And the test passes! Now... is this correct? Just because it works I'm unsure of the solution so would like some feedback on this. I feel I'm doing something illegal because I could only find waitFor() examples with expect() and nothing else.