Reputation: 1166
I am testing my component wit react-testing-library and test works well. I just can't get rid of this warning, fireEvent should by wrapped in act out-of-the-box, but I tried to wrap it again and it did'nt help.
Here is my test case.
it.only("should start file upload if file is added to the field", async () => {
jest.useFakeTimers();
const { getByTestId } = wrapper;
const file = new File(["filefilefile"], "videoFile.mxf");
const fileInput = getByTestId("drop-zone").querySelector(
"input[type='file']"
);
fireEvent.change(fileInput, { target: { files: [file] } });
act(() => {
jest.runAllTimers();
});
await wait(() => {
expect(
initialProps.uploadItemVideoFileConnect.calledWith(file, 123)
).toBe(true);
});
});
Here is the warning
Warning: An update to UploadButtonGridComponent inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
act(() => {
/* fire events that update state */
});
/* assert on the output */
Upvotes: 37
Views: 59617
Reputation: 2860
Shortened version of @jaredsk answer:
await act(() => fireEvent.submit(form));
Since async do not have to be define while returning promise
Upvotes: 0
Reputation: 173
I had a strange bug where it was giving this error and freezing for a subcomponent and the error was thrown in the parent's render function in the test.
I was simply missing brackets[]s in a useEffect.
Upvotes: 0
Reputation: 2958
So this is hard to summarise but I'll try.
The act
warning is simply telling you that there is something happening in your functional component which you're not testing.
Let's say we're rendering a list of todos like so
<ul>
{loading ? (
<p>Fetching todos</p>
) : (
<>
{appData.todoList.slice(0, 15).map((item) => {
const { id, title } = item;
return (
<li key={id} data-testid={id}>
<Link to={`/item/${id}`}>{title}</Link>
</li>
);
})}
</>
)}
</ul>
The below test case will throw the act
warning
import { waitFor, screen, waitForElementToBeRemoved } from "@testing-library/react";
it("Renders <TodoList /> component", async () => {
render(<TodoList />);
await waitFor(() => expect(axios.get).toHaveBeenCalledTimes(1));
await waitForElementToBeRemoved(() => screen.getByText(/Fetching todos/i));
expect(axios.get).toHaveBeenCalledTimes(1);
todos.slice(0, 15).forEach((td) => {
expect(screen.getByText(td.title)).toBeInTheDocument();
});
});
But if you re-order the await
lines like so
await waitForElementToBeRemoved(() => screen.getByText(/Fetching todos/i));
await waitFor(() => expect(axios.get).toHaveBeenCalledTimes(1));
The act
warning goes away. This makes sense. You get to make sure your users no longer see the loading indicator.
There are other cases so go ahead and read this post from kent Dodds.
https://kentcdodds.com/blog/fix-the-not-wrapped-in-act-warning
Upvotes: 15
Reputation: 1073
That issue is caused by many updates inside Component.
I got the same, this is how I solved the issue.
await act( async () => {
fireEvent.change(fileInput, { target: { files: [file] } });
});
Upvotes: 54
Reputation: 2786
In the source code, fireEvent
is already wrapped in act()
.
The problem may be related to this issue, in which async logic (such as a useEffect
) is triggering state changes outside of fireEvent:
https://github.com/kentcdodds/react-testing-library/issues/281
(Without seeing your component implementation it's hard to be sure if this is exactly what's happening in your case.)
Apparently there are plans to include async handling in a future release, so that this won't be a problem.
Upvotes: 17