Jir
Jir

Reputation: 3125

Jest: `querySelector` returns null in test of a ReactJS component

I'm testing a connected functional component in ReactJS using jest and the react-testing-library.

The component renders some input fields and a button. Here's a simplified version of it, in which I decided to leave the full structure of GridContainer and GridItem components (from Material-UI) as they might play a role in this issue:

export function Letter(props) {
  const [letter, setLetter] = useState({
    // not relevant
  });

  return (
    <GridContainer>
      <GridItem md={6} sm={6}>
        <GridContainer>
          <GridItem>
            <LetterImageUpload />
          </GridItem>
          <GridItem>
            <LetterText />
          </GridItem>
        </GridContainer>
      </GridItem>
      <GridItem md={6} sm={6}>
        <LetterAddress />
        <GridContainer>
          <Button
            data-testid="AddToStoreButton"
            onClick={() => {
              props.addToStore(letter);
            }}
          >
            Add to Store
          </Button>
        </GridContainer>
      </GridItem>
    </GridContainer>
  );
}

function mapDispatchToProps(dispatch) {
  return {
    addToStore: letter => {
      dispatch({ type: "ADD_TO_STORE", payload: letter });
    }
  };
}

export default connect(
  null,
  mapDispatchToProps
)(Letter);

As you can see I export both the dumb component and the connected component (the latter via export default), so that I can just import { Letter } in my tests and not bother about the redux store (is this the right way?).

The accompanying test goes like this:

import { Letter } from "components/Letter/Letter.js";

let container = null;
beforeEach(() => {
  container = document.createElement("div");
  document.body.appendChild(container);
});

afterEach(() => {
  unmountComponentAtNode(container);
  container.remove();
  container = null;
});

test("Letter", () => {
  act(() => {
    render(<Letter addToStore={jest.fn()} />, container);
  });
  // FIXME: querySelector returns null
  container.querySelector('[data-testid="AddToStoreButton"]').simulate("click");
  // assert
});

In a debugger I can see that querySelector returns null regardless of the selector I used. For instance, I tried the following in the live debugger:

> container.querySelector('[data-testid="AddToCartButton"]')
null
> container.querySelector("button")
null
> container.querySelector("div")
null

I'm clearly doing something spectacularly wrong. Can anyone spot it?

Upvotes: 1

Views: 12909

Answers (1)

Jir
Jir

Reputation: 3125

Following the tip by Anthony, it turned out I was using render from the react testing library, but actually using as it were the one exported by the "react-dom" library.

The complete solution, using the react testing library looks like this:

import { fireEvent, render } from "@testing-library/react";

test("Letter", () => {
  const { getByTestId } = render(<Letter addToStore={() => {}} />);
  fireEvent.click(getByTestId("AddToStoreButton"));
  // assert
});

Just to add a bit of more context, if you follow the approach shown in the Testing Recipes on ReactJS.org, you'll need to import { render } from "react-dom", instead.

Upvotes: 1

Related Questions