1

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?

2
  • The docs I just scanned don't use a container like you did, instead an imported screen object. The render() method also returns an object with a container property that can be used for testing the component. Commented Jul 4, 2020 at 12:45
  • Interesting. I was following the testing recipes from ReactJS.org, but I realise now that the render component there comes from "react-dom" rather than the react testing library. I'll try and follow your hint. Commented Jul 4, 2020 at 14:14

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

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.