DEV Community

Wojciech Maj
Wojciech Maj

Posted on • Updated on

Enzyme is dead. Now what?

I'm the maintainer of @wojtekmaj/enzyme-adapter-react-17. I'm here to warn you. Enzyme, a popular utility to test React components, is dead. It's time to move on. Here's why I think so.

For a long time, Enzyme has been the 1st choice when it comes to testing React applications, despite of how bumpy the road to Enzyme React 16 support was. Even today, 1/3 of React apps are still being tested using Enzyme!

How @wojtekmaj/enzyme-adapter-react-17 came to life

Back in August 2020, React 17 Release Candidate came out. Shortly after, an issue has been raised in Enzyme repository to add support for React 17. Immediately after, @layershifter has opened a PR adding an official enzyme-adapter-react-17.

Unfortunately, there were (and, spoiler alert, still are) some issues with testing that prevented this PR from being merged.

Now, here's the thing. I'm the maintainer of many popular React packages, React-PDF, React-Calendar, and React-Date-Picker just to name a few. Professionally, I maintain several large projects, which collectively have more than 30,000 Enzyme-based unit tests.

I was in no position to wait for Enzyme to add support for React 17 to support React 17 in my packages. Rewriting all unit tests also looked like no fun to me. So, I've decided to act and publish a temporary adapter based on Oleksandr's work.

It wasn't only the adapter though: certain changes were also necessary in Enzyme adapter utils, which all Enzyme adapters depend on, so a fork of them was also needed. A couple of tireless evenings later, @wojtekmaj/enzyme-adapter-react-17 was born.

Fast-forward one year

The issue for adding React 17 support remains open and has become nothing but a source of bitter comments mixed with unproductive "any updates?". Oleksandr's PR remains unmerged. enzyme-adapter-react-17 is nowhere in sight. The unofficial adapter I published with an intention of being just a stepping stone before everyone eventually migrates to enzyme-adapter-react-17, has become de facto the default adapter for React 17, with 16 million downloads so far.

Retrospectively, I'm not sure if publishing the package was a good decision.

On one hand, this move has helped thousands of developers worldwide to upgrade to React 17, relatively hassle-free.

On the other, I helped prolonging Enzyme's inevitable death and thus gave many developers hope and a sense of safety they shouldn't get to feel. And I'm sorry for that.

React 18

Before I came to this conclusion though, React 18 beta was announced, and of course, I jumped to see if @wojtekmaj/enzyme-adapter-react-18 could be released.

The big thing in React 18 are concurrent features. To opt-in, after upgrading to React 18, you also need to switch to the new createRoot API:

// before
const container = document.getElementById('root');
ReactDOM.render(<App />, container);

// after
const container = document.getElementById('root');
const root = ReactDOM.createRoot(container);
root.render(<App/>);
Enter fullscreen mode Exit fullscreen mode

Until you switch to the new API, your app will behave as if it's running React 17. So if you don't plan to do this, there's no point of upgrading!

I quickly realized that the API changes in React 18 meant that releasing a React 18 Enzyme adapter will not be possible without a huge rework of not only the adapter itself, but also Enzyme, enzyme-adapter-utils and enzyme-adapter-react-helper.

Trust me, it's not gonna happen. It's over. No more "stepping stones". And certainly no more official adapters. Whether or not you plan to upgrade to React 18 in the near future, you should consider looking for Enzyme alternative right now.

What should I do? 😱

The answer is, as always, it depends. You don't have to upgrade React, after all.

Here's what I would do:

  • Start familiarizing yourself with React Testing Library, an officially recommended library for React components.
  • Make a rule to write new tests using RTL only.
  • Consider making a rule to rewrite tests to RTL whenever you need to touch them and/or the component they are testing.
  • In your designated time for repaying technical debt (you have designated time for repaying technical debt, right? …right?), rewrite your remaining Enzyme-based tests to RTL.
  • Clean up your repo from Enzyme-specific bits
  • When you're ready, upgrade to React 18.

A bit of personal advice

While Migrate from Enzyme support article is available, I suggest you to just start fresh, forgetting that Enzyme has ever existed. RTL is by no means an Enzyme drop-in replacement, so having a completely fresh mindset will help you getting the most of it.

