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

Created on 8 Apr 2019  Â·  67Comments  Â·  Source: enzymejs/enzyme

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

  • [x] 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

  • [x] 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 ( )

Most helpful comment

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!

All 67 comments

Same here. Do you have any idea when this is going to be supported? 🙏
Thanks,

Hopefully in the next version of enzyme.

Was there a plan to support that? I made an issue in react to support this from the shallow renderer with an option. I figured that would be the only way to do it without trying to mock out useEffect or something

ah, fair enough - you're right that it still won't work in shallow, and that that issue, or mocking it out in enzyme, would be the only way to make it work.

Is there a plan or PR to fix this? Makes hard include hoos/useEffect if we can't test it

@mangel0111 see the previous 2 comments. we're waiting to see if we can add a feature to react which will make it easier to fix this

Having the same issue here. Is there any alternative to creating a snapshot that runs the useeffect hooks?

setTimeout(() => {
  expect(yourFunction).toHaveBeenCalledTimes(1);
});

This appears to work

Edit: This doesn't work at all, just skips over the test. Waiting for a solution to this now too.

@MM263 make sure that the setTimeout callback is even firing. Your test is probably passing because it isn't reaching the assertion in time

@gonzofish We've just discovered this, you are totally right! Thank you!

~It looks like the render and update calls just need to be called inside an act() callback and this will flush the effects, whether using shallow rendering or not. I have this working in a hacked together enzyme now.~ EDIT: I made a mistake, implemented the feature below though.

Are you sure? With useEffect. The implementation of use it in shallow is
just a noop so that would be surprising.

On Sun, Jul 21, 2019 at 6:49 AM James Pike notifications@github.com wrote:

It looks like the render and update calls just need to be called inside a
ReactTestUtils.act() callback and this will flush the events, whether
using shallow rendering or not. I have this working in a hacked together
enzyme now.

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/airbnb/enzyme/issues/2086?email_source=notifications&email_token=AA6MGDR4G2X7MHRM2RCCXGDQAPMDVA5CNFSM4HEGYKH2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD2N2LKQ#issuecomment-513516970,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AA6MGDRAM45GH5FRNTH5E33QAPMDVANCNFSM4HEGYKHQ
.

@bdwain Sorry I had a bunch of changes to ReactShallowRenderer which I was supposed to remove before adding the act() wrapper. Actually the act() wrapper changed nothing. It's not that hard to make the change but react maintainers don't seem to be interested at the moment.

yea i wonder if they would be more interested if it was completed already. If you got it all working maybe post that in a PR and see what they say?

@bdwain My PR is here: https://github.com/facebook/react/pull/16168 would be really grateful for your feedback.

BTW it's possible to get this working from enzyme without having to touch react, but you have to override _createDispatcher in the shallow renderer to call the original version and patch useEffect and useLayoutEffect with my versions from the PR above and return the patched dispatcher. Then after enzyme calls render you just add in my effect calling code from the PR above.

Would be nicer if the code was in React's shallow renderer though.

