test("shows the user after loading", async () => {
render(<Profile id="1" />);
expect(screen.getByText(/loading/i)).toBeInTheDocument();
expect(await screen.findByRole("heading", { name: "Ana" })).toBeInTheDocument();
expect(screen.queryByText(/loading/i)).not.toBeInTheDocument();
});
Mock the network, assert the loading state right after render, then wait for the data to appear.
The steps:
- Mock the network, ideally with MSW (Mock Service Worker). Then the component's real fetch code runs against a predictable response.
- Render the component. Assert the loading state synchronously with
getBy*, because it's there on the first render. - Wait for the data with
await screen.findByText(...)orfindByRole. These retry until the element appears. - Assert the spinner is gone with
queryBy*.
Another option for the last step: await waitForElementToBeRemoved(() => screen.queryByText(/loading/i)) waits for the spinner to disappear.
Avoid fixed setTimeout delays. Don't wrap things in act just to silence warnings. Wait for the visible result instead. This makes the test correct, and it also removes the act warnings.
- Mock the network so the component's real fetch code runs.
- Assert the loading state right after render.
- Use
await findBy*to wait for the loaded data. - Assert the spinner is gone with
queryBy*orwaitForElementToBeRemoved. - Don't use fixed sleeps.
Read more