Top comments (22)

Collapse
 
collimarco profile image
Marco Colli

Call me old-fashioned by in 10+ years of development with Rails I never seen a breaking change like this and I never had to rewrite an entire test suite... That is why I always fear the adoption of new trends.

Collapse
 
sergiodxa profile image
Sergio Daniel Xalambrí

I think the issue was because Enzyme dependent on internals of React, while tools like RTL test them from the outside, in Rails you have something similar, the test frameworks like RSpec are not dependent on Rails internals to work.

Enzyme did a bad thing there, RTL got it right, so right that testing-library has now a generic testing-library-dom and wrappers for different frameworks, theoretically a test for React could work with only a few changes to test also a Vue component, after the test render searching dom nodes and triggering events is the same.

Collapse
 
amcsi profile image
Attila Szeremiâš¡

I don't think that's a good excuse. Laravel gives you testing tools that interact with the internals of Laravel, and there are hardly ever any breaking changes there.

True though that the Laravel testing tools were created by the creators of Laravel and is officially endorsed, whereas Enzyme is completely unofficial and 3rd party to React.

Thread Thread
 
mikaelgramont profile image
Mikael Gramont

Agreed. That FB doesn't really offer a testing solution is the problem here: people set out to build their own test libraries while FB was free to break them.

Collapse
 
stretch0 profile image
Andrew McCallum

RTL is by no means an Enzyme drop-in replacement, so having a completely fresh mindset will help you getting the most of it.

You make a good point. RTL is more of an integration testing library where as Enzyme has the ability to unit test components. This move from unit to integration test focus is a pretty big change for some applications.

Collapse
 
marabesi profile image
Marabesi

Even though I see how the thinking behind integration x unit test is, I would recommend to watch Mario's talk on fragile tests (blog.devgenius.io/tdd-conference-2...).

The mindset of unit x integration around RTL is something that comes up often, and, it's possible to test a single component with RTL as well. The point is, this is not the philosophy of the library (testing-library.com/docs/guiding-p...).

In this sense, what I understand is: unit does not mean 1-1 (one test one component) rather, one behavior that you want to test.

Collapse
 
piotrstaniow profile image
Piotr Staniów • Edited

Thanks for the great work on the adapter! I think we've all seen it coming for last couple of years now, given how long it took to get support for React 16.x. In fact, it still doesn't work in various scenarios, nonetheless it's a painful process to move away from it so we all wanted to avoid it.

I like how Facebook tackles it, keeping the old Enzyme tests alive but writing the new ones only in React Testing Library, and gradually upgrading the codebase when touched.

I wrote an article a few months ago (Time to say goodbye - Enzyme.js) to suggest that it's time to call the library deprecated, as it would help to convey the point about making such migration across companies. Alas, the idea didn't resonate with the last maintainer of Enzyme.
Maybe eventually the React core team will make that call on their docs page, that they discourage using it, who knows...

Collapse
 
hillliu profile image
Hill Liu

If someone still needs a real life project to estimate how big to change from Enzyme to RTL, you could check the following pr. It's a React 16 project upgrade to React 18.

github.com/react-atomic/reshow/pul...

The biggest challenge for me is the act function, I write some utils to handle it.

I also have a custom render function that makes it more like Enzyme.

Such as render().html() or render().instance()
util link:
github.com/react-atomic/reshow/blo...

Collapse
 
andrewmat profile image
André Matulionis

FYI, publishing a unofficial package was a savior for me. I had to upgrade NextJS in a huge repo for vulnerability issues, which also upgraded React to v17

All tests for the last 3 years were done using rtl. But there is a considerable part of old tests that still are written using Enzyme. If it weren't for the adapter, the vulnerability issue would become a huge test-rewriting task.

Also, thanks for the warning. Will add the migration to rtl to our roadmap

Collapse
 
georgetaveras1231 profile image
George • Edited

A bit of shameless self-promotion, but also hoping to help some folks running into the challenge of migrating large repos away from enzyme.

If you are using jest and babel, you can consider using this babel plugin that allows you to incrementally adopt react 18 (without breaking existing tests that are using react 16 and enzyme):

npmjs.com/package/babel-plugin-jes...

Collapse
 
srshifu profile image
Ildar Sharafeev

