0

I am trying to test a component that uses useEffect to fetch data from api, which then saves the data in useState so i can map over that data and display data.

component:

    import React, { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import fetchContinents from "../../api/fetchContinents";

export const ContinentsList = () => {
  const [continents, setContinent] = useState();

  useEffect(() => {
    fetchContinents().then((continent) => setContinent(continent));
  }, []);

  return (
    <div className="flex justify-center items-center h-screen">
      <ul className="w-1/4 md:w-1/2">
        {continents?.data?.continents.map((continent) => {
          return (
            <Link to={`/countries/${continent.code}`}>
              <div
                key={continent.code}
                className="bg-green-700 text-white rounded-2xl text-center mx-2 my-2 py-6 hover:bg-blue-500"
              >
                {continent.name}
              </div>
            </Link>
          );
        })}
      </ul>
    </div>
  );
};

test:

import { render, screen, waitFor } from "@testing-library/react";
import "@testing-library/jest-dom";
import { ContinentsList } from "./ContinentsList";

describe("ContinentsList", () => {
  test("Renders Africa on the page", async () => {
    render(<ContinentsList />);
    const africa = screen.getByText("Africa");

    await waitFor(() => {
      expect(africa).toBeInTheDocument();
    });
  });
});

test runner output: enter image description here

The components renders this on the page:

enter image description here

So i think the problem is the component is rendered before the useEffect finishes fetching the data and there is nothing in the DOM ad the time of assertion, I have did a bit of googling and i have added waitFor which i think i should wait a bit before assessing but it react testing library

1

1 Answer 1

3

It's always a bit confusing. I've written mine slightly differently and I believe I had the same issue:

Instead of writing this:

const africa = screen.getByText("Africa");

await waitFor(() => {
  expect(africa).toBeInTheDocument();
});

Try writing this:

await waitFor(() => screen.getByText("Africa"));

expect(screen.getByText("Africa")).toBeInTheDocument();
Sign up to request clarification or add additional context in comments.

2 Comments

This seems to work but i had to add some extras to my test, because i am using <Link> from React Router i had this error: useHref() may be used only in the context of a <Router> component. so found this fix: render(<ContinentsList />, { wrapper: MemoryRouter }); and the test is now working
Which is the same as await screen.getByText("Africa").waitFor(); but one fewer imports and no need for a new function argument.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.