Search code examples
reactjsreact-testing-library

fireEvent is calling Found multiple elements by: data-testid error in react-testing-library


I'm calling a function by finding the button with the data-testid with "show_more_button"

<OurSecondaryButton test={"show_more_button"} onClick={(e) => showComments(e)} component="span" color="secondary">
    View {min !== -1 && min !== -2 ? min : 0} More Comments
</OurSecondaryButton>

showComments

const showComments = (e) => {
  e.preventDefault();
  if (inc + 2 && inc <= the_comments) {
     setShowMore(inc + 2);
     setShowLessFlag(true);
  } else {
     setShowMore(the_comments);
  }
};

which renders this

const showMoreComments = () => {
    return filterComments.map((comment, i) => (
        <div data-testid="comment-show-more" key={i}>
            <CommentListContainer ref={ref} comment={comment} openModal={openModal} handleCloseModal={handleCloseModal} isBold={isBold} handleClickOpen={handleClickOpen} {...props} />
        </div>
    ));
};

and upon executing fireEvent the function gets called which is good but, im getting the error:

TestingLibraryElementError: Found multiple elements by: [data-testid="comment-show-more"]

(If this is intentional, then use the `*AllBy*` variant of the query (like `queryAllByText`, `getAllByText`, or `findAllByText`)).

There is only one data-testid with "comment-show-more", i doubled checked, this function must be getting triggered multiple times in the same test i guess, Im not sure..

CommentList.test.tsx

   it("should fire show more action", () => {
      const { getByTestId } = render(<CommentList {...props} />);
      const showMore = getByTestId("show_more_button");
      fireEvent.click(showMore);
      expect(getByTestId("comment-show-more").firstChild).toBeTruthy();
   });

CommentList.test.tsx (full code)

import "@testing-library/jest-dom";
import React, { Ref } from "react";
import CommentList from "./CommentList";
import { render, getByText, queryByText, getAllByTestId, fireEvent } from "@testing-library/react";
import { Provider } from "react-redux";
import { store } from "../../../store";

const props = {
    user: {},
    postId: null,
    userId: null,
    currentUser: {},
    ref: {
        current: undefined,
    },
    comments: [
        {
            author: { username: "barnowl", gravatar: "https://api.adorable.io/avatars/400/bf1eed82fbe37add91cb4192e4d14de6.png", bio: null },
            comment_body: "fsfsfsfsfs",
            createdAt: "2020-05-27T14:32:01.682Z",
            gifUrl: "",
            id: 520,
            postId: 28,
            updatedAt: "2020-05-27T14:32:01.682Z",
            userId: 9,
        },
        {
            author: { username: "barnowl", gravatar: "https://api.adorable.io/avatars/400/bf1eed82fbe37add91cb4192e4d14de6.png", bio: null },
            comment_body: "fsfsfsfsfs",
            createdAt: "2020-05-27T14:32:01.682Z",
            gifUrl: "",
            id: 519,
            postId: 27,
            updatedAt: "2020-05-27T14:32:01.682Z",
            userId: 10,
        },
        {
            author: { username: "barnowl2", gravatar: "https://api.adorable.io/avatars/400/bf1eed82fbe37add91cb4192e4d14de6.png", bio: null },
            comment_body: "fsfsfsfsfs",
            createdAt: "2020-05-27T14:32:01.682Z",
            gifUrl: "",
            id: 518,
            postId: 28,
            updatedAt: "2020-05-27T14:32:01.682Z",
            userId: 11,
        },
    ],
    deleteComment: jest.fn(),
};
describe("Should render <CommentList/>", () => {
    it("should render <CommentList/>", () => {
        const commentList = render(<CommentList {...props} />);
        expect(commentList).toBeTruthy();
    });

    it("should render first comment", () => {
        const { getByTestId } = render(<CommentList {...props} />);
        const commentList = getByTestId("comment-list-div");
        expect(commentList.firstChild).toBeTruthy();
    });

    it("should render second child", () => {
        const { getByTestId } = render(<CommentList {...props} />);
        const commentList = getByTestId("comment-list-div");
        expect(commentList.lastChild).toBeTruthy();
    });

    it("should check comments", () => {
        const rtl = render(<CommentList {...props} />);

        expect(rtl.getByTestId("comment-list-div")).toBeTruthy();
        expect(rtl.getByTestId("comment-list-div")).toBeTruthy();

        expect(rtl.getByTestId("comment-list-div").querySelectorAll(".comment").length).toEqual(2);
    });
    // it("should match snapshot", () => {
    //     const rtl = render(<CommentList {...props} />);
    //     expect(rtl).toMatchSnapshot();
    // });

    it("should check more comments", () => {
        const { queryByTestId } = render(<CommentList {...props} />);
        const commentList = queryByTestId("comment-show-more");
        expect(commentList).toBeNull();
    });

    it("should fire show more action", () => {
        const { getByTestId } = render(<CommentList {...props} />);
        const showMore = getByTestId("show_more_button");
        fireEvent.click(showMore);
        expect(getByTestId("comment-show-more").firstChild).toBeTruthy();
    });
});

Solution

    • Try to clean up the DOM after each test

    import { cleanup } from '@testing-library/react'
    // Other import and mock props
    describe("Should render <CommentList/>", () => {
        afterEach(cleanup)
        // your test
    }

    Note: You have filterComments.map so make sure filterComments have one item.