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?
To find elements by className in React testing library: Render a component and destructure the container object from the result. Use the getElementsByClassName() method on the container to find elements by class name.
getByTestId does return the first item with that test ID in the virtual DOM. I am able to get all of the test items by using the test renderer directly and doing a findAllByProp query from there.
Where do we put data-testid ? To enable test automation support in applications using a React testing library, we need to provide a special data-testid attribute for each component. It must be placed on the containing element of each section and all related subsections.
If you wish to update the props of a rendered component in your React testing library test, then you can simply use the rerender function like so: In this way, you won't be remounting the component.
The React Testing Library is a very light-weight solution for testing React components. It provides light utility functions on top of react-dom and react-dom/test-utils, in a way that encourages better testing practices. Its primary guiding principle is:
Most of your React test cases should use methods for finding elements. React Testing Library provides you with several methods to find an element by specific attributes in addition to the getByText () method above: getByText (): find the element by its textContent value getByRole (): by its role attribute value
You want to write maintainable tests for your React components. As a part of this goal, you want your tests to avoid including implementation details of your components and rather focus on making your tests give you the confidence for which they are intended.
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");
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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With