How can I test certain elements are being rendered in my component asynchronously?

Viewed 695

I am working on updating my portfolio project which is built using React, and I've recently started learning about testing using Jest and React Testing Library, so I wanted to refactor the project to incorporate tests.

I have 2 components that I am working with: Projects, and ProjectCard.

Projects is the container component that fetches project information from a local JSON file in the public folder and then for each project, render a ProjectCard component.

Here is the code for the Projects component:

const Projects = () => {
    const sectionName = navLinks[0].toLowerCase();

    const [projects, setProjects] = useState([]);

    useEffect(() => {
        const getProjects = async () => {
            const response = await fetch('./assets/Projects.json');
            const json = await response.json();
            setProjects(json);
        };

        getProjects();

        // cleanup
        return () => {
            setProjects([]);
        };
    }, []);

    return (
        <section className={sectionName} id={sectionName} data-testid={sectionName}>
            <Heading text={sectionName} color='maire' />
            <ul className='projects__list'>
                {projects.map((project) => (
                    <ProjectCard key={project.projectTitle} project={project} />
                ))}
            </ul>
        </section>
    );
};

What I am trying to do is simply check that there are a non-0 number of li elements (ProjectCard components) being rendered inside the ul element above. I eventually realized that since my elements are being rendered asynchronously, getAllByRole would not work, and have been using findAllByRole as it returns a Promise.

Here is the test code I have written:

test('renders project cards without error', async () => {
    render(<Projects />);
    const listItems = await screen.findAllByRole('listitem');
    await waitFor(() => expect(listItems.length).not.toBe(0));
});

The error I am seeing is:

Unable to find role="listitem"

<body>
  <div>
    <section class="projects" data-testid="projects" id="projects">
      <h2 class="heading text-maire">
        projects
      </h2>
      <ul
        class="projects__list"
      />
    </section>
  </div>
</body>

  16 | test('renders project cards without error', async () => {
  17 |      render(<Projects />);
> 18 |      const listItems = await screen.findAllByRole('listitem');
     |                                     ^
  19 |      await waitFor(() => expect(listItems.length).not.toBe(0));
  20 | });
  21 |

  at waitForWrapper (node_modules/@testing-library/dom/dist/wait-for.js:173:27)
  at findAllByRole (node_modules/@testing-library/dom/dist/query-helpers.js:101:33)
  at Object.<anonymous> (src/components/Projects/Projects.test.jsx:18:33)

In addition to this, how do I go about performing tests for the ProjectCard component, since all of the JSX is rendered asynchronously? If someone could help me figure this one out, it would be much appreciated! Thanks!

0 Answers
Related