Search code examples
reactjsreact-testing-library

Testing using a component that uses useEffect


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


Solution

  • 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();