dorong
dorong

Reputation: 65

How can I test changing states in React?

I'm new to React and trying to test my codes using jest & testing-library/react.

I've made a simple select box and fired the change event on the box. All I wanted is just getting the state but I still don't know how to get it.

This is my component :

import React from "react";
import ReactDOM, { render } from "react-dom";
import NativeSelect from "@material-ui/core/NativeSelect";

const MyTest = () => {
  const [option, setOption] = React.useState("1");

  const handleChange = React.useCallback(e => {
    setOption(e.target.value);
  }, []);

  return (
    <div>
      <h3>selected : {option}</h3>
      <NativeSelect
        inputProps={{ "data-testid": "test-input" }}
        value={option}
        onChange={handleChange}
      >
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
      </NativeSelect>
    </div>
  );
};

export default MyTest;

This is the test :

import React from "react";
import { renderHook, act } from "@testing-library/react-hooks";
import { render, fireEvent } from "@testing-library/react";
import MyTest from "./MyTest";

test("should change state", () => {
  const { result } = renderHook(() => MyTest());

  let { getByTestId } = render(<MyTest />);
  const selectNode = getByTestId("test-input");
  expect(selectNode).not.toBeNull();

  act(() => {
    fireEvent.change(selectNode, { target: { value: "2" } });
  });

  expect(result.current.option).toBe("2");
});

codesandbox is here : https://codesandbox.io/s/distracted-wave-j5fed?fontsize=14

Then the error message from the test is : "Comparing two different types of values. Expected string but received undefined."

I guess "result.current.option" is the wrong way to get the state... How can I get the state of the component?

Plus, according to what I've searched, props and states can be tested quite easily with Enzyme.

If this is right, should I use Enzyme instead of react-testing-library to test states?

Thanks so much in advance.

Upvotes: 1

Views: 15656

Answers (1)

user6516856
user6516856

Reputation:

These two are different objects:

const { result } = renderHook(() => MyTest());

let { getByTestId } = render(<MyTest />);

result.current.option is undefined because result is a component returned not a hook function.

Either you test the state or you test the rendered component.

For testing component:

In your test it should be: expect(selectNode.value).toBe("2") or you follow this from docs: https://reactjs.org/docs/hooks-faq.html#how-to-test-components-that-use-hooks

For testing the state of your hooks. You should extract a custom hook and test it like this.

From https://github.com/testing-library/react-hooks-testing-library:

function useCounter() {
  const [count, setCount] = useState(0)

  const increment = useCallback(() => setCount((x) => x + 1), [])

  return { count, increment }
}

test('should increment counter', () => {
  const { result } = renderHook(() => useCounter())

  act(() => {
    result.current.increment()
  })

  expect(result.current.count).toBe(1)
})

Upvotes: 3

Related Questions