React testing library: Test attribute / prop
Asked Answered
E

3

36

I'm writing a React app using TypeScript. I use material-ui for my components and react-testing-library for my unit tests.

I'm writing a wrapper for material-ui's Grid component so that I always have an item.

import Grid from "@material-ui/core/Grid";
import withStyles, { WithStyles } from "@material-ui/core/styles/withStyles";
import React, { PureComponent } from "react";
import styles from "./styles";

export interface OwnProps {
  className?: string;
}

export interface Props extends WithStyles<typeof styles>, OwnProps {}

export interface DefaultProps {
  className: string;
}

export class GridItem extends PureComponent<Props & DefaultProps> {
  static defaultProps: DefaultProps = {
    className: ""
  };

  render() {
    const { classes, children, className, ...rest } = this.props;
    return (
      <Grid
        data-testid="grid-item"
        item={true}
        {...rest}
        className={classes.grid + " " + className}
      >
        {children}
      </Grid>
    );
  }
}

export default withStyles(styles)(GridItem);

I want to write a unit test that checks if item={true}. I tried to use the helper library jest-dom's toHaveAttribute like this:

import "jest-dom/extend-expect";
import React from "react";
import { cleanup, render } from "react-testing-library";
import GridItem, { OwnProps } from "./GridItem";
afterEach(cleanup);

const createTestProps = (props?: object): OwnProps => ({
  ...props
});

describe("Parallax", () => {
  const props = createTestProps();
  const { getByTestId } = render(<GridItem {...props} />);
  describe("rendering", () => {
    test("it renders the image", () => {
      expect(getByTestId("grid-item")).toHaveAttribute("item", "true");
    });
  });
});

But this test fails with:

● GridItem › rendering › it renders the image

    expect(element).toHaveAttribute("item", "true") // element.getAttribute("item") === "true"

    Expected the element to have attribute:
      item="true"
    Received:
      null

      14 |   describe("rendering", () => {
      15 |     test("it renders the image", () => {
    > 16 |       expect(getByTestId("grid-item")).toHaveAttribute("item", "true");
         |                                        ^
      17 |     });
      18 |   });
      19 | });

      at Object.toHaveAttribute (src/components/Grid/GridItem/GridItem.test.tsx:16:40)

Test Suites: 1 failed, 3 passed, 4 total
Tests:       1 failed, 3 passed, 4 total
Snapshots:   0 total
Time:        1.762s, estimated 2s
Ran all test suites related to changed files.

How can I test if an element has a certain attribute?

Exaggerated answered 3/11, 2018 at 15:35 Comment(2)
It's (getByTestId("grid-item") in one place and (getByTestId("item") in another. I suppose that's a typo in the question.Deglutinate
@estus it is :)Exaggerated
D
24

jest-dom toHaveAttribute assertion asserts item attribute while the test tries to test item prop.

item prop won't necessarily result in item attribute, and since it's non-standard attribute it most probably won't.

react-testing-library propagates functional testing and asserts resulting DOM, this requires to be aware of how components work. As can be seen here, item props results in adding a class to grid element.

All units but tested one should be mocked in unit tests, e.g.:

...
import GridItem, { OwnProps } from "./GridItem";

jest.mock("@material-ui/core/Grid", () => ({
  default: props => <div data-testid="grid-item" className={props.item && item}/>
}));

Then it could be asserted as:

  expect(getByTestId("grid-item")).toHaveClass("item");
Deglutinate answered 3/11, 2018 at 17:46 Comment(3)
Same error message. It still says that it gets null.Exaggerated
● GridItem › rendering › it is an item expect(element).toHaveAttribute("item") // element.hasAttribute("item") Expected the element to have attribute: item Received: null Is the error message that comes up. How can I test whether the element has the attribute item=true?Exaggerated
I see. Assertion message is misleading. null means that there's no attribute at all. The problem is it won't have item attribute. I updated the answer to explain that. If you want to test actual code (e.g. props) rather than its effects on DOM I'd suggest to switch to Enzyme.Deglutinate
P
11

If someone is still having this issue I solved it this way:

it('Check if it is a materialUI Grid item', () => {
    //Rendering the component in a constant.
    const { container } = render(<YourComponent />); 
    //Accessing the grid wrapper. In this case by the attribute you provided.
    const grid = container.querySelector('[data-testid="grid-item"]'); 
    //What we are expecting the grid to have.  
    expect(grid).toHaveClass('MuiGrid-item');
})

Notes:

  1. I noticed that in the code item it's been declared as a string and not as a boolean: item='true', which will trigger a warning when you run the test. item={true} is the correct way of declaring it. Actually in material UI when you write item inside a grid its of course by default true, in my opinion is not necessary.
  2. item is a class inside material UI Grid as the previous answer correctly suggested. So by that the correct class name should be refered in this case is 'MuiGrid-item'.
Pecan answered 25/8, 2020 at 18:49 Comment(3)
how would I test the value of the href attribute?Massacre
I believe you can access any attribute with dot syntax. This worked for me for testing that a button is disabled: const btnSave = screen.getByRole('button', { name: 'Save' }); expect(btnSave.disabled).toEqual(true); so maybe something like expect(elem.href).toEqual('https://my-href.com'); will work for you.Squeegee
@Massacre please, see my answer https://mcmap.net/q/422021/-react-testing-library-test-attribute-propDumfries
D
6

I had a different case, but the title of the question brought me here. So, if you want to check if a rendered element has a particular attribute value, you can use the getAttribute method on the found element:

  it('should have red fill', () => {
      const color = 'red';
      const { container } = render(<YourComponent color="red" />);

      expect(container.querySelector('your-selector').getAttribute('fill')).toBe(color);
  });

More info here: https://www.wilbertom.com/post/react-testing-library-testing-a-node-attribute/

Dumfries answered 17/5, 2023 at 8:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.