14

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

5 Answers 5

13

use

getAllByTestId

example:

await waitFor(() => userEvent.click(screen.getAllByTestId('serviceCard')[0]));
Sign up to request clarification or add additional context in comments.

1 Comment

This just feels sub optimal though. Why use getAll when there should be only one elemenet
10
  • 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.

8 Comments

thank you for the answer, what i ended up doing was just doing expect(getAllByTestId("comment-show-more")).toBeTruthy(); which got the tests passing. This answer is still helpful, as i do need to clean up the dom after each test.
what do you think about the edit ? i got the test passing with this approach.
That's ok but I recommend that you should need to know how many comments you rendered in CommentList then get all of them by testId any check if the are correct number.
@BARNOWL Yeah, that's better.
you should not cleanup manually
|
3

It can be solved by use getAllByTestId.

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

Comments

0

Kinda late but this may be helpful for somebody:

I can see that you are using a iterator that might return multiple children, if you want to solve differently, add a literals key for each child when defining your data-testid tag:

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

Comments

0

I encountered a similar issue where Vitest wouldn’t clean the DOM between each render. To resolve this, I added { test: { globals: true } } to my vitest.config.ts. Hope this helps someone!

Comments

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.