3

I am trying to test functionality in my component, the basic idea is some state is set and when a button is pressed a function is called with the set state. The code works but when I try to test this I don't get the expected result, it is as if the state never gets set during the test.

I am using a functional component with hooks (useState) in a React Native app tested with Jest and Enzyme.

An example which replicates my problem is:

import React, { useState } from "react";
import { View, Button } from "react-native";
import { shallow } from "enzyme";

const Example = function({ button2Press }) {
const [name, setName] = useState("");

  return (
    <View>
      <Button title="Button 1" onPress={() => setName("Hello")} />
      <Button title="Button 2" onPress={() => button2Press(name)} />
    </View>
  );
};

describe("Example", () => {
  it("updates the state", () => {
    const button2Press = jest.fn();
    const wrapper = shallow(<Example button2Press={button2Press} />)
    const button1 = wrapper.findWhere(node => node.prop("title") === "Button 1")
                        .first();
    const button2 = wrapper.findWhere(node => node.prop("title") === "Button 2")
                        .first();

    button1.props().onPress();
    button2.props().onPress();

    expect(button2Press).toHaveBeenCalledWith("Hello");
  });
});

Any help on what I am doing wrong/missing would be great.

Jon Cahill
  • 4,968
  • 4
  • 34
  • 31

1 Answers1

21

The problem here is 2 things. First I need to call wrapper.update(); after performing actions will cause the state to update. Second I need to find the element again after performing wrapper.update(); for that element to have the updated state.

The working solution is:

import React, { useState } from "react";
import { View, Button } from "react-native";
import { shallow } from "enzyme";

const Example = function({ button2Press }) {
const [name, setName] = useState("");

  return (
    <View>
      <Button title="Button 1" onPress={() => setName("Hello")} />
      <Button title="Button 2" onPress={() => button2Press(name)} />
    </View>
  );
};

describe("Example", () => {
  it("updates the state", () => {
    const button2Press = jest.fn();
    const wrapper = shallow(<Example button2Press={button2Press} />)
    const button1 = wrapper.findWhere(node => node.prop("title") === "Button 1")
                        .first();
    button1.props().onPress();
    wrapper.update(); // <-- Make sure to update after changing the state

    const button2 = wrapper.findWhere(node => node.prop("title") === "Button 2")
                        .first(); // <-- Find the next element again after performing update
    button2.props().onPress();

    expect(button2Press).toHaveBeenCalledWith("Hello");
  });
});
Jon Cahill
  • 4,968
  • 4
  • 34
  • 31
  • 5
    This answer was *ridiculously* hard to find! – kraxor May 01 '21 at 22:24
  • 1
    Wow thank you!! I was stuck on this forever! In my situation, I didn't need to call `wrapper.update()` but I did need to find the element again. – MattR Jul 30 '21 at 22:42