Home > Enterprise >  React testing with Jest and React Testing Library not renderin text displayed on the webpage
React testing with Jest and React Testing Library not renderin text displayed on the webpage

Time:12-03

I have a NextJS app that I am using Jest and React Testing Library to test. I have a card component that is passed data (id, image url, text, and name) that is rendered on the card. This works correctly on the webpage. When I run the test, the test cannot find any text on the page.

Here is the component:

import React from "react";

import Image from "next/image";

import styles from "./testCard.module.css";

export default function TestCard(data) {
  const card = data.data;

  return (
    <>
      <div className={styles.cardContainer}>
        <div className={styles.cardTop}>
          <div className={styles.cardImg}>
            <Image
              src={card.imgUrl}
              alt=""
              height={150}
              width={150}
              loading="lazy"
              className={styles.circular}
            />
          </div>
        </div>
        <div className={styles.cardBottom}>
          <div className={styles.cardText}>
            <p>&quot;{card.text}&quot;</p>
          </div>
          <div className={styles.cardName}>
            <p>-{card.name}</p>
          </div>
        </div>
      </div>
    </>
  );
}

Here is the test file:

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

import TestCard from "./testCard";

import { testimonialMock } from "../../__mocks__/next/testimonialMock";

describe("TestCard Component", () => {
  it("renders the component", () => {
    render(<TestCard data={testimonialMock} />);
  });
  it("renders the component unchanged", () => {
    const { containter } = render(<TestCard data={testimonialMock} />);
    expect(containter).toMatchSnapshot();
  });
  it("renders the passed in data", () => {
    render(<TestCard data={testimonialMock} />);
    screen.getByRole('p', {name: /test text/i});    
  });
});

And here is the testimonialMock.js file:

export const testimonialMock = [
  {
    id: 0,
    imgUrl: "/img/mock.png",
    text: "test text",
    name: "test name",
  },
];

Here is the result I am getting:

TestCard Component
    ✓ renders the component (12 ms)
    ✓ renders the component unchanged (5 ms)
    ✕ renders the passed in data (15 ms)

  ● TestCard Component › renders the passed in data

    TestingLibraryElementError: Unable to find an element with the text: test text. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

    Ignored nodes: comments, script, style
    <body>
      <div>
        <div
          
        >
          <div
            
          >
            <div
              
            />
          </div>
          <div
            
          >
            <div
              
            >
              <p>
                "
                "
              </p>
            </div>
            <div
              
            >
              <p>
                -
              </p>
            </div>
          </div>
        </div>
      </div>
    </body>

      17 |   it("renders the passed in data", () => {
      18 |     render(<TestCard data={testimonialMock} />);
    > 19 |     expect(screen.getByText("test text")).toBeInTheDocument();
         |                   ^
      20 |   });
      21 | });
      22 |

      at Object.getElementError (node_modules/.pnpm/@testing-library [email protected]/node_modules/@testing-library/dom/dist/config.js:40:19)
      at node_modules/.pnpm/@testing-library [email protected]/node_modules/@testing-library/dom/dist/query-helpers.js:90:38
      at node_modules/.pnpm/@testing-library [email protected]/node_modules/@testing-library/dom/dist/query-helpers.js:62:17
      at node_modules/.pnpm/@testing-library [email protected]/node_modules/@testing-library/dom/dist/query-helpers.js:111:19
      at Object.getByText (components/testCard/testCard.test.js:19:19)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 2 passed, 3 total
Snapshots:   1 passed, 1 total
Time:        0.725 s, estimated 1 s
Ran all test suites matching /testCard.test.js/i.

I have tried using different forms of passing in the data and different queries, all to no avail.

CodePudding user response:

Use a single object as the mock (no data prop inside it), but fix the confusing use of data instead of props for the component arguments.

Then use the getByText instead of the getByRole

so

export default function TestCard(props) {
  const card = props.data;
  ....
}

then in your mock file

export const testimonialMock = {
    id: 0,
    imgUrl: "/img/mock.png",
    text: "test text",
    name: "test name",
  };

and finally in the test

 screen.getByText(/test text/i);

CodePudding user response:

data should be object not an array

export const testimonialMock = {
  data:{
    id: 0,
    imgUrl: "/img/mock.png",
    text: "test text",
    name: "test name",
  },
}

also check the element exists by text

const text = screen.getByText("test text")

CodePudding user response:

In your test, you are trying to use screen.getByRole to get an element with the role "p" and the name "test text". However, it looks like the elements in your component do not have any roles assigned to them. Instead of using getByRole, you could try using getByText to search for the text that you are looking for in the component.

Here is an example of how you could use getByText in your test:

it("renders the passed in data", () => {
  render(<TestCard data={testimonialMock} />);
  screen.getByText(/test text/i);
});

In this example, getByText will search for any element that contains the text "test text", ignoring case. If it finds an element that contains this text, the test will pass. If it does not find any elements that match, the test will fail.

CodePudding user response:

If you are still having trouble getting the text to appear in your test, there are a few things that you can try to troubleshoot the issue.

First, make sure that the text you are searching for is actually present in the rendered component. You can do this by logging the result of screen.debug() to the console, which will show the HTML of the rendered component. Then, check to see if the text you are looking for is included in the HTML output.

If the text is present in the rendered HTML, but the getByText assertion is still failing, you can try using a different selector to search for the element. For example, instead of using getByText, you could try using getByTestId to search for an element with a specific data-testid attribute.

Here is an example of how you could use getByTestId in your test:

it("renders the passed in data", () => {
  render(<TestCard data={testimonialMock} />);
  expect(screen.getByTestId("test-text")).toBeInTheDocument();
});

In this example, the getByTestId method will search for an element with the attribute data-testid="test-text". If it finds an element that matches this criteria, the test will pass. If it does not find any elements that match, the test will fail.

You will need to add the data-testid attribute to the elements in your component in order for this approach to work. For example, you could add a data-testid attribute to the p element that contains the "test text" like this:

<p data-testid="test-text">"{card.text}"</p>
  • Related