enzyme icon indicating copy to clipboard operation
enzyme copied to clipboard

Support for React 18

Open TeoTN opened this issue 3 years ago • 14 comments

I would like to ask for support for React 18, as the alpha version was recently released: https://reactjs.org/blog/2021/06/08/the-plan-for-react-18.html

While this is an alpha release, my understanding is that this release is targeted towards library maintainers. The React team announced they're open for feedback:

We’ve published a React 18 Alpha so that library authors can try it and provide feedback.

I'm asking early, because it might be a good moment to start looking into React 18 adapter, and to try influence React in case there are major issues with onboarding Enzyme onto it.

TeoTN avatar Jun 10 '21 09:06 TeoTN

That’d be great, but first we’d need to resolve #2429.

ljharb avatar Jun 14 '21 15:06 ljharb

is there enzyme support for react 17 ?

mahdizaabi avatar Jun 30 '21 02:06 mahdizaabi

@mahdizaabi nope, see #2429

ljharb avatar Jun 30 '21 03:06 ljharb

Following :) Putting here again the unofficial solution of enzyme-React-17-adapter https://github.com/enzymejs/enzyme/issues/2429#issuecomment-679265564

tomer-dev avatar Dec 23 '21 16:12 tomer-dev

React 18 is now stable: https://reactjs.org/blog/2022/03/29/react-v18.html

csvan avatar Mar 31 '22 06:03 csvan

If you've got a large number of enzyme unit tests (> 1200 in our case) but you still want to switch to react 18 right now and migrate to react-testing-library progressively you can do it with this method (inspired by this article) :

  • update to react 18
  • create another package.json in a sub-folder like ./testing-react-17 and npm/yarn install it
{
  "private": true,
  "description": "Old enzyme based test that required react 17",
  "dependencies": {
    "react": "17.0.2",
    "react-dom": "17.0.2",
    "react-test-renderer": "17.0.2"
  }
}
// jest.config.js
  ...
  testMatch: ['**/*.spec.js'],
  moduleDirectories: [
    'node_modules',
  ],

// jest2.config.js
  ...
  testMatch: ['**/*.spec2.js'],
  moduleDirectories: [
    '<rootDir>/test-react-17/node_modules',
    'node_modules',
  ],
  • run jest twice : on --config jest.config.js then on --config jest2.config.js
  • use .spec2.js for new tests using react-testing-library (and react 18 under the hood)
  • keep your old .spec.js for old tests using enzyme (and react 17 under the hood) and migrate them progressively

It's not perfect but i think it's better than waiting for the migration of all our tests or for an hypothetical official (or unofficial) enzyme-adapter-react-18.

cbazureau avatar May 03 '22 15:05 cbazureau

Using enzyme-adapter-react-17 and a bit tweak such as (https://stackoverflow.com/a/72109612/3764994)

const Environment = require('jest-environment-jsdom-global');
/**
 * A custom environment to set the TextEncoder
 */
module.exports = class CustomTestEnvironment extends Environment {
    constructor({ globalConfig, projectConfig }, context) {
        super({ globalConfig, projectConfig }, context);
        if (typeof this.global.TextEncoder === 'undefined') {
            const { TextEncoder } = require('util');
            this.global.TextEncoder = TextEncoder;
        }
    }
};

everything should work with react v18 and jest28

ayxos avatar May 04 '22 08:05 ayxos

@cfaester/enzyme-adapter-react-18 works fine for me

bertho-zero avatar Jan 19 '23 13:01 bertho-zero

So, guys do we already have the solution how to use Enzyme in react 18?

ArtemFedorchuk avatar Sep 05 '23 12:09 ArtemFedorchuk

So, guys do we already have the solution how to use Enzyme in react 18?

We have successfully used @cfaester/enzyme-adapter-react-18 to run over 3500 tests. This gives you a possibility to migrate off Enzyme progressively.

Packages with these versions which proven to be working together on a large amount of various tests. The whole thing is very fragile, so you have to stick to these MINOR or exact PATCH versions.

"devDependencies": {
  "@cfaester/enzyme-adapter-react-18": "^0.5.1",
  "@testing-library/react": "^13.3.0",
  "@types/enzyme": "^3.10.12",
  "enzyme": "^3.11.0",
  "enzyme-to-json": "^3.6.1",
  "@types/react": "^18.0.15",
  "@types/react-dom": "^18.0.6",
  "react": "^18.2.0",
  "react-docgen-typescript": "^2.2.2",
  "react-dom": "^18.2.0",
  "ts-react-display-name": "^1.2.2",

  // Jest versions working with this setup in case you have issues
  "@types/jest": "^27.5.2",
  "jest": "^27.5.1",
  "ts-jest": "^27.1.5",
}

Generally, three methods are causing issues with new React: simulate, setProps and mount. You have to wait before component updates because the update happens asynchronously in multiple rounds which old adapter has no compatibility with. I have added a nasty workaround, but hey.. it is better than convincing your stackeholders to rewrite several thousands of tests, right?!

The nasty hack is to absolutely wait for all component updates before continuing executing the rest of the test. Here is an example which may be of some help.

test-utils/src/testComponentHelper.ts

import {
  act,
} from '@testing-library/react';
import type {
  CommonWrapper,
} from 'enzyme';

// State update magic happens here
const waitForComponentToPaint = async (wrapper: CommonWrapper): Promise<void> => {
  await act(async () => {
    await new Promise<void>((resolve) => {
      window.setTimeout(
        () => {
          /*
           * Make sure it is the last task in the queue.
           * https://dmitripavlutin.com/javascript-promises-settimeout/
           */
          window.setTimeout(
            resolve,
            1,
          );
        },
        1,
      );
    });
  });
  wrapper.update();
};

export default waitForComponentToPaint;

And then you do terrible things like these in your old tests:

wrapper.setProps({ value: 'foobar' });
await waitForComponentToPaint(wrapper);

and

wrapper.find('input').simulate('change', { target: { files: mockFiles } });
await waitForComponentToPaint(wrapper);

and

const wrapper = mount(...);
// Wait even longer for complex component updates
await waitForComponentToPaint(wrapper);
await waitForComponentToPaint(wrapper);

This is not perfect, but it works for old React 16/17 components and buys you time to migrate to React Testing Library. It is possible to run smart search&replace to add waits to existing tests where needed. Hope this helps. ;)

https://github.com/cfaester/enzyme-adapter-react-18

igorpupkinable avatar Sep 05 '23 16:09 igorpupkinable

@igorpupkinable I like the solution. Do you have the configuration that you use for the adapter, and if you use jest, which version

eduardoacskimlinks avatar Oct 19 '23 13:10 eduardoacskimlinks

@igorpupkinable I like the solution. Do you have the configuration that you use for the adapter, and if you use jest, which version

Standard adapter configuration as follows:

import Adapter from '@cfaester/enzyme-adapter-react-18';
import { configure } from 'enzyme';

configure({ adapter: new Adapter() });

"jest": "^27.5.1", in that particular project, but it should not matter.

igorpupkinable avatar Oct 22 '23 16:10 igorpupkinable

Thanks, @igorpupkinable. I initially used 29.x.x, but I couldn't get it to work due to missing support for jest-enzyme and jest-environment-enzyme. Therefore, I had to downgrade back to 24.8.0, but I am glad I could have gone for 27.5.1.

Screenshot 2023-10-19 at 14 26 59

eduardoacskimlinks avatar Oct 23 '23 07:10 eduardoacskimlinks

@eduardoacskimlinks thanks for the feedback. I have updated my answer accordingly.

igorpupkinable avatar Oct 31 '23 07:10 igorpupkinable