Search code examples
reactjsunit-testingjestjsenzymereact-context

Unit testing: react context api with enzyme return an empty object


I am trying for the first time to use React context API to pass information from a main component to a grandchild component.

So first I have created a context

const MyContext = React.createContext({});

export default MyContext;

Here is the main component that sets the value of the context

import MyContext from "./MyContext.js";
import ParentComponent from "./ParentComponent.js";

function App() {
  return (
    <div>
      <MyContext.Provider value={{ foo: 12 }}>
        <ParentComponent />
      </MyContext.Provider>
    </div>
  );
}

The parent component doesn't care about the context and is just here to create the grandchild component

import ChildComponent from "./ChildComponent.js";

class ParentComponent extends Component {
  render() {
    return (
      <div>
        Parent
        <ChildComponent />
      </div>
    );
  }
}

export default ParentComponent;

And here is the child component that reads the context

import MyContext from "./MyContext.js";

class ChildComponent extends PureComponent {
  constructor() {
    super();
    this.state = {
      bar: 456
    };
  }

  render() {
    return (
      <div>
        <MyContext.Consumer>
          {({ foo }) => (
            <div>
              <h1>Hello I'm the ChildComponent</h1>
              <h2>Context value: {foo}</h2>
              <h2>State value: {this.state.bar}</h2>
              <button onClick={() => this.setState({ bar: foo })}>
                Click me
              </button>
            </div>
          )}
        </MyContext.Consumer>
      </div>
    );
  }
}

export default ChildComponent;

So far no problem. Everything works as expected. The ChildComponent has retrieved the context value.

The problem comes when I try to test it with jest/enzyme. I can't manage to set the context

it("Should test the context value", () => {
  let wrapper = mount(<ChildComponent />, {
    context: { foo: 987 }
  });

  expect(wrapper.state("bar")).toEqual(456);
  expect(wrapper.context("foo")).toEqual(987);
});

The last expect fails and the context value is an empty object. So foo is undefined

I have recreated the problem here: https://codesandbox.io/embed/x25yop4x5w?fontsize=14

Thank you for your help


Solution

  • Enzyme context affects legacy React context, not modern context API. It should be mocked with:

    mount(<MyContext.Provider value={{foo: 987}}><ChildComponent/></MyContext.Provider>)
    

    And asserted with:

    expect(wrapper.find('h2').text()).toBe('Context value: 987');