My 14 Days Long Story About Upgrading React | Karol Działowski

My 14 Days Long Story About Upgrading React

It took me almost 14 days to upgrade React. Now it is the time for a review.

One Year Delay

I started working on the React upgrade on February 14, 2023. Almost a year after creating an improvement task for it, when most teams were migrating. This delay was not a big deal. In fact, it was good considering I had more material on the subject.

The First Step

The process was a bit chaotic. I hadn't really planned the steps. My intuition was to bump the React version first. This caused some problems like React.FC not having implicit children props [1] or a lot of act(...) warnings in the tests. The first issue was easy to fix. Just explicitly define children in prop types. The biggest pain was the number of failed tests - 86 test suites and 605 failed test cases in total [2].

Bumping Other Packages

I mistakenly thought that bumping other package versions would fix something. So instead of looking closely at these failed tests, I've started upgrading more packages, introducing even more problems. The latest versions of react-redux, mui and router were introduced. Fortunately, there were no breaking changes at all, just some minor things like using useAppDispatch and useAppSelector instead of the default ones [5]. The biggest problems were caused by the userEvent package.

Pain with the userEvent Package

userEvent v14 introduced breaking changes [3]. Now the number of failed tests increased from 605 to 948. I've wasted time making code adjustments to properly support the new userEvent version. Every single use of userEvent now has to be awaited and test utility functions should be adapted to accept the user object [4]. After a day of fixing and no significant progress, I've decided to downgrade to the 13.5 release. I'll deal with the breaking changes later. It was already day 10 of my journey.

Failing Tests

After downgrading userEvent and fixing some minor problems, it was time to fix the failed tests. On the one hand, there were a lot of act(...) warnings. The temporary solution was to surprass them - we will deal with that later. To handle most of the act(...) warnings I used global.IS_REACT_ACT_ENVIRONMENT = false; [6]. On the other hand, I had more than 200 failed test cases. This means that 66% of the test cases are already fixed. Most of the failed tests were fixed as a byproduct of fixing other things like react-redux types.

One problem with our existing tests is that we did not wait for api calls to be completed. We just expected the API endpoint to be called and assumed the data would already be there. But in reality it is an asynchronous action, so we have to wait for the data to appear on the screen. One way to fix this is to use the findBy selector. Alternatively, if there is some kind of loading spinner, there is an option to wait for it to disappear [2].

Next Steps

There are other things to do. The first is to upgrade userEvent and fix its breaking changes. Another task on the list is to remove global.IS_REACT_ACT_ENVIRONMENT = false; from setupTests.ts and start fixing existing test cases. I estimate that a complete upgrade of this project would take about 3-4 weeks of work for a single developer.

Other Project

On the contrary, upgrading React on one of my side project was as simple as running just one command.

npm install react@latest react-dom@latest react-scripts@latest --legacy-peer-deps

There wer problems with other packages, but upgrading them solved the issue. You can see the commit in which I've upgraded React together with other packages (@testing-library/user-event too!) here.

Learnings

I learned a few things from this task. First of all, I realized that I was missing out on frequent package updates. That's what dependabot is for, and I should have used it. It would be much easier to upgrade one package at a time rather than trying to fix all the problems at once.

My testing strategies were not that bad, but now they are a little closer to following best practices. In fact, I'm grateful for the act(...) warnings [7].

Upgrading React should not be done in such an unplanned way. Learning and reading before doing would save me many hours. I think the best idea is to do a timeboxed spike to see what is failing and what stopped working and then spend some time reading changelogs and github issues. Having the knowledge from spike and literature review would certainly speed up the whole process of upgrading React.


[1]: What Happened to the FC Type's Implicit children Prop in @types/react v18?
[2]: Stack Overflow: Async thunks cause warnings in tests
[3]: user-event v14.0.0 release
[4]: Helper functions and user object
[5]: Redux: Usage With TypeScript
[6]: Disable missing act warnings in React 18
[7]: Why should you be grateful for act() warnings in React tests

© karlosos 2020 Open sourced on