37

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?

2
  • 1
    It's (getByTestId("grid-item") in one place and (getByTestId("item") in another. I suppose that's a typo in the question. Commented Nov 3, 2018 at 17:47
  • @estus it is :) Commented Nov 3, 2018 at 20:16

3 Answers 3

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");
Sign up to request clarification or add additional context in comments.

3 Comments

Same error message. It still says that it gets null.
● 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?
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.
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'.

3 Comments

how would I test the value of the href attribute?
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.
@chovy please, see my answer stackoverflow.com/a/76270061/9936102
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/

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.