enzymejs / enzyme

JavaScript Testing utilities for React
https://enzymejs.github.io/enzyme/
MIT License
19.95k stars 2.01k forks source link

Support for React 18 #2524

Open TeoTN opened 3 years ago

TeoTN commented 3 years ago

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.

ljharb commented 3 years ago

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

mahdizaabi commented 3 years ago

is there enzyme support for react 17 ?

ljharb commented 3 years ago

@mahdizaabi nope, see #2429

tomer-dev commented 2 years ago

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

csvan commented 2 years ago

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

cbazureau commented 2 years ago

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) :

// jest2.config.js ... testMatch: ['*/.spec2.js'], moduleDirectories: [ '/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](https://dev.to/wojtekmaj/enzyme-is-dead-now-what-ekl)) enzyme-adapter-react-18.
ayxos commented 2 years ago

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

bertho-zero commented 1 year ago

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

ArtemFedorchuk commented 1 year ago

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

igorpupkinable commented 1 year ago

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

eduardoacskimlinks commented 1 year ago

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

igorpupkinable commented 1 year ago

@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.

eduardoacskimlinks commented 1 year ago

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
igorpupkinable commented 1 year ago

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