最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

javascript - Jest: `querySelector` returns null in test of a ReactJS component - Stack Overflow

matteradmin4PV0评论

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

The ponent 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 ponents (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 ponent and the connected ponent (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 acpanying test goes like this:

import { Letter } from "ponents/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?

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

The ponent 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 ponents (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 ponent and the connected ponent (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 acpanying test goes like this:

import { Letter } from "ponents/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?

Share Improve this question edited Jul 5, 2020 at 17:51 skyboyer 23.8k7 gold badges62 silver badges71 bronze badges asked Jul 4, 2020 at 6:27 JirJir 3,1558 gold badges47 silver badges70 bronze badges 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 ponent. – Anthony Commented Jul 4, 2020 at 12:45
  • Interesting. I was following the testing recipes from ReactJS, but I realise now that the render ponent there es from "react-dom" rather than the react testing library. I'll try and follow your hint. – Jir Commented Jul 4, 2020 at 14:14
Add a ment  | 

1 Answer 1

Reset to default 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 plete 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, you'll need to import { render } from "react-dom", instead.

Post a comment

comment list (0)

  1. No comments so far