Thank you for this article! Doing migration from Enzyme in my project, I figured out there is a way to make this process more manageable and automated: thesametech.com/migrate-away-from-...

Please check out my article, and let me know what you think! I plan to work on my plugin and improve it further, for now, it's a beta version.

Collapse
 
lexlohr profile image
Alex Lohr

I came here expecting a rant and was surprised by genuinely interesting content. I had already moved on to RTL in the meantime, but still wondered what had happened. Thanks for satiating my curiosity.

Collapse
 
hbroer profile image
Hauke B.

I currently working on a project which uses RTL, coming from another company working with enzyme (and Preact). This project has like no view unit tests. At my old company I tested most of the view and most of the tests are done with shallow() for the main reason that we wanted to only test one and no other component. Now just realise that RTL has no shallow() and therefor does not even provide unit testing and instead only integration testing. That's kind of sad.

But it also shows IMO that the current direction of development of React, and sadly Preact too in some cases, went into a bad direction. As a maintainer for long term projects it is anoying that with every release they just change something because they can. Nowadays all that hooks are a good example how FB pushes new webdevs into a direction which causes a lot of blown up render functions which are not even not tested often, but also like I learned now, definitivly not unit tested.

I think I will put some effort in research for a new Framework. The only thing I need from React/Preact is the diff/renderer. Everything else is not used because it does not provide good coding pattern. For React it is even anoying that it does not support native events and everything is touched by React before you get it in your "hands". It is like a new jQuery.

Sorry, just frustrated.

Collapse
 
andrew1234 profile image
Andrew

It's really unfortunate that Enzyme is dead, although I can see why things came to this. Depending on the React internals has always been a minefield, and I suppose we finally stepped on a big one.

To date, RTL continues to frustrate me and comes up short in the ways that are the most valuable to me as a developer. It wouldn't be so bad if there was still a decent way to unit test components, but it seems that the React community at large has eschewed clean, self-contained unit tests in favor of these sweeping integration tests, which cover more ground, but with less depth and more blind spots. I would prefer to have a combination of both approaches, but alas...

I don't think I could disagree with that Kent C. Dodds opinion piece on testing implementation details any more than I already do. I wish that the industry at large had taken it with a larger grain of salt - as one valid approach instead of the only correct approach.

I guess I'll be dragged kicking and screaming into the future :')

Collapse
 
nfrmn profile image
Freeman

RTL is simply worse than Enzyme.
I'll preface my next comment by saying I don't blame the Enzyme team at all, FOSS development is completely voluntary.
But it really feels like the only reason Enzyme is dying is because nobody wants to work on it, not because RTL is better. It just happens that Meta pays people to maintain RTL.

Collapse
 
trismi profile image
trismi

I'm doing an upgrade at work and we're looking at going to React 17 vs React 18. I have seen a number of resources that show you how to configure React 17 for your test folder and React 18 for the rest of your application. What kind of drawbacks are there to this? I'm assuming it doesn't properly test the new React 18 APIs, are there other things?

Collapse
 
nfrmn profile image
Freeman • Edited

This is a really tough one to stomach, since RN was launched we invested heavily into extremely detailed class and UI testing with Enzyme. Step by step it's become harder to test components with the introduction of Hooks / phase out of class components and now this.
I know our field is considered bleeding edge but it really is such a shame to now have to imagine our tests never existed and redo the whole philosophy and strategy because this lib is abandoned.
I have no choice but to do it (RN 69 is here and pretty much forces us off Enzyme with React 18), so I'll roll sleeves up with my team but it really really sucks and makes me worried about relying on the JS ecosystem so heavily for production applications in the future.

Collapse
 
tieje profile image
tieje

This is so crazy.

Collapse
 
kumarldh profile image
Kumar Chetan Sharma

you have designated time for repaying technical debt, right? …right?

(â—”_â—”) We have quite a few things on Enzyme. Gotta explain to product managers where the sprint bandwidth is going cause we don't have a designated time for repaying tech debts.

Everyone has broken up with Enzyme at work... RTL is the new "bae".

Collapse
 
larsejaas profile image
Lars Ejaas

I also really keep my eyes on the new Vitest library. It is in beta, and not ready for production yet. But it looks promising at least! vitest.dev