CodePark/ questions / Async UI & act()
START PRACTICINGPRACTICE
Frontend question · Testing › Async UI & act()

How do you test a component that shows a loading state, then fetched data?

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(...) or findByRole. 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* or waitForElementToBeRemoved.
  • Don't use fixed sleeps.