question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

`useEffect` not called when the component is `shallow` renderered

See original GitHub issue

Current behavior

useEffect fonction does not seem to be executed when the component is rendered with shallow.

Given the following simple component using useEffect hook to call a method given as a prop:

import React, { useEffect } from 'react';

export const MyComponent = ({ callback }) => {
  useEffect(() => {
    callback('Say something');
  });

  return <div>Hello world!</div>;
};

And the following tests checking that the callback function is indeed called accordingly:

import React from 'react';
import { shallow, mount } from 'enzyme';
import { MyComponent } from '../MyComponent';

describe('MyComponent', () => {
  describe('shallow render', () => {
    it('should call callback when shallow rendered', () => {
      const callback = jest.fn();
      shallow(<MyComponent callback={callback} />);
      expect(callback).toHaveBeenCalled();
    });
  });

  describe('mount', () => {
    it('should call callback when mounted', () => {
      const callback = jest.fn();
      mount(<MyComponent callback={callback} />);
      expect(callback).toHaveBeenCalled();
    });
  });
});

We observe that the method is called as expected when “mounted”, but not when using a shallow renderer:

 FAIL  src/tests/MyComponent.test.js
  MyComponent
    shallow render
      ✕ should call callback when shallow rendered (12ms)
    mount
      ✓ should call callback when mounted (24ms)

  ● MyComponent › shallow render › should call callback when shallow rendered

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

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

       8 |       const callback = jest.fn();
       9 |       shallow(<MyComponent callback={callback} />);
    > 10 |       expect(callback).toHaveBeenCalled();
         |                        ^
      11 |     });
      12 |   });
      13 |

      at Object.toHaveBeenCalled (src/tests/MyComponent.test.js:10:24)

You may find this reproducible example here.

Expected behavior

When using shallow to render the components, the function passed to useEffect should be executed, as it is when using mount.

Your environment

API

  • shallow
  • mount
  • render

Version

library version
enzyme 3.9.0
react 16.8.6
react-dom 16.8.6
react-test-renderer 16.8.6
adapter (below)

Adapter

  • enzyme-adapter-react-16
  • enzyme-adapter-react-16.3
  • enzyme-adapter-react-16.2
  • enzyme-adapter-react-16.1
  • enzyme-adapter-react-15
  • enzyme-adapter-react-15.4
  • enzyme-adapter-react-14
  • enzyme-adapter-react-13
  • enzyme-adapter-react-helper
  • others ( )

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:301
  • Comments:68 (13 by maintainers)

github_iconTop GitHub Comments

67reactions
shirazecommented, Dec 12, 2019

Please stop posting solutions/issues that relate to mount(). This issue relates to limitations of shallow() when trying to confirm expected changes made by useEffect when using setProps or update(). There are already ample solutions that show how mount() can be used. This is also not the place to discuss the pros and cons of shallow/deep rendering. Thanks!

33reactions
shirazecommented, Aug 23, 2020

Seriously guys, just use mount() instead of shallow(). Changes are minimal, and you can still mock sub-components to stop full tree-loading. As an example of how easy the switch is, I had code as follows:

    shallow(<RequireLogon {...props} />).setProps({
      logonExpiresAt: "same date",
    });

that was changed to the following when a class component was converted to a functional component, and logic from lifecycle events (e.g. componentDidUpdate) was moved to useEffect:

    const wrapper = mount(<RequireLogon {...props} />);
    wrapper
      .setProps({
        logonExpiresAt: "same date",
      })
      .update();
Read more comments on GitHub >

github_iconTop Results From Across the Web

Testing a component that uses useEffect using Enzyme ...
I've solved / worked around this by: not using shallow rendering from Enzyme anymore; use the React Testing Library instead of Enzyme; mocking ......
Read more >
Shallow Renderer - React
Shallow rendering lets you render a component “one level deep” and assert facts about what its render method returns, without worrying about the...
Read more >
Shallow rendering & React Hooks. And why shallow rendering ...
They simply don't know that a component calls useEffect() . Yet, it's being called when you invoke shallow() .
Read more >
Testing useEffect and Redux Hooks using Enzyme - Medium
Enzyme doesn't support effect hooks by default while shallow mounting components. You'd need to add jest-react-hooks-shallow to ensure that the ...
Read more >
Shallow Testing Hooks with Enzyme - Carbon Five Blog
The trick to shallow testing hooks like useEffect is to use spies. The examples here are specifically for Jest, but they should work...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found