Open TeoTN opened 3 years ago
That’d be great, but first we’d need to resolve #2429.
is there enzyme support for react 17 ?
@mahdizaabi nope, see #2429
Following :) Putting here again the unofficial solution of enzyme-React-17-adapter https://github.com/enzymejs/enzyme/issues/2429#issuecomment-679265564
React 18 is now stable: https://reactjs.org/blog/2022/03/29/react-v18.html
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) :
{
"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: [
'
- 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.
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
@cfaester/enzyme-adapter-react-18
works fine for me
So, guys do we already have the solution how to use Enzyme in react 18?
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. ;)
@igorpupkinable I like the solution. Do you have the configuration that you use for the adapter, and if you use jest, which version
@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.
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.
@eduardoacskimlinks thanks for the feedback. I have updated my answer accordingly.
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:
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.