score:10

Accepted answer

In order to run the clean up function you specified in the useEffect hook, you can cache a reference to it and then call that reference later in your test:

let cleanupFunc;

jest.spyOn(React, "useEffect").mockImplementationOnce(func => {
    cleanupFunc = func();
});

cleanupFunc();

score:-2

React doesn't run the hook in sync mode. https://codesandbox.io/s/m5m5yqrr18

import React from "react";
import { cleanup, render } from "react-testing-library";

afterEach(cleanup);

it("React test", () => {
  let a = false;
  function Test() {
    React.useEffect(() => {
      a = true;
    });
    return <div>Hello World</div>;
  }
  const { rerender } = render(<Test />);
  rerender(<Test />);
  expect(a).toBe(true);
});

score:2

Building on the answer from @thomas-rufflo it's worth pointing out that:

import { useEffect } from 'react';

Doesn't work. You have to use:

React.useEffect

Taken from this blog post: https://blog.carbonfive.com/shallow-testing-hooks-with-enzyme/

I'm new to front-end testing so this tripped me up for some time!

score:3

To those of you who, like me, could not make the accepted answer work:

jest.spyOn(React, "useEffect").mockImplementationOnce(cb => cb()());

Adding the second () to the callback worked to execute the cleanup.

score:4

Here is the complete answer that solves my problem:

it('Should run useEffect cleanUp return function', () => {
  const remover = jest
    .spyOn(global, 'removeEventListener')
    .mockImplementation(() => {});
  act(() => {
    component = mount( < MyComponent value = "Test" / > );
  });
  component.unmount();

  expect(remover).toHaveBeenCalled();
});

score:17

I would suggest you checkout react-testing-library. The library offers a unmount method, that gets returned from its render method. After calling unmount(), you can check if the listeners have been removed. In general, I can very much recommend react-testing-library. We use it for all our frontend tests in combination with jest and it works like a charm.

Sample usage of the unmount method:

import { render } from "@testing-library/react";

it("Should do what I want", () => {
  const { unmount } = render(
    <MyComponent value="test" } />
  );

  unmount();

  // ... expects
});

Related Query

More Query from same tag