Darek Kay's picture
Darek Kay
Solving web mysteries

Handling Enzyme in React 18

React Testing Library (RTL) is arguably superior to Enzyme, due to a shift from testing implementation details to more user-centric unit tests. However, many projects still contain lots of Enzyme tests from the early days, making migration difficult and time-consuming. At my company, we've decided to keep Enzyme for old tests and write all new tests using RTL. This worked out fine, until we had to update React. While the missing support for React 17 can be worked around, making Enzyme ever work with React 18 is unlikely to happen.

Migrating ~700 Enzyme tests at once was not a viable option for our project, so I've explored other approaches to handle Enzyme tests with React 18.

Write a custom adapter

The first idea was to write a custom adapter: a middle-layer class that translates Enzyme API calls to RTL (not to be confused with enzyme-adapter-react). However, the fundamental differences between both libraries make such an adapter difficult (or impossible) to implement.

This is how far I've got until abandoning this approach:

import React from "react";
import { render } from "@testing-library/react";

export const mount = (component) => {
const { container, rerender } = render(component);
return {
find: (matcher) => {
const nodes = container.querySelectorAll(matcher);
return {
length: nodes.length,
exists: () => nodes.length > 0,
// NOTE: innerText is not implemented by jsdom
text: () => nodes[0].innerHTML,
};
},

html: () => container.innerHTML,

setProps: (props) => {
const updatedComponent = React.cloneElement(component, props);
rerender(updatedComponent);
},
};
};

Run multiple React versions

Finally, I followed the guide from Vitali Zaidman to keep using React 16 for Jest, while running React 18 for the application itself.

  • package.json:
{
"dependencies": {
"react": "18.0.0",
"react-16": "npm:react@16.14.0",
"react-dom": "18.0.0",
"react-dom-16": "npm:react-dom@16.14.0"
}
}
  • jest.config.js:
module.exports = {
'moduleNameMapper': {
'^react-dom((\\/.*)?)$': 'react-dom-16$1',
'^react((\\/.*)?)$': 'react-16$1'
}
}

This is not a real solution, but it allows us to gradually migrate our Enzyme tests to RTL while being able to use React 17+ without any code change.


Related posts

Want to leave a comment?

If you want to give me some feedback, please contact me via Twitter or email. 💌

Handling Enzyme in React 18