Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing a component that uses useEffect using Enzyme shallow and not mount

Tags:

reactjs

enzyme

// MyComponent.jsx
const MyComponent = (props) => {
  const { fetchSomeData } = props;

  useEffect(()=> {
    fetchSomeData();
  }, []);

  return (
    // Some other components here
  )
};

// MyComponent.react.test.jsx
...
describe('MyComponent', () => {
  test('useEffect', () => {
    const props = {
      fetchSomeData: jest.fn(),
    };

    const wrapper = shallow(<MyComponent {...props} />);

    // THIS DOES NOT WORK, HOW CAN I FIX IT?
    expect(props.fetchSomeData).toHaveBeenCalled();
  });
});



When running the tests I get:

expect(jest.fn()).toHaveBeenCalled()

Expected mock function to have been called, but it was not called.

The expect fails because shallow does not call useEffect. I cannot use mount because of other issues, need to find a way to make it work using shallow.

like image 729
Adolfo Avatar asked Dec 03 '19 19:12

Adolfo


People also ask

Does enzyme shallow call useEffect?

expect(jest. fn()). toHaveBeenCalled() Expected mock function to have been called, but it was not called. The expect fails because shallow does not call useEffect.

What is the difference between shallow and mount in enzyme?

The difference between shallow() and mount() is that shallow() tests components in isolation from the child components they render while mount()goes deeper and tests a component's children.

Does useEffect always run on Mount?

Important: the useEffect hook will always run on mount regardless of if there is anything in its dependency array.

How do you test a hook using useEffect?

To test the component update useEffect hook you'd simply trigger state updates and check for effects in rendered elements. Redux hooks can be tested by mocking them and their implementation.


1 Answers

useEffect is not supported by Enzyme's shallow rendering. It is on the roadmap (see column 'v16.8+: Hooks') to be fixed for the next version of Enzyme, as mentioned by ljharb

What you're asking is not possible with the current setup. However, a lot of people are struggling with this.

I've solved / worked around this by:

  • not using shallow rendering from Enzyme anymore
  • use the React Testing Library instead of Enzyme
  • mocking out modules via Jest

Here's a summary on how to mock modules, based on Mock Modules from the React docs.

contact.js

import React from "react";
import Map from "./map";

function Contact(props) {
  return (
    <div>
      <p>
        Contact us via [email protected]
      </p>
      <Map center={props.center} />
    </div>
  );
}

contact.test.js

import React from "react";
import { render, unmountComponentAtNode } from "react-dom";
import { act } from "react-dom/test-utils";

import Contact from "./contact";
import MockedMap from "./map";

jest.mock("./map", () => {
  return function DummyMap(props) {
    return (
      <p>A dummy map.</p>
    );
  };
});

it("should render contact information", () => {
  const center = { lat: 0, long: 0 };
  act(() => {
    render(
      <Contact
        name="Joni Baez"
        email="[email protected]"
        site="http://test.com"
        center={center}
      />,
      container
    );
  });
});

Useful resources:

  • React Testing Library docs - mocking
  • React docs - Mocking Modules
like image 166
ndequeker Avatar answered Oct 19 '22 23:10

ndequeker