Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Testing Library: Test if Elements have been mapped/rendered

Issue:

I have a list of Items that I want to test by each one of the items name value (string). I'm using @testing-library/react and have the test suite correctly working, but I can't get my test to work.

Overview:

  • Each item has a test id of data-testid="side-menu-link". Does this have to be unique or can it be tested as is?
  • The menuItems consist of strings like Dashboard, Settings, and User Preferences

DisplayItems.test.tsx:

// Imports: Dependencies
import React from 'react';
import { render, screen } from '@testing-library/react';

// Imports: App
import App from '../../App';

// Side Menu: Dashboard
test('Renders Dashboard correctly', () => {
  // Render: App
  const { getByTestId } = render(<App />);

  // Expect
  expect(getByTestId('side-menu-link')).toHaveAttribute('Dashboard')
});


// Side Menu: User Preferences
test('Renders Dashboard correctly', () => {
  // Render: App
  const { getByTestId } = render(<App />);

  // Expect
  expect(getByTestId('side-menu-link')).toHaveAttribute('User Preferences')
});

Map Items:

// Map Menu Items
return menuItems.map((menuItem, i) => {
  return (
    <Link data-testid="side-menu-link" key={i} href="#" className="side-menu-link" to={`/${menuItem.itemName}`}>
      <div className={props.currenttab === `${menuItem.itemName}` ? 'side-menu-item-container-selected-light' : 'side-menu-item-container-light'}>
        {menuItem.itemIcon}
        <p className={props.currenttab === `${menuItem.itemName}` ? 'side-menu-title-selected-light' : 'side-menu-title-light'}>{menuItem.itemName}</p>
      </div>
    </Link>
  );
});
like image 971
jefelewis Avatar asked Oct 15 '25 02:10

jefelewis


1 Answers

You can have multiple testIDs. Otherwise, there wouldn't be __AllByTestId selectors. The name wasn't well-thought out, it seems, because of similarity to HTML ids which must be unique.

A throw happens if you use __ByTestId yet you have multiple elements with the matching test id:

it("getByTestId will throw with multiple testIDs", () => {
  const {getAllByTestId, getByTestId} = render(
    <View>
      <Text testID="foo">a</Text>
      <Text testID="foo">b</Text>
    </View>
  );
  expect(getAllByTestId("foo")).toHaveLength(2); // OK
  getByTestId("foo"); // => Error: Found multiple elements with testID: foo
});

To test a map, you can add test ids to the children and use the above pattern.

React Native:

import "@testing-library/jest-native/extend-expect";

// ...

it("should find text content in all children", () => {
  const {getAllByTestId} = render(
    <View>
      {[..."abcd"].map((e, i) => 
        <View key={e + i} testID="foo"><Text>{e}</Text></View>
      )}
    </View>
  );

  expect(getAllByTestId("foo")).toHaveLength(4);
  
  [..."abcd"].forEach((e, i) => {
    expect(getAllByTestId("foo")[i]).toHaveTextContent(e);
  });
});

React:

it("should find text content in all children", () => {
  const {getAllByTestId} = render(
    <ul>
      {[..."abcd"].map((e, i) => 
        <li key={e + i} data-testid="foo">{e}</li>
      )}
    </ul>
  );

  expect(getAllByTestId("foo")).toHaveLength(4);

  [..."abcd"].forEach((e, i) => {
    expect(getAllByTestId("foo")[i].textContent).toEqual(e);
  });

  // or:
  //const contents = getAllByTestId("foo").map(e => e.textContent);
  //expect(contents).toEqual([..."abcd"]);
});

It's also possible to add a testID to the parent of the mapped list elements, select the parent, then traverse over its .children array to make assertions on each child tree.

Note the differences between testID in RN and data-testid in React.


As a side note, I'm not sure

expect(getByTestId('side-menu-link')).toHaveAttribute('User Preferences')

makes much sense here. attributes are <div this_is_an_attribute="foo"> -- you're probably looking for text content.


Packages used, for reference:

React Native

{
  "dependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-native": "^0.64.0",
    "react-native-web": "^0.15.6"
  },
  "devDependencies": {
    "@babel/core": "^7.13.15",
    "@testing-library/jest-native": "^4.0.1",
    "@testing-library/react-native": "^7.2.0",
    "babel-jest": "^26.6.3",
    "jest": "^26.6.3",
    "metro-react-native-babel-preset": "^0.65.2",
    "react-test-renderer": "^17.0.2"
  }
}

React

{
  "dependencies": {
    "@babel/runtime": "7.10.5",
    "react": "16.13.1",
    "react-dom": "16.13.1",
  },
  "devDependencies": {
    "@babel/core": "7.10.5",
    "@babel/plugin-proposal-class-properties": "7.10.4",
    "@babel/preset-env": "7.10.4",
    "@babel/preset-react": "7.10.4",
    "@testing-library/dom": "7.21.0",
    "@testing-library/jest-dom": "^5.11.1",
    "@testing-library/react": "10.4.7",
    "@testing-library/react-hooks": "3.3.0",
    "@testing-library/user-event": "12.0.11",
    "babel-jest": "26.1.0",
    "jest": "26.1.0",
    "jest-environment-jsdom": "26.1.0",
    "react-test-renderer": "16.13.1",
  }
}
like image 115
ggorlen Avatar answered Oct 17 '25 17:10

ggorlen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!