I needed this feature like... 5 months ago. Which is about the length of time the react maintainers have been ignoring the issue for. If they don't respond to my PR in another few weeks could I maybe do the private method override thing? I would make enzyme's code test for the existence of the private method first so as not to break if the internals change. Then when (or more like if) react accept the PR or code then it could just be removed. Although it is super hacky :( In my own project I switched from enzyme to the test renderer and do the hack now so I can at least test my effects, but I'd much rather be using enzyme.

@ohjames as long as your tests here are good, that is totally fine.

@ljharb Cool, I've written the code now. Having trouble testing it. After running the steps listed in CONTRIBUTORS.md I get the following after npm run react 16:

james@lapchil enzyme % npm run react 16                                                                         

> [email protected] react /home/james/projects/enzyme                                                                
> sh install-relevant-react.sh "16"                                                                             

installing React 16                                                                                             

> [email protected] env /home/james/projects/enzyme                                                                  
> babel-node ./env.js "16"                                                                                      

rimraf ./node_modules/react                                                                                     
rimraf ./node_modules/react-dom                                                                                 
rimraf ./node_modules/react-addons-test-utils                                                                   
rimraf ./node_modules/react-test-renderer                                                                       
rimraf ./node_modules/create-react-class                                                                        
rimraf node_modules/.bin/npm 
rimraf node_modules/.bin/npm.cmd
npm i
npm WARN checkPermissions Missing write access to /usr/lib/node_modules/npm/node_modules

Hmmm... not sure why it wants to install things to system owned directories. Don't really want to contaminate my system :(

Okay... so I decided to run it in a container (I chose node:11) because I didn't want to run things as root just to get this working (and have lost all interest in trying lerna which I thought previously might be a good idea). But get 11 failing tests with a totally clean codebase. Hmm... enzyme's build system is intense and scary.

Here's some examples of failing tests:

  1) Adapter provides node displayNames supports Profiler:                                                      
     AssertionError: expected null to equal 'Profiler'                                                          
      at Context.<anonymous> (packages/enzyme-test-suite/test/Adapter-spec.jsx:1048:47)                         
      at processImmediate (internal/timers.js:443:21)

  2) Adapter provides node displayNames supports ConcurrentMode:                                                
     AssertionError: expected null to equal 'ConcurrentMode'                                                    
      at Context.<anonymous> (packages/enzyme-test-suite/test/Adapter-spec.jsx:1052:53)                         
      at processImmediate (internal/timers.js:443:21)

  10) (uses jsdom) mount Profiler wrapped: with console throws: mounts without complaint:                       
     AssertionError: expected [Function] to not throw an error but 'EvalError: Warning: React.createElement: typ
e is invalid -- expected a string (for built-in components) or a class/function (for composite components) but g
ot: %s.%s%s' was thrown                                                                                         
      at Context.<anonymous> (packages/enzyme-test-suite/test/ReactWrapper-spec.jsx:865:9)                      
      at processImmediate (internal/timers.js:443:21)                                                           

  11) (uses jsdom) mount Profiler wrapped: with console throws: "after each" hook: afterEachWithOverrides:
     Uncaught EvalError: The above error occurred in the <SomeComponent> component:                             
    in SomeComponent (created by WrapperComponent)                                                              
    in WrapperComponent

Now I kinda feel like giving up.

It doesn’t need root unless npm install -g needs root, which it doesn’t if you’re using nvm.

@ljharb Most of the world seems to have moved onto docker-compose instead of nvm now, so I don't think mandating nvm is a good idea. IMO using docker-compose is a way better approach for most people/projects as it fixes a tonne of other system difference problems as well.

Hi,
I am also encountering this issue.
I really appreciate your work and would like to have that feature, too :(

@LeonardPurschke Don't worry I've completed the work and it should be available soon. I'm just waiting on the enzyme Devs to fix the reliability of enzyme's tests so I can open the PR.

@ohjames that's a very bold, highly untrue (travis-ci uses nvm, for example, and the number of travis jobs ran dwarfs almost every other usage), and unhelpful claim. Since I'm the primary maintainer, I'm going to mandate whatever makes my life easier, and docker isn't it.

Okay, if you care more about your own development experience on a community project than that's your prerogative, but it doesn't change the fact that docker is a far better system for environmental isolation than nvm. You chose Travis as your example, but Travis also supports docker, and CircleCI, which is the CI of react and millions others, is built on top of docker. It seems evident from the unreliability of the tests when run in containers, even on versions of react other than 16.9, that enzyme is highly coupled to your personal environment and the one on Travis. If they were run via containers this issue would be moot.

Running into this issue when I try to use shallow or mount in enzyme tests:

Invariant Violation: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.

  65 | export function ProgrammeCard(props):React.ReactElement{
  66 | 
> 67 |   const classes = useStyles({});
  68 | 
  69 |   let Pinned =  false;
  70 |   if (props.item[definitions.pinnedColumn + 'Id'] !== null){

  at invariant (node_modules/react/cjs/react.development.js:88:15)
  at resolveDispatcher (node_modules/react/cjs/react.development.js:1436:28)
  at Object.useContext (node_modules/react/cjs/react.development.js:1441:20)
  at useTheme (node_modules/@material-ui/styles/useTheme/useTheme.js:15:25)
  at node_modules/@material-ui/styles/makeStyles/makeStyles.js:244:39
  at Object.ProgrammeCard (src/webparts/wfd1/components/ProgrammeCard.tsx:67:33)
  at Suite.Object.<anonymous>.describe (src/webparts/wfd1/test/ProgrammeCard.test.ts:25:5)
  at Object.<anonymous> (src/webparts/wfd1/test/ProgrammeCard.test.ts:23:1)

The code I want to test is a small component that renders a material-ui card in an spfx web part, my setup is as follows:

React v16.8.5
React-DOM v16.8.5
enzyme v3.10.0

The test suite is

> //Tests for ProgrammeCard
> 
> /// <reference types="jest" />
> 
> import * as React from 'react';
> import { configure, mount, shallow } from 'enzyme';
> import * as Adapter from 'enzyme-adapter-react-16';
> import * as testdata from '../testdata/testdata';
> 
> 
> configure({ adapter: new Adapter() });
> function updateItem(){
>   console.log('Pass');
> } 
> import {ProgrammeCard} from '../components/ProgrammeCard';
> const Title = testdata.Programmes[0].ProgrammeName;
> const validProps = {
>   currentUser:testdata.UserProfile,
>   item:testdata.Programmes[0],
>   updateItem:updateItem(),
>   variant:'my'
>    };
> describe ('Check 3 variants of ProgrammeCard', () => {
>   const myProgramme = mount(
>     ProgrammeCard(validProps)
>   );
>   expect(myProgramme.text()).toEqual('I am Groot');
> });
> 
> 

Has anyone got this working?

I've found sollution that you need to add import in your test file:
import React, {useEffect} from 'react';

And then in beforeEach function add following line:
useEffect = jest.spyOn(React, "useEffect").mockImplementation(f => f());

Also in your Component use React.useEffect instead of just useEffect
This will trigger useEffect function using shallow

@dikamilio but this wouldn't allow to test any behavior after any monitored value changed, ex.

  useEffect(() => {}, [params])

I made it work with the react-dom/test-utils act helper.

const myCB = jest.fn();
act(() => {
  mount(<MyComponent myCB={myCB} />);
});
expect(myCB).toHaveBeenCalled();

I have made my own version that will run the effect if the dependences changes

import React from "react";

/** Workarround for useEffect. It will run the effect synchronously if any deps changes */
function almostUseEffect() {
    return jest.spyOn(React, 'useEffect').mockImplementation((cb, deps) => {
        // create a new symbol, different at each run and save the first one
        const firstRun = Symbol();
        const isFirstRun = React.useMemo(() => firstRun, []) === firstRun;
        const ref = React.useMemo(() => ({
            current: deps,
        }), []);
        const last = ref.current;

        // compare the last known version of deps with the current one
        const changed = deps && last.some((value, i) => value !== deps[i]);

        if (isFirstRun || changed) {
            ref.current = deps;
            // run the callback if it changed
            cb();
        }
    });
};

Been open since Apr 8th... is this being worked on?

FWIW, this issue now appears first on Google when searching "enzyme test useEffect".

If you're coming from Google, and because it wasn't mentioned above, useEffect is not supported when using shallow.

I posted a stackoverflow question to see if anybody answers it.

Here's a solution from a colleague of mine at CarbonFive:
https://blog.carbonfive.com/2019/08/05/shallow-testing-hooks-with-enzyme/
TL;DR: jest.spyOn(React, 'useEffect').mockImplementation(f => f())

@sweetleon what you suggest is more of a work around, and not a particularly robust one if you need to test that useEffect fires when a value changes (or if the component unmounts).

I've had success with getting realistic behavior by using a full mount via enzyme's mount capability. This will cause a full tree render, BUT only if you let it. It is extra work but to avoid the full tree render, I mock out component constructors via jest.mock capability.

example:

// Component.jsx
import React from 'react';
export default () => {
  return <div>component with lots of nested other components we don't want to test</div>;
}

```JavaScript
// App.jsx
import React, { useEffect, useState } from 'react';
import Component from './Component.jsx';

export default (props) => {
const [capital, setCapital] = useState('');
useEffect(() => {
setCapital(props.importantProp.toUpperCase());
}, [props.importantProp]);
return (


{capital}



);
}

```JavaScript
// App.spec.jsx
import { mount } from 'enzyme';
import App from './App.jsx';
jest.mock('./Component.jsx', () => {
  return () => null;
});
it('should do the thing', () => {
  const wrapper = mount(<App importantProp="some value" />);
  expect(wrapper.find('.capital-value').text()).toBe('SOME VALUE');
  wrapper.setPros({
    importantProp: 'new value',
  });
  wrapper.update(); // this is needed for some reason
  expect(wrapper.find('.capital-value').text()).toBe('NEW VALUE');
});

I've adopted this approach in my code base until shallow works as expected. I hope this helps...

I made it work with the react-dom/test-utils act helper.

const myCB = jest.fn();
act(() => {
  mount(<MyComponent myCB={myCB} />);
});
expect(myCB).toHaveBeenCalled();

I have tried this, still not working.

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!

My workaround for now, so you don't have to use React.useEffect, you can still use import React, { useEffect } from 'react'; in your codebase.

jest.mock('react', () => ({
  ...jest.requireActual('react'),
  useEffect: (f) => f(),
}));

Shallow still does not trigger useEffect and this issue is still open... can we expect it to work at some point ?

Ps: https://github.com/airbnb/enzyme/issues/1938#issuecomment-476834809 seems to answer my question but this issue is still open so is it an issue or not?

@Aljal There is another active GitHub thread, https://github.com/facebook/react/issues/17321 ,where there is discussion around the future of the Shallow Renderer with regards to eventually supporting the behavior being discussed here.

I've created a package that solves the issue - https://www.npmjs.com/package/jest-react-hooks-shallow

@mikeborozdin fwiw, some corrections to your "long story": enzyme definitely does perform shallow rendering; that it uses react-test-renderer is an implementation detail; react-test-renderer alone shallow renders but not usefully; there's no other way to shallow render react components that i know of.

This is an interesting approach, though, and it might be worth including the hook mock itself into enzyme (and leave the mocking to users, explained via documentation, that for jest points to your package).

@ljharb ,

Thanks a lot for the details! And I apologise for the misleading readme. I'll correct it.

Do you think though that enzyme relies on react-test-renderer is quite important in the context of hooks? After all, it is react-test-renderer which chooses to implement some hooks, like useState() and not implement the others (useEffect()). And given that so far it's been part of the React itself, it was quite difficult to change the way it works.

As for including the hook mock into enzyme - that sounds really good! I guess its implementation should not rely on Jest though.

@inkless Your workaround will not work when there's dependencies to the useEffect(). It'll only be usefull when you component use useEffect() on each re-render without dependencies

another way of dealing with the problem:

jest.mock('react', () => ({
  ...jest.requireActual('react'),
  useEffect: (cb: () => void, deps: unknown[]=[]) => {
    const ref = React.useRef<unknown[]>();
    if (
      !ref.current ||
      (ref.current !== undefined &&
        JSON.stringify(ref.current) !== JSON.stringify(deps))
    ) {
      ref.current = deps;
      cb();
    }
  },
}));
        JSON.stringify(ref.current) !== JSON.stringify(deps))

will fail if deps is not representable in JSON such as functions, but you can swap with a deep equal function.

My workaround for now, so you don't have to use React.useEffect, you can still use import React, { useEffect } from 'react'; in your codebase.

jest.mock('react', () => ({
  ...jest.requireActual('react'),
  useEffect: (f) => f(),
}));

this worked for me! I know it's not the best solution, but a solution none the less! thanks! :)

I've created a package that solves the issue - https://www.npmjs.com/package/jest-react-hooks-shallow

This package works beautifully, and is the simplest solution to integrate. Thanks @mikeborozdin

Hey guys, if I would like to test my mock of useEffect toHaveBeenCalled, how would I use the way as introduced above?

jest.mock('react', () => ({
  ...jest.requireActual('react'),
  useEffect: (f) => f(),
}));

I have tried this as well but it seems useEffect is not able to be mocked for real

const mockUseEffect = jest.fn();
jest.spyOn(React, 'useEffect').mockImplementation(() => mockUseEffect);

...
expect(mockUseEffect).toHaveBeenCalled() // failed as seems my actual useEffect is being called rather than my mocked function

Any guide on how to test the useEffect with mocked as toHaveBeenCalled() or not.toHaveBeenCalled()?

@kevinding0218 I suggest you observe the effects wired up inside your useEffect instead of checking whether useEffect is called. In the approach you are considering, you are mocking the useEffect implementation to always execute the registered effect. This means that on every render the useEffect will trigger.

But to answer your question:

jest.mock('react', () => ({
  __esModule: true, // maybe required?
  ...jest.requireActual('react'),
  useEffect: jest.fn(f => f()),
}));
import React, { useEffect } from 'react';

// before each reset the mock

// in the test
expect(useEffect).toHaveBeenCalled();

I got it to work using mount instead of shallow

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();

Deleting my previous comments since they are a bit confusing; to summarize:

This adapter supports useEffect and useLayoutEffect with shallow:
https://www.npmjs.com/package/enzyme-adapter-react-16-with-shallow-effects

It does so by monkey-patching the dispatcher's handlers. It also uses react-shallow-renderer rather than react-test-renderer/shallow, but that is a less substantive change that should not affect usage.

I could adapt these changes for inclusion in the official adapter and open a PR.... but note:

  • this would be a behavior change that could break tests unexpectedly.
  • this relies on not-explicitly-public implementation details of react-shallow-renderer

Seriously guys, just use mount() instead of shallow(). Changes are minimal, and you can still mock sub-components to stop full tree-loading.

Lets say I have a component X that renders a tree like this :

<>
    <Y bar={baz} />
    <Z shouldFetch>Hello</Z>
    <p>Lorem ipsum</p>
    <button onClick={onClick}>Click me</button>
</>

If we use mount in the test cases involving X then all of those tests have to know exactly which children X uses and know enough to understand that the child Y is a simple component that we don't have to mock and that the Z child makes API call so we should mock that component. We also have to keep track of how many tests cases we have to be updated if we add a useEffect or complex logic to Y which makes ticket estimations harder since changing a component that is used in multiple places might result in changes for 50+ test cases.

It is certainly possible to do this in smaller components, components with few test cases, or components with many test cases where each root can be setup by a shared function, but that is not the case for many of our tests.

Replacing shallow with mount is a major increase in test maintenance workload and increases the cost of making changes in the tested components, shallow is also much faster than mount so this also slows down the code/test feedback loop.

Perhaps opinions on testing approaches could be moved to forums better suited to discussion?

+1 to last comment from @Gyllsdorff . Yes, it may be possible to use mount instead with proper mocks, but that adds additional overhead and complication to the tests. It also may have other side effects. The entire point of using shallow is to provide a single reference to the component without going deeper. This issue is one I've had my eye on for a while and am really hoping for a fix!

For now, I guess we'll keep with the more complicated way. At least we have a workaround.
Just because there is a workaround, that doesn't mean it's best.

jest.mock('react', () => ({
  ...jest.requireActual('react'),
  useEffect: (f) => f(),
}));

Works fine, but keep in mind that it will run for every effect and on every render even if their dependencies are still the same. There's a pretty ugly workaround, but it works:

let mockLastDeps = {};
jest.mock("react", () => ({
  ...jest.requireActual("react"),
  useEffect: (f, deps) => {
    const effect = new Error().stack.split("\n")[2]; // <-- to find fileName and lineNumber, since we can't identify by `f`
    if (!mockLastDeps[effect] || deps.some((dep, i) => dep !== mockLastDeps[effect][i])) {
      f();
      mockLastDeps[effect] = deps;
    }
  },
}));

Ran into a use case for this; ended up going with jest-react-hooks-shallow like was linked above to work around it. Definitely interested in this support coming by default from enzyme!

I spent a fair bit of time working on this and even made an enzyme adapter with hook support (see above), but in the end I decided to create a replacement for enzyme shallow that supports the full set of hooks and is self-contained: https://www.npmjs.com/package/isolate-components

I think it should support most of what shallow does except for dive(), albeit with a different/simpler interface. Also if you want to to test your hooks directly, without components, I made this: https://www.npmjs.com/package/isolate-hooks

@davidmfoley interesting! could you help me understand the difference between isolate-components and shallow (if it had full hook support)? In other words, why could your package not be used or adapter into improving shallow itself?

@ljharb

The big difference in implementation is that isolate-components does not use an external renderer. For the most part, the features are similar to enzyme shallow with only react 16+ support, but there are some other cases that I want to support in future versions that don't really fit into enzyme (the big ones: 1) ability to "inline" a subcomponent to support cases where you refactor a component into smaller compnents without breaking tests and 2) "mount" without a virtual DOM).

I did start down the path of building a hook-compatible renderer for enzyme, but forking the enzyme repo so that I could fork react-shallow-renderer, or alternatively monkey patching the shallow renderer as I did in the adapter above, was painful. The unfortunate reality is that react is not built with component testability in mind.

You could probably build an adapter for enzyme using isolate-components (at least I can't think of any reasons you couldn't off the top of my head?). That would be cool. Enzyme is great. But I'm not inclined to spend my time on that given the speed of development on enzyme and react-shallow-renderer.

Enzyme moves slowly, which is understandable since it's an established project, supports old react versions, and has thousands of users whose tests could be broken if the shallow renderer suddenly started supporting effects.

This issue -- which is effectively "enzyme shallow is not useful for react 16 components" is 18 months old and there is no sign it will be addressed any time soon. An issue about transferring the shallow renderer to enzyme is 8 months old.

So, given all that, I decided to start from scratch without the baggage of supporting old react versions or depending on other packages.

I totally agree that React is not built with component testability in mind :-/

I'm also totally happy to remove the dependency on react-shallow-renderer/react-test-renderer, if it makes an API for shallowly testing a component more robust. If we could fix shallow to work properly on React 16.9+, say, I'd also be willing to make a major bump of enzyme that drops support for older React versions. Do you have any interest in exploring those possibilities?

@ljharb sure; let's chat -- email me at my github name at gmail?

@davidmfoley @ljharb any update on this? Should we expect a solution any time soon?

No update, nothing any time soon. Help is welcome.

@dolsem we chatted about potentially making an enzyme adapter that uses isolate-components under the hood but I haven't had time since then to do more than look into the enzyme adapter interface at a high-level and see that it will be a fair amount of work. If anyone is interested in helping on that, I'd be happy to chat about it.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

abe903 picture abe903  Â·  3Comments

thurt picture thurt  Â·  3Comments

benadamstyles picture benadamstyles  Â·  3Comments

nelsonchen90 picture nelsonchen90  Â·  3Comments

modemuser picture modemuser  Â·  3Comments